c语言实现单链表反转的四种方法

链表反转即假设有一链表1->2->3,反转后为3->2->1

以下的方法是没有头节点只有首元节点的情况

方法一:迭代法
如图所示,创建三个指针。小方块从左到右的值分别为1、2、3,假设
是以1->2->3的方向,那么,如果想实现链表反转,可以让中间的mid指针
从原来指向end变为指向pre,然后三个指针整体向右移动,mid再指向pre,直到end指向了NULL为止。最后让头指针指向mid即可,此时方向变为3->2->1
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

代码如下:

#include<Stdio.h>
#include<Stdlib.h>
typedef struct Node{
	int elem;
	struct Node *next;
}node;
node *initNode(){
	node *end=(node *)malloc(sizeof(node));//尾指针 
	node *p=(node *)malloc(sizeof(node));//首元节点 
	p->elem=1;
	p->next=NULL;
	end=p;
	for(int i=2;i<=3;i++){
		node *newnode=(node *)malloc(sizeof(node));
		newnode->elem=i;
		newnode->next=NULL;
		//尾插法 
		end->next=newnode;
		end=newnode;
	}
	return p;
}
void show(node *p){
	node *temp=p;
	while(temp){
		printf("%d",temp->elem);
		temp=temp->next;
	}
	printf("\n");
}
node *iteration(node *p){
	if(p==NULL||p->next==NULL){
		return p;
	}else{
		node *pre=NULL;
		node *mid=p;
		node *end=p->next;
		while(true){
			mid->next=pre;
			if(end==NULL){
				break;
			}
			//整体右移 
			pre=mid;
			mid=end;
			end=end->next;
		}
		p=mid;//原来的头指针指向mid(因为此时mid为首元节点)
		return p; 
	}
}
int main(void){
	node *p=initNode();
	show(p);
	p=iteration(p);
	show(p);
	return 0;
}

方法二:递归法
该方法是通过递归,使得指针指向最后一个结点,然后从后往前改变指针的指向,从而实现反转。
有几点需要注意的:
1.需要建立一个头指针,返回该头指针。
2.需要建立一个从后往前递归的指针,从而不断地改变指针指向,即
head->next->next=head;
3.最重要的一点!!!
必须把原来结点的指针域置空,即head->next=NULL;不然,请看第二张图:
由于我们马上要写的函数当head指针指向1的时候,便结束循环,如果我们只写head->next->next=head;前面的2和3的指针域与确实分别指向1和2;
但是1的指针域指向的是2,当我们遍历的时候,由于循环结束的条件是:

while(temp){
temp=temp->next;
}

当temp指针指向1的时候,temp->next指向2,即temp此时指向2,然后while循环判断不为空,从而执行temp=temp->next,又指向了1。1和2之间就形成了一个循环链表,永远不会结束循环,你会在屏幕上看到2121212121无限循环…,所以必须把原来的指针域置空!!!!
在这里插入图片描述
在这里插入图片描述

代码如下:

#include<stdio.h>
#include<stdlib.h>
typedef struct Node{
	int elem;
	struct Node *next;
}node;
node *initNode(){
	node *end=NULL;
	node *p=(node *)malloc(sizeof(node));
	p->next=NULL;
	p->elem=1;
	end=p;
	for(int i=2;i<3;i++){
		node *newnode=(node *)malloc(sizeof(node));
		newnode->next=NULL;
		newnode->elem=i;
		end->next=newnode;
		end=newnode;
	}
	return p;
}
void show(node *p){
	node *temp=p;
	while(temp){
		printf("%d ",temp->elem);
		temp=temp->next;
	}
	printf("\n");
}
node *recursion(node *p){
	if(p==NULL||p->next==NULL){
		return p;
	}else{
		node *newnode = recursion(p->next);
		p->next->next=p;
		p->next=NULL;
		return newnode;
	}
}
int main(void){
	node *p=initNode();
	show(p);
	p=recursion(p);
	show(p);
	return 0;
}

有一点需要提一下:
node *newnode = recursion(p->next);

return newnode;
返回值是newnode,这个值不变,一直指向末尾(即反转后链表的头指针)
而每次返回p都会左移,直到移动到原链表第一个结点为止。

方法三:新建链表
该方法是新建一个链表,然后循环要反转的链表中的每个元素,通过头插法(因为头插法会改变数据原来的顺序,正好适合反转)插入到新链表中的方法。
在这里提一下:
有头结点和没有头结点的头插法写法是不一样的,而尾插法写法是一样的
有头结点的头插法:

node *head;//头结点
head->next=NULL;
node *newnode=(node *)malloc(sizeof(node));
newnode->next=head->next;
head->next=newnode;

没有头结点的头插法:

node *p;//首元节点
p->elem=xxx;
p->next=NULL;
node *newnode=(node *)malloc(sizeof(node));
newnode->next=p;
p=newnode;

无论是否有头结点的尾插法:

node *end=NULL;//尾指针
node *head=(node *)malloc(sizeof(node));//有头结点
//只有首元结点则node *p=(node *)malloc(sizeof(node));和上面一样
head->next=NULL;
end=head;
node *newnode=(node *)malloc(sizeof(node))
end->next=newnode;
end=newnode;

代码如下:

#include<stdio.h>
#include<stdlib.h>
typedef struct Node{
	int elem;
	struct Node *next;
}node;
node *initNode(){
	node *end=NULL;
	node *p=(node *)malloc(sizeof(node));
	p->next=NULL;
	p->elem=1;
	end=p;
	for(int i=2;i<4;i++){
		node *newnode=(node *)malloc(sizeof(node));
		newnode->next=NULL;
		newnode->elem=i;
		end->next=newnode;
		end=newnode;
	}
	return p;
}
void show(node *p){
	node *temp=p;
	while(temp){
		printf("%d ",temp->elem);
		temp=temp->next;
	}
	printf("\n");
}
node *head(node *p){
	node *new_p=NULL;
	node *temp=NULL;
	if(p==NULL||p->next==NULL){
		return p;
	}
	while(p){
		temp=p;
		p=p->next;
		temp->next=new_p;
		new_p=temp;
	}
	return new_p;
}
int main(void){
	node *p=initNode();
	show(p);
	p=head(p);
	show(p);
	return 0;
}

注意一点:

while(p){
		temp=p;
		p=p->next;
		temp->next=new_p;
		new_p=temp;
	}

这部分代码中,p=p->next必须在temp=p后面,如果放在最后面,由于
temp->next=new_p,使得temp指向的结点到后面所有结点的链断了(因为该节点的指针域不指向后面而指向new_p了),但是此时p也指向该结点,所以,此时的p=p->next为NULL(因为断链了)

方法4:在原链表上直接反转
思路是这样的:我们需要创建两个指针,如下图(图中有一个头指针p没画出来)。然后把第二个结点移除,操作类似于删除结点,就是让第一个结点的指针域指向第三个结点,
即pre->next=end->next,然后让第二个结点指向第一个结点,
即end->next=p,然后p指向end,接下来让end指针指向pre->next,即第三个结点。一直循环下去,直到end为NULL。

在这里插入图片描述

代码如下:

#include<stdio.h>
#include<stdlib.h>
typedef struct Node{
	int elem;
	struct Node *next;
}node;
node *initNode(){
	node *end=NULL;
	node *p=(node *)malloc(sizeof(node));
	p->next=NULL;
	p->elem=1;
	end=p;
	for(int i=2;i<4;i++){
		node *newnode=(node *)malloc(sizeof(node));
		newnode->next=NULL;
		newnode->elem=i;
		end->next=newnode;
		end=newnode;
	}
	return p;
}
void show(node *p){
	node *temp=p;
	while(temp){
		printf("%d ",temp->elem);
		temp=temp->next;
	}
	printf("\n");
}

			pre=mid;
			mid=end;
			end=end->next;
		}
		p=mid;
		return p;
	}
}
node *recursion(node *p){
	if(p==NULL||p->next==NULL){
		return p;
	}else{
		node *newnode = recursion(p->next);
		p->next->next=p;
		p->next=NULL;
		return newnode;
	}
}
node *head(node *p){
	node *new_p=NULL;
	node *temp=NULL;
	if(p==NULL||p->next==NULL){
		return p;
	}
	while(p){
		temp=p;
		p=p->next;
		temp->next=new_p;
		new_p=temp;
	}
	return new_p;
}
node *local(node *p){
	node *pre=NULL;
	node *end=NULL;
	if(p==NULL||p->next==NULL){
		return p;
	}
	pre=p;
	end=p->next;
	while(end){
		pre->next=end->next;
		end->next=p;
		p=end;
		end=pre->next;
	}
	return p;
}
int main(void){
	node *p=initNode();
	show(p);
	p=recursion(p);
	show(p);
	p=head(p);
	show(p);
	p=local(p);
	show(p);
	return 0;
}
  • 22
    点赞
  • 136
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,可以开始讨论如何用C语言实现链表递归反转。 首先,我们需要了解链表和递归的概念。链表是由一系列节点组成的数据结构,每个节点都包含一个数据元素和一个指向下一个节点的指针。递归则是一种通过函数自身不断调用来解决问题的方法。 在链表中,反转的关键在于修改每个节点的指针指向前一个节点。而递归则可以通过不断递归到链表尾部,并在回溯的过程中修改指针来完成反转。 下面是用C语言实现链表递归反转的代码: ``` #include <stdio.h> #include <stdlib.h> struct Node { int data; struct Node* next; }; struct Node* reverse(struct Node* head) { if (head == NULL || head->next == NULL) { return head; } struct Node* newHead = reverse(head->next); head->next->next = head; head->next = NULL; return newHead; } int main() { struct Node* head = NULL; // 创建链表 head = (struct Node*)malloc(sizeof(struct Node)); head->data = 1; head->next = (struct Node*)malloc(sizeof(struct Node)); head->next->data = 2; head->next->next = (struct Node*)malloc(sizeof(struct Node)); head->next->next->data = 3; head->next->next->next = (struct Node*)malloc(sizeof(struct Node)); head->next->next->next->data = 4; head->next->next->next->next = NULL; // 反转链表 head = reverse(head); // 打印链表 while (head != NULL) { printf("%d ", head->data); head = head->next; } return 0; } ``` 在上面的代码中,我们定义了一个Node结构体来表示节点,其中包括了数据和指向下一个节点的指针。reverse函数通过递归来实现链表反转,并返回反转后的新头节点。在递归的过程中,我们先递归到链表尾部,然后在回溯的过程中修改每个节点的指针,实现链表反转。 希望这个例子能帮助您更好地理解链表递归反转的原理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值