您的位置:首页 > 理论基础 > 数据结构算法

线性表链表表相关习题及详解(综合) ——数据结构

2017-10-19 15:38 375 查看

习题部分

[b]第一题[/b]

设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点

[b]第二题[/b]

在带头结点的单链表L中,删除所有值为x的结点,并释放空间,假设值为x的结点不唯一,试编写算法以实现上述操作。

[b]第三题[/b]

设L为带头结点的单链表,编写算法实现从尾到头反向输出每个结点的值

[b]第四题[/b]

试编写在带头结点的单链表L中删除一个最小值结点的高效算法(假设最小值结点时唯一的)

[b]第五题[/b]

试编写算法将带头结点的单链表就地逆置,所谓“就地”是指辅助空间复杂度为O(1)。

[b]第六题[/b]

有一个带头结点的单链表L,设计一个算法使其元素递增有序。

[b]第七题[/b]

设在一个带表投机诶单的单链表中所有元素结点的数据值无序,试编写一个函数,删除表中所有介于给定的两个值(作为函数参数给出)之间的元素的元素(若存在)

[b]第八题[/b]

给定两个单链表,编写算法找出两个链表的公共结点。

[b]第九题[/b]

给定一个带表头结点的单链表,设head为头指针,结点的结构为(data,next),data为整形元素,next为指针,试写出算法:按递增次序输出单链表中各结点的数据元素,并释放结点所占的存储空间(要走:不允许使用数组作为辅助空间)

[b]第十题[/b]

给定一个带表头结点的单链表A分解为两个带头结点的单链表A和B,使得A表中含有原表中序号为奇数的元素,而B表中含有原表中序号为偶数的元素,且保持其相对顺序不变

[b]第十一题[/b]

设C={a1,b1,a2,b2…,an,bn}位线性表,采用带头结点的hc单链表存放,设计一个就地算法,将其拆分为两个线性表,使得

A={a1,a2,…,an} B={bn,…,b2,b1}

[b]第十二题[/b]

在一个递增有序的线性表中,有数值想通的元素存在。若存储方式为单链表,设计算法去掉数值相同的元素,使表中不再有重复的元素。例如(7,10,10,21,30,42,42,42,51,70)将变作(7,10,21,30,42,51,70)

[b]第十三题[/b]

假设有两个按元素值递增次序排列的线性表,均以单链表形式存储。请编写算法将这两个单链表归并为一个按元素值递减次序排列的单链表,并要求利用原来两个单链表的结点存放归并后的单链表

[b]第十四题[/b]

设A和B是两个单链表(带头结点),其中元素递增有序,设计一个算法从A和B中公共元素产生单链表C,要求不破坏A B 的结点

[b]第十五题[/b]

一直两个链表A和B分别表示两个集合,其元素递增排列。绘制函数,求A与B的交集,并存放于A链表中。

[b]第十六题[/b]

两个整数序列A=a1,a2,a3,…,am和B=b1,b2,b3,…,bn已经存入两个单链表中,设计一个算法,判断序列B是否是序列A的连续子序列

[b]第十七题[/b]

设计一个算法用于判断带头结点的循环双链表是否对称

[b]第十八题[/b]

有两个循环单链表,链表头指针分别为h1和h2,编写一个函数将链表h2链接到链表h1之后,要求链接后的链表仍保持循环链表形式。

[b]第十九题[/b]

设有一个带头结点的循环单链表,其结点值均为正整数。设计一个算法,反复找出单链表中结点值最小的结点并输出,然后将该结点从中删除,直到单链表为空位置,再删除表头结点

[b]第二十题[/b]

设头指针为L的带有表头节点的非循环双向链表,其每个结点中除了有pred(前去指针),data(数据)和next(后继指针)外,还有一个访问频度域freq。在链表被启用前,气质均初始化为零。每当在链表中进行一次Locate(L,x)运算时,令元素值为x的结点中freq域的值增加1,并使此链表中结点保持按访问频度非增(递减)的顺序排列,同事最近访问的结点排在频度相同的结点的前面,以便使频繁访问的结点总是靠近表头。试编写符合上述要求的Locate(L,x)运算的算法,该运算为函数过程,返回找到结点的地址,类型为指针型

解答部分

第一题

设f(L,x)的功能是删除以L为首结点指针的单链表中所有值等于x的结点,则显然有f(L->next,x)的功能是删除以L->next为首结点指针的单链表中所有值等于x的结点,由此,可以退出递归模型如下:

终止条件:f(L,x) 不作任何事情; 若L为空表

递归主体:f(L,x) 删除*L结点;f(L->next,x); 若L->data==x

f(L,x) f(L->next,x); 其他情况

本题代码如下:

void Del_X_3(Linklist &L,ElemType x){
LNode *p;               //p指向待删除结点
if (L==NULL)            //递归出口
{
return;
}
if(L->data == x){       //若L所指结点的值为x
p=L;                //删除*L,并让L指向下一结点
L=L->next;
free(p);
Del_X_3(L,x);       //递归调用

}
else                    //若L所指结点的值不为x
Del_X_3(L->next,x); //递归调用
}


算法需要借助一个递归工作栈,深度为O(n),时间复杂度为O(n)。有人认为直接free屌结点会造成断链,实际上因为L为引用,是直接对原链表进行操作,因此不会断链。

第二题

解法一

用p从头到尾扫描单链表,pre指向*p结点的前驱。若p所指结点的值为x,则删除,并让p移向下一个结点,否则让pre、p指向同步后移一个结点。

void Del_X_1(Linklist &L,ElemType x){
//L为带头结点的但俩你报,本算法删除L中所有值为x的结点
LNode *p=L->next,*pre=L,*q;//置p和pre的初始值
while(p!=NULL){
if(p->data==x){
q=p;                //q指向该结点
p=p->next;
pre->next=p;        //删除*q结点
free(q);            //释放*q结点的空间
}
else{                   //柔则,pre和p同步后移
pre=p;
p=p->next;
}//else
}//while
}


本算法是在无须单链表中删除满足某种太哦啊见的所有结点,这里的条件是结点的值为x。实际上,这个条件是可以任意指定的,只要修改if条件即可,比如,我们要求删除值介于mink和maxk之间的所有结点,则只需将if语句修改为ifp->datamink && p->data

void Del_X_2(Linklist &L,ElemType x){
//L为带头结点的但俩你报,本算法删除L中所有值为x的结点
LNode *p=L->next,*r=L,*q;       //r指向尾结点,其初值为头结点
while(p!=NULL){
if(p->data!=x){             //*p结点值不为x时将其链接到L尾部
r->next=p;
r=p;
p=p->next;              //继续扫描
}
else{                       //*p结点值为x时将其释放
q=p;
p=p->next;              //继续扫描
free(q);                //释放空间
}
}//while
r->next=NULL;                   //插入结束后置尾结点指针为NULL
}


第三题

考虑到从头到尾输出比较简单,本题的思路很自然的联系到借助上题链表逆置的方法来实现,改变链表的方向,然后就可以从头到尾实现反向输出了

此外,本题还可以借助一个栈来实现,每经过一个结点时,将该结点访入栈中。在遍历完整个链表后,再从栈顶开始输出结点值即可。

既然能用栈的思想解决,也就很自然地联想到了用递归来实现,每当访问一个结点时,先递归输出它后面的结点,再输出该结点自身,这样链表就反向输出了。

本体代码如下:

void R_Print(LinkList L){
//从尾到头输出单链表L中每个结点的值
if(L->next!=NULL){
R_Print(L->next);   //递归
}//if
printf(L->data);        //输出函数

}


第四题

算法思想:用p从头至尾扫描单链表,pre指向*p结点的前驱,用minp保存值最小的结点指针(初值为p),minpre指向*minp结点的前驱(初值为pre)。一边扫描,一边比较,若p->data小于minp->dara,则将p、pre分别复制给minp、minpre。

当p扫描完毕,minp指向最小值结点,minpre指向最小值结点的前驱结点,再将minp所指结点删除即可。

LinkList Delete_Min(LinkList &L){
//L是带头结点的单链表,本算法删除其最小值结点
LNode *pre=L,*p=pre->next;      //p为工作指针,pre指向其前驱
LNode *minpre=pre,*minp =p;     //保存最小值结点及其前驱
while(p!=NULL){
if(p->data < minp->data){
minp=p;                 //找到比之前找到的最小值结点更小的结点
minpre=pre;
}
pre=p;                      //继续扫描下一个结点
p=p->next;
}
minpre->next=minp->next;        //删除最小值结点
free(minp);
return L;
}


算法需要从头至尾扫描链表,时间复杂度为O(n),空间复杂度为O(1)。

如果本题改为不带头结点的单链表,则实现上会有所不同

第五题

解法一

将头结点摘下,然后从第一结点开始,一次前插入到头结点的后面(头插法建立单链表),直到最后一个结点为止,则实现了链表的逆置,

LinkList Reverse_1(LinkList L){
//L是带头结点的单链表,本算法将L就地逆置
LNode *p ,*r;               //p为工作指针,r为p的后继,以防断链
p-L->next;                  //从第一个元素结点开始
L->next=NULL;               //先将头结点L的next域置为NULL
while(p!=NULL){             //依次将元素结点摘下
r=p->next;              //暂存p的后继
p->next=L->next;        //将p结点插入到头结点之后
L->next=p;              //
p=r;                    //
}
return L;
}


解法二

大部分数据结构只介绍第一种方法。下面假设pre、p和r指向3个相邻的结点,如下图所示。假设经过若干操作,*pre之前的结点的指针都已调整完毕,它们的next都指向其原前驱结点。现在令 *p结点的next域指向*pre结点,注意到一旦调整指针的指向后,*p的后继结点的链就断开了,为此需要用r来指向原*p的后继结点。处理时需要注意两点:一是在处理第一个结点时,应将其next域置为NULL,而不是指向头结点(因为它将作为新表的尾结点);二十在处理完最后一个结点后,需要将头结点的指针指向它。

本题代码

LinkList Reverse_2(LinkList L){
//依次遍历线性表L,并将结点指针翻转
LNode *pre,*p=L->next,*r=p->next;
p->next =NULL;          //处理第一个结点
while(r!=NULL){         //r为空,则说明p为最后一个结点
pre=p;              //依次继续遍历
p=r;
r=r->next;
p->next=pre;        //指针反转
}
L->next=p;              //处理最后一个结点
return L;
}


上述两个算法的时间复杂度为O(n),空间复杂度为O(1)

第六题

算法思想:采用直接插入排序算法的思想,先构成只含一个数据结点的有序单链表,然后依次扫描单链表中剩下的结点*p(直至p==NULL为止),在有序表中通过比较查找插入*p的前驱结点*pre,然后*p插入到*pre之后,找到合适的位置插入

本题代码如下:

void Sort(LinkList &L){
//本算法实现将单链表L的结点重拍,使其递增有序
LNode *p=L->next,*pre;
LNode *r=p->next;                   //r保持*p后继结点指针,以保证不锻炼
p->next=NULL;                       //构造只含一个数据结点的有序表
p=r;
while(p!=NULL){
r=p->next;                      //保存*p的后继结点指针
pre=L;
while(pre->next!=NULL&&pre->next->data < p->data){
pre=pre->next;              //在有序表中查找插入*p的前驱结点*pre
}
p->next=pre->next;              //将*p插入到*pre后
pre->next=p;
p=r;                            //扫描原单链表中剩下的结点
}
}


细心的话话显然该算法的时间复杂度为O(n^2)

第七题

因为链表是无序的,所以只能逐个节点进行检查,执行删除。

void RangeDelete(LinkList &L,int min,int max){
LNode *pr=L,*p=L->link;                 //p是检测指针,pr是其前驱
while(p!=NULL){
if(p->data > min&&p->data < max){   //寻找到被删结点,删除
pr->link = p->link;
free(p);
p=pr->link;
}
else{                               //否则继续寻找被删结点
pr=p;
p=p->link;
}
}
}


第八题

两个单链表有公共结点,也就是说两个链表从某一结点开始,它们的next都指向同一个结点。由于每个单链表结点只有一个next域,因此从第一个公共结点开始,之后它们所有的结点都是重合的,不可能再出现分叉。所以,两个有公共结点而部分重合的单链表,拓扑形状看起来像Y而不可能像X。

本题极容易联想到“蛮力”的方法:在第一个链表上顺序遍历每个节点,每遍历一个结点,在第二个链表上顺序遍历所有结点,如果找到两个相同的结点,于是就找到了它们的公共结点。显然该算法的时间复杂度为O(len1*len2)。

接下来我们试着去寻找一个线性时间复杂度的算法。先把问题简化:如何判断两个单向链表有没有公共结点?应注意到这样一个事实:如果两个链表有一个公共结点,那么该公共结点之后的所有结点都是重合的,即它们的最后一个结点必然是重合的。因此,我们判断两个链表是不是有重合的部分,只要分别遍历两个链表到最后一个结点。如果两个尾结点是一样的,说明它们有公共结点,否则两个链表没有公共的结点。

然而,在上面的思路中,顺序遍历两个链到尾结点的时候,并不能保证两个链表上同事到达尾结点。这是因为两个链表长度不一定一样。但假设一个链表比另一个长k个结点,我们先在长的链表上遍历k个结点,之后再同步遍历,此时我们就能保证同时到达最后一个结点了。由于两个链表从第一个公共结点开始到链表的尾结点,这一部分是重合的。因此它们肯定也是同时到达第一公共结点的。于是在遍历中,第一个相同的结点就是第一个公共的结点。

在这个思路中,我们先要分别遍历两个链表得到它们的长度,并求出两个长度之差。在长的链表上先遍历长度之差个结点之后,再同步遍历两个链表,直到找到相同的结点,或者一直到链表结束。此时该方法的时间复杂度为O(len1+len2)。

本题代码如下

LinkList Search_1st_Common(LinkList L1, LinkList L2){
//本算法实现在线性的时间内找到两个单链表的第一个公共结点
int len1 = Length(L1),len2=Length(L2);              //计算两个链表的表长
LinkList longList ,shortList;                       //分别指向表长较长和较短的链表
if(len1>len2){                                      //L1表长较长
longList = L1->next;shortList=L2->next;
dist = len1-len2;                               //表长之差
}
else{                                               //L2表长较长
longList = L2->next;shortList=L1->next;
dist = len2-len1;                               //表长之差
}
while(dist--)                                       //表长的链表先遍历到第dist个结点,然后同步
longList =longList->next;
while(longList!=NULL){                              //同步寻找共同结点
if(longList==shortList)                         //找到第一个公共结点
return longList;
else{                                           //继续同步寻找
longList=longList->next;
shortList=shortList->next;
}
}//while
return NULL;

}


第九题

算法思想:对链表进行遍历,在每趟遍历中查找出整个链表的最小值元素,输出并释放结点所占空间;再查找次小值元素,输出并释放空间,如此下去,直至链表为空,最后释放头结点所占存储空间,该算法的时间复杂度为O(n^2)。



若题设不限制数组辅助空间的使用,则可先将链表的数据复制在数组里,再采用时间复杂度为O(nlog2n)的排序算法进行派速,然后将数组元素输出,时间复杂度为O(nlog2n)

第十题

算法思想:设置一个访问序号变量(初值为0),每访问一个结点序号自动加1,然后根据序号的奇偶性将结点插入到A表或B表中。重复以上操作直到表尾

void Min_Delete(LinkList &head){
//head是带头结点的单链表的头指针,本算法按递增顺序输出单链表中的数据元素
while(head->next!NULL){                     //循环到仅剩头结点
pre=head;                               //pre为元素最小值结点的寝取结点和指针
p=pre->next;                            //p为工作指针
while(p->next!=NULL){
if(p->next->data < pre->next->data)
pre=p;                          //记住当前最小值结点的前驱
p=p->next;
}
print(pre->next->data);                 //输出元素最小值结点的数据
u=pre->next;                            //删除元素值最小的结点,释放结点空间
pre->next=u->next;
free(u);

}//while
free(head);                                 //释放头结点
}


为了保持原来结点中的顺序,本题采用尾插法建立单链表。此外,本算法完全可以不用设置序号变量。while循环中的代码改为将结点插入到表A中和将下一结点插入到表B中,这样while中第一处理的结点就是奇数号结点,第二处理的结点就是偶数号结点。



第十一题

算法思想:采用上面的思路,不设序号变量。二者的差别仅在于对B表的建立不采用尾插法,而是采用头插法。

LinkList DisCreat(LinkList &A){
LinkList B= (LinkList)malloc(sizeof(LNode));    //创建B表表头
B->next=NULL;                                   //B表的初始化
LNode *p=A->next,*q;                            //p为工作指针
LNode *ra=A;                                    //ra始终指向A的尾结点
while(p!=NULL){
ra->next=p;ra=p;                            //将*p链到A的表尾
p=p->next;
q=p->next;                                  //头插后,*p将断链,因此用q记忆*p的后继
p->next=B->next;                            //将*p插入到B的前端
B->next=p;
p=q;
}
ra->next=NULL;                                  //A尾结点的next域置空
return B;
}


该算法特别需要注意的是,采用头插法插入结点后,*p的指针域已经改变,如果不设变量保存其后继结点会引起断链,从而导致算法出错。

第十二题

算法思想:由于是有序表,所有相同值域的结点都是相邻的。用p扫描递增单链表L,若*p结点的值域等于其后继结点的值域,则删除后者,否则p移向下一个结点

void Del_Same(LinkList &L){
//L是递增有序的单链表,本算法删除表中数值相同的元素
LNode *p=L->next,*q;            //p为扫描工作指针
if(p==NULL)
return;
while(p->next!=NULL){
q=p->next;                  //q指向*p的后几及诶单
if(p->data==q->data){       //找到重复值的结点
p->next=q->next;        //释放*q结点
free(q);                //释放相同元素值的结点
}
else
p=p->next;
}
}


本题算法的时间复杂度为O(n),空间复杂度为O(1)。

本题也可以采用尾插法,将头结点摘下,然后从第一结点开始,一次与已经插入结点的链表的最后一个结点比较,若不等则直接插入,否则将当前遍历的结点删除并处理下一个结点,直到最后一个结点为止。

第十三题

算法思想:两个链表已经按元素值递增次序排序,将其合并时,均从第一个结点起进行比较,将笑的结点链入链表,同时后移工作指针。该问题要求结果俩你报按元素值递减次序,故新链表的建立应该采用头插法。比较结束后,可能会有一个链表非空,此时用头插法将剩下的结点一次插入新链表中即可。。。

void MergeList(LinkList &La,LinkList &Lb){
//合并两个递增有序链表(带头结点),并使合并后的链表递增排列
LNode *r,*pa=La->next,*pb=Lb->next; //分别是表La和Lb的工作指针
La->next=NULL;                      //La作为结果链表的头指针,先将结果链表初始化为空

while(pa&&pb){                      //当两链表均不为空时,循环
if(pa->data<=pb->data){
r=pa->next;                 //r暂存pa的后继结点指针
pa->next=La->next;
La->next=pa;                //将pa结点链于结果表中,同事逆置(头插法)

pa=r;                       //恢复pa为当前待比较结点
}
else{
r=pb->next;                 //r暂存pb的后继结点指针
pb->next=La->next;
La->next=pb;                //将pb结点链于结果表中,同事逆置(头插法)

pb=r;                       //恢复pb为当前待比较结点
}
}
if(pa)                              //通常情况下回剩一个链表非空,处理剩下的部分
pb=pa;
while(pb){                          //处理剩下的一个非空链表
r=pb->next;                     //一次插入到La中(头插法)
pb->next=La->next;
La->next=pb;
pb=r;
}
free(Lb);
}


第十四题

算法思想:表A ,B都有序,可从第一个元素起一次比较A、B量表的元素,若元素值不等,则值小的指针往后移,若元素值相等,则创建一个值等于两结点的元素值的新的结点,使用尾插法插入到新的链表中,并两个原表指针后移一位,直到其中一个链表遍历到表尾。

void Get_Common(LinkList A, LinkList B){
//本算法产生单链表A和B的公共元素的单链表的C
LNode *p=A->next,*q-B->next,*r,*s;
LinkList C=(LinkList)malloc(sizeof(LNode)); //建立表C
r=C;                                        //r始终指向C的尾结点
while(p!=NULL&&q!=NULL){                    //循环挑出条件
if(p->data<q->data)
p=p->next;                          //若A的当前元素较小,后移指针
else if(p->data>q->data)
q=q->next;                          //若B的当前元素较小,后移指针
else{                                   //找到公共元素结点
s=(LNode*)malloc(sizeof(LNode));
s->data=p->data;                    //复制产生结点*s
r->next=s;                          //将*s链接到C上(尾插法)
r=s;
p=p->next;                          //表A和表B继续向后扫描
q=q->next;
}
}
r->next=NULL;                               //置C尾结点指针为空
}


第十五题

算法思想:采用归并的思想,设置两个工作指针pa和pb,对两个链表进行归并扫描,只有同时出现在两集合中的元素才链接到结果表中且仅保留一个,其他的结点全部释放。当一个链表遍历完毕后,释放另一个表中剩下的全部结点。。

LinkList Union(LinkList &la,LinkList &lb){
pa=la->next;                        //设工作指针分别为pa和pb
pb=lb->next;
pc=la;                              //结果表中当前合并结点的前去指针
while(pa&&pa){
if(pa->data==pb->data){         //交集并入结果表中
pc->next=pa;                //A中结点链接到结果表
pc=pa;
pa=pa->next;
u=pb;                       //B中结点释放
pb=pb->next;
free(u);
}
else if(pa->data<pb->data){     //若A中当前结点值小于B中当前结点值
u=pa;
pa=pa->next;                //后移指针
free(u);                    //释放A中当前结点
}
else{                           //若B中当前结点值小于A中当前结点值
u=pb;
pb=pb->next;                //后移指针
free(u);                    //释放B中当前结点
}
}//while结束
while(pa){                          //B已经遍历完,A没完
u=pa;
pa=pa->next;
free(u);                        //释放A中剩余节点
}
while(pb){                          //A已经遍历完,B未完
u=pb;
pb=pb->next;
free(u);                        //释放B中剩余结点
}
pc->next=NULL;                      //置结果链表尾指针为NULL
free(lb);                           //释放B表的头结点
return la;
}


该算法的时间复杂度为O(len1+len2),空间复杂度为O(1)

第十六题

算法思想:因为两个整数序列已存放如两个链表中,操作从两个链表的第一个结点开始,若对应数据相等,则后移指指针;若对应数据不等,则A俩你报从上次开始比较结点的后继开始,链表扔从第一个结点开始比较,直到B链表到尾表示匹配成功。A链表到尾而B连不了未到尾表示失败。操作中应记住A链表每次的开始结点,以便下趟匹配时刚好从其后继开始。

int Pattern(LinkList A,LinkList B){
//A和B分别是数据域为整数的单链表,本算法判断B是否是A的子序列
LNode *p=A;                 //p为A链表的工作指针,本题假设A和B均无头结点
LNode *pre=p;               //pre记住每趟比较中A链表的开始结点
LNode *q=B;                 //q是B链表的工作指针
while(p&&q){
if(p->data==q->data){   //结点值相同
p=p->next;
q=q->next;
}
else{
pre=pre->next;
p=pre;              //A链表新的开始比较结点
q=B;                //q从B链表第一个结点开始
}

}
if(q==NULL)                 //B已经比较结束
return 1;               //说明B是A的子序列
else
return 0;               //B不是A的子序列
}


此题其实是字符串模式匹配的链式表示形式。

第十七题

算法思想:让p从左向右扫描,q从右向左扫描,直到它们指向同一结点(p==q,当循环双链表中节点个数为奇数时)活相邻(p->next=q或p->prior=p,当循环双链表中结合个数为偶数时)未知,若它们所指结点值相同,则继续进行下去,否则返回0。若比较全部党性,则返回1。

int Symmetry(DLinkList L){
//本算法从两头扫描循环双链表,以判断链表是否对称
DNode *p = L->next,*q=L->prior;     //两头工作指针
while(p!=q&&q->next!=p){            //循环挑出条件
if(p->data==q->data){           //所指结点值相同则继续比较
p=p->next;
q=q->prior;
}
else                            //否则,返回0
return 0;
}
return 1;                           //比较结束后返回1
}


第十八题

算法思想:先找到两个链表的尾指针,将第一个链表的尾指针与第二个链表的头结点链接起来,在使之成为循环的。

···

LinkList Link(LinkList &h1,LinkList &h2){

//将循环链表h2链接到循环链表h1之后,使之仍保持循环链比老的形式

LNode *p,*q; //分别直线搞两个链表的尾结点

p=h1;

while(p->next!=h1) //寻找h1的尾结点

p=p->next;

q=h2;

while(q->next!=h2) //寻找h2的尾结点

q=q->next;

p->next =h2; //将h2链接到h1之后

q->next=h1; //令h2的尾结点指向h1

return h1;

}

···

第十九题

对于循环但俩你报L,在不空时循环:每循环一次查找一个最小结点(由minp指向最小值结点,minpre指向其前驱结点)并删除它,最后释放头结点

void Del_All(LinkList &L){
//本算法实现每次删除循环单链表中的最小元素,知道链表为空为止
LNode *p, *pre,*minp, *minpre;
while(L->next!=L){                      //表不空,循环
p=L-next;pre=L;                     //p为工作指针,pre指向其前驱
minp=p;minpre=pre;                  //minp指向最小值结点
while(p!=L){                        //循环一趟,查找最小值结点
if(p->ndata < minp->data){
minp =p;                    //找到值更小的结点
minpre=pre;
}
pre=p;                          //查找下一个结点
p=p-next;
}
printf("%d",minp->data)             //输出最小值结点元素
minpre->next=minp->next;            //最小值结点从表中“断”开
free(minp);                         //释放空间
}
free(L);                                //释放头结点
}


第二十题

此题主要考察双链表的查找、删除和插入算法。

算法思想:首先在双向链表中查找数据值为x的结点,查到后,将结点从链表上摘下,然后再顺着结点的前驱链查找该结点的插入位置。(频度递减,且排在同频度的第一个,即向前找到第一个比它频度大的结点,插入位置为该结点之后),并插入到该位置。

DLinkList Locate(DLinkList &L, ElemType x){
//本算法先查找数据x,查找成功时结点的访问频度域增加1
//最后将该结点按频度递减插入链表中适当位置(同频度最近访问的在前边)
DNode *p=L->next, *q;               //p为工作指针,q为p的前驱,用于查找插入位置
while(p&&p->data!=x)
p=p->next;                      //查找值为x的结点
if(!p){
printf("不存在值为x的结点\n" );
exit(0);
}
else{                               //令元素值为x的结点的freq域加1
p->freq++;
p->next->pred=p->pred;          //将p结点从链表上摘下
p->pred->next=p->next;          //以下查找p结点的插入位置
q=p->pred;
while(q!=L&&q->freq<=p->freq)
q=q->pred;
p->next=q->next;
q->next->pred=p;                //将p结点插入,一定是排在同频率的第一个
p->pred=q;
q->next=p;
}
return p;                           //返回值为x的结点的指针
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐