C语言—链表的逆置
组里考核题有这么一道题:创建一个链表,链表里的数据取随机数,现在要求把链表逆置,写出实现代码。
刚看到这道题的时候我第一想到的是交换指针实现,但是画了半天想不出来,为了过审核就用了最笨的值交换。就是把头和尾的值交换,头向后移,尾向前移,直到相遇。
后来组长除了这个值交换还说了两种方法:迭代逆置链表和递归逆置链表。
迭代逆置链表:从第一个节点开始依次改变节点指针,把原来链表里的下一个节点插在前面,从而实现逆置。
递归逆置指针:先递归到链表的最后一个节点,再从后往前改变。
1.值交换
没什么好说的,直接上代码。
注意:这里的函数的参数是指向结构体指针的指针!!!!
void listReverse(LinkList *L)
{
int index = 0;
LinkList temp = (*L)->next;
for(; temp != NULL; index++) //遍历出节点个数index
{
temp = temp->next;
}
for(int i = 0; i < index/2; i++) //外层循环 index/2 次
{
LinkList pre = (*L)->next,aft = (*L)->next;
for(int j = 0; j < i; j++) //前面的节点
{
pre = pre->next;
}
for(int k = 0; k < index-i-1; k++) //后面的节点
{
aft = aft->next;
}
int temp = pre->data; //交换前后节点的数据
pre->data = aft->data;
aft->data = temp;
}
}
2.迭代逆置链表
迭代和递归逆置链表的代码块都很小,但是需要深刻理解,我先贴上代码,然后通过画图重现过程。
void listReverse2(LinkList L)
{
printf("迭代逆置:\n");
if(L->next == NULL || L->next->next == NULL)
{
return;
}
LinkList temp = L->next;
L->next = NULL;
LinkList tail;
while(temp)
{
tail = temp;
temp = temp->next;
tail->next = L->next;
L->next = tail;
}
}
首先,我们有一条已创建好的链表:
然后我们开始执行函数:
这些做完之后开始第一次循环:
再是第二次:
这下是不是看懂了?
紧接着第三次第四次循环之后 退出循环,迭代完成。
3.递归逆置链表
思想:迭代是从第一个节点开始改变指针指向,而递归是先找到最后的节点,从后往前走。
代码:
注意:调用时参数为头节点的下一个节点的指针。如果没有头节点就不用管
LinkList listReverse2(LinkList L)
{
if(L->next == NULL)
{
return L;
}
LinkList newhead = listReverse2(L->next);
L->next->next = L;
L->next = NULL;
return newhead;
}
首先是我们本来给定的链表:
开始递归,到最深处,newhead有值了
然后开始回溯,L向前移动
继续回溯,最终完成逆置(注意:如果链表有头节点,千万不能以头节点作为参数,否则头节点会被逆置成新链表的最后一个节点,而这个节点里的值是不可预料的。)
这样就用递归完成了链表的逆置。