【前面使用的所有链表的定义在第29节】
试题1:
设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点。
首先来看非递归算法,暴力遍历:
int Del(LinkList &L,ElemType x){
//此函数实现删除链表中为x的元素
LNode *p,*q;
p = L; //p指向头结点
q = L->next; //q指向首元结点
while(q->next!=NULL){
if(q->data == x){
p->next = q->next;
free(q);
q = p->next;
}
else{
p = p->next;
q = q->next;
}
}
return 0;
}
int main(){
LinkList L;
InitList(L);
Create(L);
PrintList(L);
Del(L, 3);
PrintList(L);
return 0;
}
然后看递归算法:
int Del(LinkList &L,ElemType x){
//此函数实现递归删除链表中为x的元素
LNode *p;
if(L==NULL)
return 0;
if(L->data==x){
p = L;
L = L->next;
free(p);
Del(L, x);
}
else{
Del(L->next, x);
}
return 0;
}
int main(){
LinkList L;
InitList(L);
Create(L);
PrintList(L);
Del(L, 3);
PrintList(L);
return 0;
}
这里分析一下怎么递归的:从头开始,如果首元结点就是被删掉的x那很显然;如果不是,这时候执行Del(L->next, x),如果第2个是被删掉的元素,进入if(L->next->data==x)分支,此时p=L实际上执行p=L->next,p指向了第2个被删除的结点;第2行L = L->next执行的是L->next=L->next->next,把首元结点的next域修改为指向第3个结点;然后free(p)释放空间,最后继续执行Del(L,x)相当于Del(L->next, x),这时L->next是第3个结点,依次递归。
试题2:(与题1差不多)
试题3:L是带头结点的单链表,编写算法实现从尾到头反向输出每个结点的值
此题可以使用栈来解决,这里主要提书上的递归方法:
void AdversePrint(LinkList L){
//此函数实现反向打印链表L的元素
if(L!=NULL){
AdversePrint(L->next); //递归
printf("[%d] ", L->data); //打印当前元素
}
}
int main(){
LinkList L;
InitList(L);
Create(L);
PrintList(L);
AdversePrint(L->next); //带头结点的链表,这里L->next指向首元结点
return 0;
}
试题4:编写在带头结点的单链表L中删除一个最小值结点的高效算法。
(注意不要写野指针!)
void Deletexmin(LinkList &L){
//此函数实现删除链表最小值元素
LNode *p, *q, *m, *n;
int a;
p = L; //p指向头结点
q = L->next; //q指向首元结点
a = q->data; //首元结点元素赋给a
m = p;
n = q;
while (q->next != NULL){
q = q->next; //指针后移
p = p->next; //指针后移
if(q->data < a){
a = q->data; //更新a
m = p; //记录当前最小值的前驱结点
n = q; //记录当前最小值结点
}
}
m->next = n->next;
free(n);
}
int main(){
LinkList L;
InitList(L);
Create(L);
PrintList(L);
Deletexmin(L);
PrintList(L);
return 0;
}
试题5:将单链表的元素就地逆置
利用头插法重新建立链表:
void ReverseL(LinkList &L){
//此函数实现逆置单链表所有元素
LNode *p, *q;
p = L;
q = L->next; //q指向首元结点
p = q;
q = q->next; //q指向第二个结点
p->next = NULL;
if(q==NULL)
return ;
else{
while (q!=NULL){
p = q->next; //p移向首元结点
q->next = L->next;
L->next = q; //修改头结点指针,头插法
q = p;
}
}
}
int main(){
LinkList L;
InitList(L);
Create(L);
PrintList(L);
ReverseL(L);
PrintList(L);
return 0;
}
试题6:有一个带头结点的单链表L,设计算法使其递增有序。
采用插入排序的思想:
void SortL(LinkList &L){
//此函数实现递增排序单链表所有元素
LNode *p, *q, *r;
p = L->next; //p工作在排好序的链表
q = p->next; //q是待排序元素,即第二个结点,断开之后的第一个结点
r = q->next; //r在q之后
p->next = NULL; //断开
while(q!=NULL){
r = q->next;
p = L;
while(q->data > p->next->data && p->next!=NULL){
p = p->next;
}
q->next = p->next;
p->next = q;
q = r;
}
}
int main(){
LinkList L;
InitList(L);
Create(L);
PrintList(L);
SortL(L);
PrintList(L);
return 0;
}
输出:
请输入要输入元素的个数:5
请输入第1元素的值:5
请输入第2元素的值:3
请输入第3元素的值:1
请输入第4元素的值:2
请输入第5元素的值:4
当前单链表的所有元素:[5] [3] [1] [2] [4]
当前单链表的所有元素:[1] [2] [3] [4] [5]
试题7:(修改试题1的参数条件if(q->data == x)即可)
试题8:求两个链表的公共链表
如果有公共链表,一定是这样的Y型拓扑结构:
int LengthL(LinkList L){
//此函数实现求解链表长度
LNode *p;
p = L;
int i = 0;
while(p->next!=NULL){
p = p->next;
i++;
}
return i;
}
LinkList Search_1st_common(LinkList L1,LinkList L2){
//此函数实现查找两个链表的公共结点
int L1length = LengthL(L1);
int L2length = LengthL(L2);
printf("%d", LengthL(L1));
printf("%d", LengthL(L2));
int delta = 0; //记录长链表比短链表多多少
LNode *longList, *shortList;
if(L1length > L2length){
longList = L1->next; //L1更长,longList指向L1首元结点
shortList = L2->next;
delta = L1length - L2length;
}
else{
longList = L2->next; //L2更长,longList指向L2首元结点
shortList = L1->next;
delta = L2length - L1length;
}
printf("%d", longList->data);
printf("%d", shortList->data);
printf("%d", delta);
for (int i = 0; i < delta;i++){ // 移动longList指针至delta位置
longList = longList->next;
}
printf("%d", longList->data);
//经过以上移动,此时longList指针与shortList指针指的剩余长度一样
while (longList!=shortList && longList != NULL){
longList = longList->next;
shortList = shortList->next;
}
return longList;
}
void PrintResult(LinkList L){
if(L == NULL)
printf("公共结点不存在!");
else
PrintList(L);
}
int main(){
LinkList L1,L2;
InitList(L1);
Create(L1);
PrintList(L1);
InitList(L2);
Create(L2);
PrintList(L2);
PrintResult(Search_1st_common(L1, L2));
return 0;
}
输出:
请输入要输入元素的个数:2
请输入第1元素的值:1
请输入第2元素的值:2
当前单链表的所有元素:[1] [2]
请输入要输入元素的个数:5
请输入第1元素的值:3
请输入第2元素的值:4
请输入第3元素的值:5
请输入第4元素的值:6
请输入第5元素的值:7
当前单链表的所有元素:[3] [4] [5] [6] [7]
253136公共结点不存在!
请输入要输入元素的个数:2
请输入第1元素的值:1
请输入第2元素的值:2
当前单链表的所有元素:[1] [2]
请输入要输入元素的个数:3
请输入第1元素的值:3
请输入第2元素的值:4
请输入第3元素的值:5
当前单链表的所有元素:[3] [4] [5]
233114公共结点不存在!
在写这段代码的时候踩了一个坑:大家观察下面两段代码:
void Search_1st_common(){
//此函数实现查找两个链表的公共结点
int L1length = 3;
int L2length = 5;
int delta = 0; //记录长链表比短链表多多少
if(L1length > L2length){
delta = L1length - L2length;
}
else{
delta = L2length - L1length;
}
printf("%d", delta);
}
int main(){
Search_1st_common();
return 0;
}
void Search_1st_common(){
//此函数实现查找两个链表的公共结点
int L1length = 3;
int L2length = 5;
int delta = 0; //记录长链表比短链表多多少
if(L1length > L2length){
int delta = L1length - L2length;
}
else{
int delta = L2length - L1length;
}
printf("%d", delta);
}
int main(){
Search_1st_common();
return 0;
}
打印delta的结果分别是2和0.后一段代码中if...else...结构体内相当于重新定义了一个delta,当结构体执行结束后又被释放掉了,所以delta的返回结果是0.