线性表的应用(一)
(1)设计一个算法,将顺序表逆置。
(2)已知长度为 n 的线性表 A 采用顺序存储结构,请写一时间复杂度为 O(n)、空间复杂度为 O(1)的算法,该算法删除线性表中所有值为 item 的数据元素。
(3)将两个递增的有序链表合并为一个递增的有序链表。要求结果链表仍使用原来两个链表的存储空间, 不另外占用其它的存储空间。表中不允许有重复的数据。
(4)已知两个链表 A 和 B 分别表示两个集合,其元素递增排列。请设计算法求出 A 与 B的交集,并存放于 A 链表中。
(5)设计一个算法,通过遍历一趟,将链表中所有结点的链接方向逆转,仍利用原表的存储空间。
(6)设计一个算法,删除递增有序链表中值大于 mink 且小于 maxk 的所有元素(mink和 maxk 是给定的两个参数,其值可以和表中的元素相同,也可以不同 )。
(7)已知 p 指向双向循环链表中的一个结点,其结点结构为 data、prior、next 三个域,写出算法 change§,交换 p 所指向的结点和它的前驱结点的顺序。
(1)顺序表逆置。
算法思想:将第一个元素与最后一个元素交换,第二个与倒数第二个,以此类推。
void Reverse(SqList &L)
{
ElemType temp;
for(i = 0;i < L.length/2;i++)//循环条件为长度的一半,才能实现逆置
{
temp = L.elem[i];
L.elem[i] = L.elem[L.length - 1 - i];
L.elem[L.length - 1 - i] = temp;
}
}
(2)删除顺序表中所有值为 item 的数据元素。
算法思想:直接对原顺序表进行赋值,遇到第一个item,就前移一位,遇到第二个就前移两位,以此类推。
void DeleteItem(SqList L, ElemType item)
{
n = L.length;
/* 此步不能省,长度变化了,
循环判断条件不能直接用j < L.length */
for(i = 0,j = 0;j < n;i++,j++)
{
if(L.elem[j]!=item)
{
L.elem[i]=L.elem[j];//L.elem[i]为“新”顺序表元素,L.elem[j]为原来顺序表元素
}
else
{
j++;//遇到item,原顺序表元素直接跳到下一个元素,不进行赋值
L.length--;//长度-1
}
}
}
该算法时间复杂度为 O(n)、空间复杂度为 O(1)。
(3)两个有序递增链表的合并。
算法思想:两个有序递增链表分别为A、B,合并为C。链表C使用A(A、B都行)的头节点。
- 先将A、B中的第一个元素进行比较。
- 假如A小,将C指向A,然后A后移,C后移。
- 假如B小,将C指向B,然后B后移,C后移。
- 两者相等,将C指向A,然后A后移,C后移,B后移。(B后移完成题目要求不能重复元素)
- 当一个表到达表尾结点(为空),将非空表的剩余元素直接链接在 C的最后。
最后不要忘记释放B中相同元素的节点!!!
void MergeList(LinkList &A,LinkList &B,LinkList &C)
{
/*链表的第一步操作一般都是记下第一个元素,
方便后续操作,因为不能把头指针改变了*/
pa = A->next;pb = B->next;
C = pc = A; //用 A 的 头结点作为 C 的头结点
while(pa && pb)
{
if(pa->data < pb->data)//A小
{
pc->next = pa;// 将C指向A
pc = pa;// C后移
pa = pa->next;// A后移
}
else if(pa->data > pb->data) //B小
{
pc->next = pb; // 将C指向B
pc = pb; // C后移
pb = pb->next;// B后移
}
else //相等时,取A中的元素,删除B中的元素
{
pc->next = pa;//将C指向A
pc = pa;// C后移
pa = pa->next;// A后移
q = pb->next;//记下B的后继,用于释放
free(pb) ; //释放
pb = q; // B后移
}
}
pc->next = pa?pa:pb; //将非空表的剩余元素直接链接在C的最后。
free(B); //释放B的头结点
}
如果允许有重复元素 :两者相等时,将C指向A,然后A后移,C后移,B后移。 ,然后继续执行循环。
(4)两个有序递增链表的交集。
算法思想: 两个有序递增链表分别为A、B,交集为C。链表C使用A的空间。交集即取A中A、B相同元素,不相同元素节点释放。
- 比较A、B元素,两者元素相同,将C指向A,然后A后移,C后移,B后移;
- 不相同,C不做任何操作
- 当某个表为空时,停止循环。
最后不要忘记释放未空表中剩余元素的节点!!!
void InterSection(LinkList &A, LinkList B)
{
pc = A; pa = A->next;
pb = B->next;
while(pa&&pb)
{
if(pa->data == pb->data)//两者元素相同
{
pc->next = pa;// 将C指向A
pc = pa;// C后移
pa = pa->next;// A后移
pb = pb->next; // B后移
}
else if(pa->data < pb->data) //删除不在交集中的A中的元素
{
q = pa;pa = pa->next;//删除时,一定要找到删除元素的后继
free(q);
}
else
{
pb = pb->next;
}
}
while(pa) //释放未空表中剩余元素的节点
{
q = pa; pa = pa->next; free(q);
}
pc->next=NULL; //表尾为空
}
如果求两个有序递增链表的 差集 。
算法思想: 两个有序递增链表分别为A、B,交集为C。链表C使用A的空间。仅由在 A 中出现而不在 B 中出现的元素构成集合C,即取A中A、B不相同元素,相同元素节点释放。
(5)链表逆置 。
算法思想:即链表前插法。
- 将链表 L 的头结点与链表的第一个元素结点断开;让 p 指向第一个元素结点,L 变成一个只有一个头结点的空链表。
- 将 p 所指的链表中的各结点依次插在 L 的链头。
void Inverse(LinkList &L)
{
p = L->next; //p为头节点
L->next = NULL; //将头结点与第一个结点断开
while(p)
{
q = p->next; // q指向第一个元素
p->next = L->next; //将 p 插入在头结点之 后
L->next = p;
p = q;
}
}
(6)删除递增有序链表中值大于 mink 且小于 maxk 的所有元素。
算法思想:找第一个值大于 mink 的结点,然后删除在(mink,maxk)之间的所有结点。
void delete_L( LinkList &L,int mink,int maxk)
{
if(L->next && mink < maxk)
{
p = L;
q = L->next;
while(q && q->data <= mink) //找第一个值大于 mink 的结点;
{
p = q;
q = q->next;
}//跳出循环时,p为删除节点片段的前驱
while (q && q->data < maxk) //删除在(mink,maxk)之间的所有结点
{
s = q;
q = q->next ;
free(s);
}
p->next = q; // q未删除节点片段的后继
}
}
(7)交换双向链表的两个节点。
void Exchange(DuLinkList p)
{ //p 是双向循环链表中的一个结点的指针,将p所指结点与其前驱结点交换。
q=p->prior;
q->prior->next=p; //q的前驱的后继变成p
p->prior=q->prior; //p的前驱变成q的前驱,相当于将q从链表中删除
q->prior=p;
q->next=p->next;
p->next->prior=q;
p->next=q;
}