在带头结点的单链表L中,删除所有值为x的结点,并释放其空间,假设值为x的结点不唯一,试编写算法以实现上述操作。
思路:两个指针一次遍历,用p从头到尾扫描单链表,pre指向*p结点的前驱(因为删除一个结点,首先得知道它的前驱结点的位置)。若p所指结点的值为x,则删除,并让p移向它的下一结点,否则让pre和p指针同时后移一个结点。
相关代码:
void del_x(Linklist *&L,ElemType x)
{
Linklist *p=L->next,*pre=L,*q;
//分别定义了结构体指针变量p,以及指向它的前驱的指针变量pre,还有用来临时存放要删除的结点的指针变量q
while(p!=NULL){
//p不为NULL则为真,用于遍历整个链表,这里也可以直接写"p"表示非0则为真,达到同样的效果。注意这里不能填p->next!=NULL,这样的话最后一个结点会遍历不到
if(p->data==x)
{
q=p; //q临时存放要删除的结点
p=p->next;
pre->next=p;
free(q); //这三行为标准的删除语句
}
else{
pre=p;
p=p->next; //pre与p指针同时向后移一位
}
}
}
试编写在带头结点的单链表L中删除一个最小值结点的高效算法(假设最小值结点是唯一的)
总的原理和上面删除与x值相同的结点差不多,定义一个指针p,和它的前驱指针pre,p还是遍历整个链表,另外还有用来存放它们最小值结点的两个指针,分别为minpre和minp。
相关算法:
Linklist del_Min(Linklist *&L,ElemType x)
{
Linklist *p=L->next,*pre=L,*q;
//分别定义了结构体指针变量p,以及指向它的前驱的指针变量pre。这两个指针用于比较、遍历
Linklist *minpre=pre,*minp=p;
//分别用来存放pre的值,与最小值minp,这两个智者用于存放最小值的结点以及最小值结点的前驱结点
while(p!=NULL){
//p不为NULL则为真,用于遍历整个链表,这里也可以直接写"p"表示非0则为真,达到同样的效果。注意这里不能填p->next!=NULL,这样的话最后一个结点会遍历不到
if(p->data<minp->data)
{
minp=p; //让minp指向最小值的结点
minpre=pre; //minpre始终指向最小值结点的前一个结点。
}
pre=p;
p=p->next; //pre与p指针同时向后移一位
}
minpre->next=minp->next;
free(minp);
return L;
}
试编写算法将带头结点的单链表就地逆置 ,所谓就地逆置是指辅助空间复杂度为O(1)
第一种方法为直接把链表的指针反过来指向,将第一个结点的next域置空,然后再将头指针指向原本链表的最后一个结点。
相关代码:
#include <stdio.h>
Linklist Reverse_1(Linklist *&L)
{
Linklist *pre,*p=L->next,*r=p->next;
p->next=NULL; //处理组开始的结点,将它的next域置空,变成逆置链表的尾结点。
while(p!=NULL) //p依旧为遍历单链表
{
pre=p; //依次遍历
p=r;
r=r->next;
p->next=pre; //指针反置,后一个指向前一个结点
}
L->next=p; //将头结点指向原本链表最后一个结点
return L;
}
第二种方法则是使用头插法,首先将第一个结点的next域置为空,然后后面的结点依次连接到头结点后面(注意,后面的每个结点都是连接到头结点),并且后面连接好之前插好的结点。
#include <stdio.h>
Linklist Reverse_2(Linklist *&L)
{
Linklist *pre,*p=L->next;
L->next=NULL; //第一次循环会将第一个结点变成尾结点,会将L->next赋值给尾结点的指针域,即赋值为空
while(p!=NULL) //p依旧为遍历单链表
{
pre=p; //将p所指向的结点让pre也指向
p=p->next;
pre->next=L->next; //下面这两步是常规的插入操作,先连后断,现将pre的next域指向L的next域所指向的结点
L->next=pre; //将L的next域指向pre,两者不可调换位置,否则会断链。
}
return L;
}