python单链表逆序_看图深入理解单链表的反转

如何把一个单链表进行反转?

方法1:将单链表储存为数组,然后按照数组的索引逆序进行反转。

方法2:使用3个指针遍历单链表,逐个链接点进行反转。

方法3:从第2个节点到第N个节点,依次逐节点插入到第1个节点(head节点)之后,最后将第一个节点挪到新表的表尾。

方法4: 递归(相信我们都熟悉的一点是,对于树的大部分问题,基本可以考虑用递归来解决。但是我们不太熟悉的一点是,对于单链表的一些问题,也可以使用递归。可以认为单链表是一颗永远只有左(右)子树的树,因此可以考虑用递归来解决。或者说,因为单链表本身的结构也有自相似的特点,所以可以考虑用递归来解决)

方法1:

浪费空间。

方法2:

使用p和q两个指针配合工作,使得两个节点间的指向反向,同时用r记录剩下的链表。

p = head;

q = head->next;

2019211111333977.png?2019111111346

head->next = NULL;

2019211111406049.png?2019111111412

现在进入循环体,这是第一次循环。

r = q->next;

q->next = p;

2019211111422029.png?2019111111428

p = q;

q =r;

2019211111449152.png?2019111111455

第二次循环。

r = q->next

2019211111510722.png?2019111111516

q->next = p;

2019211111535158.png?2019111111541

p = q;

2019211111553098.png?2019111111559

q = r

2019211111609230.png?2019111111615

第三次循环。。。。。

具体代码如下

ActList* ReverseList2(ActList* head)

{

//ActList* temp=new ActList;

if(NULL==head|| NULL==head->next) return head; //少于两个节点没有反转的必要。

ActList* p;

ActList* q;

ActList* r;

p = head;

q = head->next;

head->next = NULL; //旧的头指针是新的尾指针,next需要指向NULL

while(q){

r = q->next; //先保留下一个step要处理的指针

q->next = p; //然后p q交替工作进行反向

p = q;

q = r;

}

head=p; // 最后q必然指向NULL,所以返回了p作为新的头指针

return head;

}

updated 2014-01-24,重新非IDE环境写了一遍

如果觉得上面的先成环再断环的过程不太好理解,那么可以考虑下面这个办法,增加一个中间变量,使用三个变量来实现。

struct ListNode{

int val;

ListNode* next;

ListNode(int a):val(a),next(NULL){}

};

ListNode* reverseLinkedList3(ListNode* head){

if(head==NULL||head->next==NULL)

return head;

ListNode* p=head; //指向head

ListNode* r=head->next; //指向待搬运的节点,即依次指向从第2个节点到最后一个节点的所有节点

ListNode* m=NULL; //充当搬运工作用的节点

ListNode* tail=head->next;

while(r!=NULL){ //bug2 循环语句写错了, while写成了if

m=r;

r=r->next;

m->next=p->next;

p->next=m;

//if(r!=NULL)

//std::cout<<"m="<val<<" ,p="<val<<" ,r="<val<

//else

//std::cout<<"m="<val<<" ,p="<val<<" ,r=NULL"<

}

head=p->next;

tail->next=p;

p->next=NULL;

tail=p;

return head; // bug1 忘记了return

}

方法3

还是先看图,

2019211112002608.jpg?2019111112023

从图上观察,方法是:对于一条链表,从第2个节点到第N个节点,依次逐节点插入到第1个节点(head节点)之后,(N-1)次这样的操作结束之后将第1个节点挪到新表的表尾即可。

代码如下:

ActList* ReverseList3(ActList* head)

{

ActList* p;

ActList* q;

p=head->next;

while(p->next!=NULL){

q=p->next;

p->next=q->next;

q->next=head->next;

head->next=q;

}

p->next=head;//相当于成环

head=p->next->next;//新head变为原head的next

p->next->next=NULL;//断掉环

return head;

}

附:

完整的链表创建,显示,反转代码:

//创建:用q指向当前链表的最后一个节点;用p指向即将插入的新节点。

//反向:用p和q反转工作,r记录链表中剩下的还未反转的部分。

#include "stdafx.h"

#include

using namespace std;

struct ActList

{

char ActName[20];

char Director[20];

int Mtime;

ActList *next;

};

ActList* head;

ActList* Create()

{//start of CREATE()

ActList* p=NULL;

ActList* q=NULL;

head=NULL;

int Time;

cout<<"Please input the length of the movie."<

cin>>Time;

while(Time!=0){

p=new ActList;

//类似表达: TreeNode* node = new TreeNode;//Noice that [new] should be written out.

p->Mtime=Time;

cout<<"Please input the name of the movie."<

cin>>p->ActName;

cout<<"Please input the Director of the movie."<

cin>>p->Director;

if(head==NULL)

{

head=p;

}

else

{

q->next=p;

}

q=p;

cout<<"Please input the length of the movie."<

cin>>Time;

}

if(head!=NULL)

q->next=NULL;

return head;

}//end of CREATE()

void DisplayList(ActList* head)

{//start of display

cout<<"show the list of programs."<

while(head!=NULL)

{

cout<Mtime<<"\t"<ActName<<"\t"<Director<<"\t"<

head=head->next;

}

}//end of display

ActList* ReverseList2(ActList* head)

{

//ActList* temp=new ActList;

if(NULL==head|| NULL==head->next) return head;

ActList* p;

ActList* q;

ActList* r;

p = head;

q = head->next;

head->next = NULL;

while(q){

r = q->next; //

q->next = p;

p = q; //

q = r; //

}

head=p;

return head;

}

ActList* ReverseList3(ActList* head)

{

ActList* p;

ActList* q;

p=head->next;

while(p->next!=NULL){

q=p->next;

p->next=q->next;

q->next=head->next;

head->next=q;

}

p->next=head;//相当于成环

head=p->next->next;//新head变为原head的next

p->next->next=NULL;//断掉环

return head;

}

int main(int argc, char* argv[])

{

//DisplayList(Create());

// DisplayList(ReverseList2(Create()));

DisplayList(ReverseList3(Create()));

return 0;

}

方法4: 递归

updated: 2014-01-24

因为发现大部分问题都可以从递归角度想想,所以这道题目也从递归角度想了想。

现在需要把A->B->C->D进行反转,

可以先假设B->C->D已经反转好,已经成为了D->C->B,那么接下来要做的事情就是将D->C->B看成一个整体,让这个整体的next指向A,所以问题转化了反转B->C->D。那么,

可以先假设C->D已经反转好,已经成为了D->C,那么接下来要做的事情就是将D->C看成一个整体,让这个整体的next指向B,所以问题转化了反转C->D。那么,

可以先假设D(其实是D->NULL)已经反转好,已经成为了D(其实是head->D),那么接下来要做的事情就是将D(其实是head->D)看成一个整体,让这个整体的next指向C,所以问题转化了反转D。

上面这个过程就是递归的过程,这其中最麻烦的问题是,如果保留新链表的head指针呢?想到了两个办法。

// 递归版的第一种实现,借助类的成员变量m_phead来表示新链表的头指针。

struct ListNode{

int val;

ListNode* next;

ListNode(int a):val(a),next(NULL){}

};

class Solution{

ListNode* reverseLinkedList4(ListNode* head){ //输入: 旧链表的头指针

if(head==NULL)

return NULL;

if(head->next==NULL){

m_phead=head;

return head;

}

ListNode* new_tail=reverseLinkedList4(head->next);

new_tail->next=head;

head->next=NULL;

return head; //输出: 新链表的尾指针

}

ListNode* m_phead=NULL;//member variable defined for reverseLinkedList4(ListNode* head)

};

第二个办法是,增加一个引用型参数 new_head,它用来保存新链表的头指针。

struct ListNode{

int val;

ListNode* next;

ListNode(int a):val(a),next(NULL){}

};

class Solution{

ListNode* reverseLinkedList5(ListNode* head, ListNode* & new_head){ //输入参数head为旧链表的头指针。new_head为新链表的头指针。

if(head==NULL)

return NULL;

if(head->next==NULL){

new_head=head; //当处理到了旧链表的尾指针,也就是新链表的头指针时,对new_head进行赋值。因为是引用型参数,所以在接下来调用中new_head的值逐层传递下去。

return head;

}

ListNode* new_tail=reverseLinkedList5(head->next,new_head);

new_tail->next=head;

head->next=NULL;

return head; //输出参数head为新链表的尾指针。

}

};

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值