细说单链表反转(单链表逆向)

本文详细介绍了链表反转的多种方法,包括滑动法、逐次插入法及其优化版,递归实现及其优化,通过实例代码展示了每种方法的特点和优缺点,帮助读者深入理解链表操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单链表反转(逆向)据说时一道面试的老题,问题想来应该不难,但动手写来发现真是方法各异,繁简不一

在此把各种思想都实现了一边,大致如此:

  1. 用滑动的指针将链表中每一个指针反转
  2. 将链表一分为2,right链表依次在left链表的头部插入
  3. 对方法2的优化
  4. 递归实现,直接利用子问题是原问题的更小规模
  5. 对递归的优化,这个写的头有点大

1、

struct Node
{
	int val;
	Node* next;
	Node(int i):val(i),next(NULL){}
};

//滑动法反转链表,调用方法:head=Reverse(&head);
void Reverse(Node **head)
{
	if(*head==NULL||(*head)->next==NULL)
		return;
	Node *lef=*head;
	Node *rig=lef->next;
	bool isHead=true;
	while(rig->next!=NULL)
	{
		lef=rig;
		rig=rig->next;
		if(isHead)	//处理反转后第一个节点变为尾节点
		{
			(*head)->next=NULL;
			isHead=false;
		}
		lef->next=*head;
		*head=lef;
	}
	rig->next=lef;	//处理最后一个节点
	*head=rig;
}

2、

//逐次插入反转链表,调用方法:head=Reverse(head);可以避免二维指针参数
//rig指向待排序的部分,rigHead指向将要移动的节点
Node* Reverse2(Node* head)
{
	if(head==NULL||head->next==NULL)
		return NULL;
	Node* rig=head->next;
	head->next=NULL;
	Node* rigHead;
	while(rig!=NULL)
	{
		rigHead=rig;
		rig=rig->next;
		rigHead->next=head;
		head=rigHead;
	}
	return rigHead;
}

3、


//Reverse2的优化
//pre指向完成逆序的前半部分,next指向待排序的后半部分
Node* Reverse22(Node* head)
{
	Node *pre=NULL,*next;
	while(head!=0)
	{
		next=head->next;
		head->next=pre;
		pre=head;
		head=next;
	}
	return pre;
}

4、

//用递归解决,栈开销大,复杂度为O(n^2)
//head为首节点,inorder为排好顺序的节点
Node* Reverse_recur(Node* p)
{
	if(p==NULL||p->next==NULL)
		return p;
	Node* inorder=Reverse_recur(p->next);
	Node* res=inorder;
	while(res->next!=NULL)
		res=res->next;
	res->next=p;
	p->next=NULL;
	return inorder;
}

5、

//优化的递归,线性复杂度
//递找到尾节点tail,每次归将尾节点的前一个节点p移到最后
Node* Reverse_recur2(Node* p)
{
	if(p==NULL||p->next==NULL)
		return p;
	Node *tail=Reverse_recur2(p->next);
	p->next->next=p;
	p->next=NULL;
	return tail;
}


完整代码:

/*************************************************************************
    > File Name: list.cpp
    > Title:输入链表,将其反转后输出 
    > Description: 可以使用反转函数,但建议顺次遍历链表,每次从头部插入
	> Look out:普通指针形参无法修改指针实参
    > Created Time: 2014年03月09日 星期日 09时27分04秒
 ************************************************************************/

#include<iostream>
using namespace std;

struct Node
{
	int val;
	Node* next;
	Node(int i):val(i),next(NULL){}
};

//注意:要改变指针的值,需要使用指向指针的指针
void Insert(Node** head,int val)
{
	Node* cur=new Node(val);
	cur->next=*head;
	*head=cur;
}

//滑动法反转链表,调用方法:head=Reverse(&head);
void Reverse(Node **head)
{
	if(*head==NULL||(*head)->next==NULL)
		return;
	Node *lef=*head;
	Node *rig=lef->next;
	bool isHead=true;
	while(rig->next!=NULL)
	{
		lef=rig;
		rig=rig->next;
		if(isHead)	//处理反转后第一个节点变为尾节点
		{
			(*head)->next=NULL;
			isHead=false;
		}
		lef->next=*head;
		*head=lef;
	}
	rig->next=lef;	//处理最后一个节点
	*head=rig;
}

//逐次插入反转链表,调用方法:head=Reverse(head);可以避免二维指针参数
//rig指向待排序的部分,rigHead指向将要移动的节点
Node* Reverse2(Node* head)
{
	if(head==NULL||head->next==NULL)
		return NULL;
	Node* rig=head->next;
	head->next=NULL;
	Node* rigHead;
	while(rig!=NULL)
	{
		rigHead=rig;
		rig=rig->next;
		rigHead->next=head;
		head=rigHead;
	}
	return rigHead;
}
//Reverse2的优化
//pre指向完成逆序的前半部分,next指向待排序的后半部分
Node* Reverse22(Node* head)
{
	Node *pre=NULL,*next;
	while(head!=0)
	{
		next=head->next;
		head->next=pre;
		pre=head;
		head=next;
	}
	return pre;
}

//用递归解决,栈开销大,复杂度为O(n^2)
//head为首节点,inorder为排好顺序的节点
Node* Reverse_recur(Node* p)
{
	if(p==NULL||p->next==NULL)
		return p;
	Node* inorder=Reverse_recur(p->next);
	Node* res=inorder;
	while(res->next!=NULL)
		res=res->next;
	res->next=p;
	p->next=NULL;
	return inorder;
}
//优化的递归,线性复杂度
//递找到尾节点tail,每次归将尾节点的前一个节点p移到最后
Node* Reverse_recur2(Node* p)
{
	if(p==NULL||p->next==NULL)
		return p;
	Node *tail=Reverse_recur2(p->next);
	p->next->next=p;
	p->next=NULL;
	return tail;
}

int main()
{
	int n;
	while(cin>>n)	//输入链表长度n
	{
		if(n==0)
		{
			cout<<"NULL"<<endl;
			continue;
		}
		Node* head=NULL;
		while(n--)	//按照输入顺序的逆序生成链表
		{
			int cur;
			cin>>cur;
			Insert(&head,cur);	//欲改变head的值,要传递其地址
		}

		//对链表进行反转
		//Reverse(&head);
		//head=Reverse2(head);
		//head=Reverse22(head);
		//head=Reverse_recur(head);
		head=Reverse_recur2(head);

		//遍历输出后析构各节点
		while(head!=NULL)
		{
			cout<<head->val;
			if(head->next!=NULL)
				cout<<" ";
			//head=head->next;	直接移动头指针会发生内存泄漏
			Node* used=head;
			head=head->next;
			delete used;
		}
		cout<<endl;
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值