mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4mobile wallpaper 5mobile wallpaper 6
780 字
2 分钟
反转链表——递归实现
2026-04-03

递归反转链表#

本篇包含反转打印和真实反转,坐稳发车!

一、递归打印链表#

我们要实现的效果是先正向打印链表,随后再反转打印链表,本质上链表并未有任何变化

a

比如这个链表,我们要实现打印2 6 5 4,接着是4 5 6 2

首先实现正向打印

#include<stdio.h>
#include<stdlib.h>
struct Node{
int data;
struct Node *next;
};
void Print(struct Node *p){
if(p==NULL)return;//防止无限递归
printf("%d",p->data);//先打印当前数据
Print(p->next);//递归继续调用函数
}
struct Node* Insert(struct Node *head,int data){
struct Node *temp=(struct Node*)malloc(sizeof(struct Node));
temp->data=data;
temp->next=NULL;
if(head==NULL){
head=temp;
return head;
}
struct Node *temp2=head;
while(temp2->next!=NULL){
temp2=temp2->next;
}
temp2->next=temp;
return head;
};
int main(){
struct Node *head=NULL;
head=Insert(head,2);
head=Insert(head,4);
head=Insert(head,6);
head=Insert(head,5);
Print(head);
}

那么如何反转打印链表呢???🤔

仅仅需要先递归后打印即可!

void RPrint(struct Node *p){
if(p==NULL)return;//防止无限递归
Print(p->next);//递归继续调用函数
printf("%d",p->data);//先打印当前数据
}

完整c代码

#include<stdio.h>
#include<stdlib.h>
struct Node{
int data;
struct Node *next;
};
void Print(struct Node *p){
if(p==NULL)return;//防止无限递归
printf("%d",p->data);//先打印当前数据
Print(p->next);//递归继续调用函数
}
void RPrint(struct Node *p){
if(p==NULL)return;//防止无限递归
Print(p->next);//递归继续调用函数
printf("%d",p->data);//后打印当前数据
}
struct Node* Insert(struct Node *head,int data){
struct Node *temp=(struct Node*)malloc(sizeof(struct Node));
temp->data=data;
temp->next=NULL;
if(head==NULL){
head=temp;
return head;
}
struct Node *temp2=head;
while(temp2->next!=NULL){
temp2=temp2->next;
}
temp2->next=temp;
return head;
};
int main(){
struct Node *head=NULL;
head=Insert(head,2);
head=Insert(head,4);
head=Insert(head,6);
head=Insert(head,5);
Print(head);
printf("\n");
RPrint(head);
}

cc

函数调用栈从main()开始!(忽略哪些Insert)接着进入Print(100)中,首先会执行printf("%d",p->data);打印当前数据,接着执行Print(p->next);进入Print(200)中,后面也是一样啦!😎

我们来从内存的视角看一看,栈里面有局部变量和函数,而堆里面有new或者malloc的东东😋

下图是Print函数调用过程

vv

main先入栈,后续Print跟着入栈,而栈遵循先进后出的原则,所以出栈顺序看图是从上往下。

而在RPrint函数中,我们先递归再打印。

我们将上图左边所有Print看成RPrint,由于栈是遵循先进后出的原则,又因为是先递归再打印,所以会从最后一个执行的RPrint函数开始退出,并且退出后会打印数据然后下一个栈开始退出,这就造成了反转打印的效果。

Print(p->next);//递归继续调用函数
printf("%d",p->data);//后打印当前数据

递归相比迭代会消耗大量内存,从上图就可以看出来!🤔但是有时候,递归还是有很大的用处的!

二、递归实现反转链表#

假设我们要反转的链表如下

a

结果如下

bb

接着上面反转打印的栗子,我们来简单实现一下

struct Node* Reverse(struct Node *current){
if(current==NULL||current->next==NULL){//处理单链表或者空链表,也用于遍历到末尾,返回新head
return current;
}
Reverse(head->next);
}

这样只能修改我们的head指针,因此我们还需要在出栈时(出栈相当于原路返回遍历链表!)进行操作

kk

因此我们继续修改代码

struct Node* Reverse(struct Node *current){
if(current==NULL||current->next==NULL){//这是退出递归的条件,功能是遍历链表到达尾部
return current;
}
struct Node* newhead = Reverse(current->next);
// 反转当前连接
struct Node *q = current->next;
q->next=current; // 让下一个节点指向当前节点
current->next = NULL; // 断开当前节点的原连接
return newhead;
}
//7,8两行可以优化成 current->next->next=current;

来看看出栈时的样子

qq

接着几个Reverse函数出栈也是一样的操作,大佬们可以画图理解一下🤔

current->next=NULL这个设计很巧妙!它断开了原有的150指向250的连接,也为最左边节点指向NULL做了铺垫!😎

三、疑惑?#

struct Node* Reverse(struct Node *current){
if(current==NULL||current->next==NULL){//这是退出递归的条件,功能是遍历链表到达尾部
return current;
}
struct Node* newhead = Reverse(current->next);
// 反转当前连接
struct Node *q = current->next;
q->next=current; // 让下一个节点指向当前节点
current->next = NULL; // 断开当前节点的原连接
return newhead;
}

你可能会好奇,Reverse有这么多返回值,到底会返回什么呢???又是current又是newhead的?好绕啊!

实际上,我们从调用栈的角度理解一下。

只有走到Reverse(250)会进入if条件,然后return!return 了 newhead,来自->newhead = Reverse(current->next);

而后续进行出栈的过程也就是下面

struct Node* newhead = Reverse(current->next);
// 反转当前连接
struct Node *q = current->next;
q->next=current; // 让下一个节点指向当前节点
current->next = NULL; // 断开当前节点的原连接
return newhead;

newhead一直都是Reverse(250)返回的current,也就是说整个递归过程返回的值都是最终的current(也就是被main里面赋值为head的那个指针!)

大体过程抽象为如下。

Reverse(C) → returns C
Reverse(B) → receives C, returns C
Reverse(A) → receives C, returns C
main() → gets C as newHead

有点烧脑。

ko

分享

如果这篇文章对你有帮助,欢迎分享给更多人!

反转链表——递归实现
https://fatdog.20060113.xyz/posts/reverse-linklist-digui/
作者
神秘大胖狗
发布于
2026-04-03
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

封面
Sample Song
Sample Artist
封面
Sample Song
Sample Artist
0:00 / 0:00