单链表反转(逆向)据说时一道面试的老题,问题想来应该不难,但动手写来发现真是方法各异,繁简不一
在此把各种思想都实现了一边,大致如此:
- 用滑动的指针将链表中每一个指针反转
- 将链表一分为2,right链表依次在left链表的头部插入
- 对方法2的优化
- 递归实现,直接利用子问题是原问题的更小规模
- 对递归的优化,这个写的头有点大
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;
}
}