目录
1.设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点。
4.带头结点单链表L中删除一个最小值结点的比较高效的算法,假设最小值结点唯一
以下是几道涉及到链表的代码题。
注意涉及到链表的操作,一定要在纸上把过程先画出来,再写程序!
1.设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点。
- 因为不带头结点,所以表空这样表示:L->next == NULL
- 需要新建一个结点来释放内存,指向待删除结点:LNode *p;
- 因为是递归,搞清楚递归出口:L == NULL,从前往后删除值为val的结点:
代码
- 只需要一个存储待删除结点的p就够了
//删除不带头结点的单链表L中所有值为x的结点
void Del_x_3(LinkList &L, ElemType x){
LNode *p;
if(L == NULL) return;
if(L->next == x){
p = L;
L = L->next;
free(p);
Del_x_3(L, x);
}else{
Del_x_3(L->next, x);
}
}
这道题返回值为空,不是因为返回值地址相互连接在一起的,而是因为在本来的链表中逐个删除才得到的新链表。原理就是逐个删除等于x的结点。
2.删除带头结点的单链表L中所有值为x的结点。
这个不是递归算法,而是正常解法
- 设头结点指针pre,第一个结点指针p,需要一个存储待删除结点的指针q
- 遍历条件是p没到头:即p != NULL;
- 通过判断p->data是否等于x来进行操作:如果等于删除加上两节点后移,不等於则直接两节点后移
//删除带头结点的单链表L中所有值为x的结点。
void Del_x_2(LinkList &L, ElemType x){
LNode *p = L->next, *pre = L, *q;//新加两个指针pre和p
while(p != NULL){
if(p->data == x){
q = p;
p = p->next;
pre->next = p;
free(p);
}else{
pre = p;
p = p->next;
}
}
}
这道题返回值为空,也是通过遍历逐个删除值为x的结点实现的,操作之后直接就得出了现在的链表
3.在带头结点的单链表L中从尾到头反向输出每个结点的值
- 如果有下一个结点的话,输出下一个结点的值,然后再输出自己
代码
//在带头结点的单链表L中从尾到头反向输出每个结点的值
void R_print(LinkList L){
if(L->next != NULL){
R_print(L->next);
}
printf(L->data);
}
有头结点比较方便,不必特殊考虑第一个结点
4.带头结点单链表L中删除一个最小值结点的比较高效的算法,假设最小值结点唯一
从头到尾遍历单链表,用minp作为指向最小值的指针,遍历过程如果遇到更小值的就替换minp
- p指针工作指针,pre指针指向p的前驱;
- minp保存最小结点的指针,minpre保存最小值结点的前驱
一个一个遍历就很高效了,因为没有重复遍历,遍历一次就够了
//带头结点单链表L中删除一个最小值结点的比较高效的算法,假设最小值结点唯一
LinkList DeleteMin(LinkList &L){
LNode *pre = L, *p = L->next;
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;
}
minpre->next = minp->next; 和 free(minp); 这两句就是删除minp结点。
5.将带头结点的链表就地逆置
把头结点摘下,然后从第一个结点开始,依次插入到头结点后面直到最后一个结点
除了自带的L指针外,还需要 p 和 r 指针,r 是 p 的后继
//将带头结点的链表就地逆置
LinkList Reverse_L(LinkList L){
LNode *p, *r;
p = L->next;
L->next = NULL;//把头结点摘出来
while(p != NULL){
r = p->next;
p->next = L->next;
L->next = p;
p = r;
}
}