图解链表反转

article/2025/9/23 12:22:10

转自:http://blog.csdn.net/feliciafay/article/details/6841115

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

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

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

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

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

 

方法1:

浪费空间。


 

方法2:

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


p = head;

q = head->next;


head->next = NULL;


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

r = q->next;

q->next = p;


p = q;

q =r;


第二次循环。

r = q->next


q->next = p;    


p = q;


q = r


第三次循环。。。。。



具体代码如下

[cpp]  view plain copy
print ?
  1. ActList* ReverseList2(ActList* head)  
  2. {  
  3.     //ActList* temp=new ActList;  
  4.  if(NULL==head|| NULL==head->next) return head;    //少于两个节点没有反转的必要。  
  5.     ActList* p;  
  6.     ActList* q;  
  7.     ActList* r;  
  8.     p = head;    
  9.     q = head->next;  
  10.     head->next = NULL; //旧的头指针是新的尾指针,next需要指向NULL  
  11.     while(q){  
  12.         r = q->next; //先保留下一个step要处理的指针  
  13.         q->next = p; //然后p q交替工作进行反向  
  14.         p = q;   
  15.         q = r;   
  16.     }  
  17.     head=p; // 最后q必然指向NULL,所以返回了p作为新的头指针  
  18.     return head;      
  19. }  

updated 2014-01-24,重新非IDE环境写了一遍
如果觉得上面的先成环再断环的过程不太好理解,那么可以考虑下面这个办法,增加一个中间变量,使用三个变量来实现。

[cpp]  view plain copy
print ?
  1. struct ListNode{  
  2.     int val;  
  3.     ListNode* next;  
  4.     ListNode(int a):val(a),next(NULL){}  
  5. };  
  6. ListNode* reverseLinkedList3(ListNode* head){  
  7.         if(head==NULL||head->next==NULL)  
  8.             return  head;  
  9.         ListNode* p=head; //指向head  
  10.         ListNode* r=head->next; //指向待搬运的节点,即依次指向从第2个节点到最后一个节点的所有节点  
  11.         ListNode* m=NULL; //充当搬运工作用的节点  
  12.         ListNode* tail=head->next;  
  13.         while(r!=NULL){  //bug2 循环语句写错了, while写成了if  
  14.             m=r;  
  15.             r=r->next;  
  16.             m->next=p->next;  
  17.             p->next=m;  
  18.             //if(r!=NULL)  
  19.                 //std::cout<<"m="<<m->val<<" ,p="<<p->val<<" ,r="<<r->val<<std::endl;  
  20.             //else  
  21.                 //std::cout<<"m="<<m->val<<" ,p="<<p->val<<" ,r=NULL"<<std::endl;  
  22.         }  
  23.         head=p->next;  
  24.         tail->next=p;  
  25.         p->next=NULL;  
  26.         tail=p;  
  27.         return head; // bug1 忘记了return  
  28.     }  


方法3

还是先看图,


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

代码如下:

[cpp]  view plain copy
print ?
  1. ActList* ReverseList3(ActList* head)  
  2. {  
  3.     ActList* p;  
  4.     ActList* q;  
  5.     p=head->next;  
  6.     while(p->next!=NULL){  
  7.         q=p->next;  
  8.         p->next=q->next;  
  9.         q->next=head->next;  
  10.         head->next=q;  
  11.     }  
  12.   
  13.     p->next=head;//相当于成环  
  14.     head=p->next->next;//新head变为原head的next  
  15.     p->next->next=NULL;//断掉环  
  16.     return head;    
  17. }  

附:

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

[cpp]  view plain copy
print ?
  1. //创建:用q指向当前链表的最后一个节点;用p指向即将插入的新节点。  
  2. //反向:用p和q反转工作,r记录链表中剩下的还未反转的部分。  
  3.   
  4. #include "stdafx.h"  
  5. #include <iostream>  
  6. using namespace std;  
  7.   
  8. struct ActList  
  9. {  
  10.     char ActName[20];  
  11.     char Director[20];  
  12.     int Mtime;  
  13.     ActList *next;  
  14. };  
  15.   
  16. ActList* head;  
  17.   
  18. ActList*  Create()  
  19. {//start of CREATE()  
  20.     ActList* p=NULL;  
  21.     ActList* q=NULL;  
  22.     head=NULL;  
  23.     int Time;  
  24.     cout<<"Please input the length of the movie."<<endl;  
  25.     cin>>Time;  
  26.     while(Time!=0){  
  27.     p=new ActList;  
  28.     //类似表达:  TreeNode* node = new TreeNode;//Noice that [new] should be written out.  
  29.     p->Mtime=Time;  
  30.     cout<<"Please input the name of the movie."<<endl;  
  31.     cin>>p->ActName;  
  32.     cout<<"Please input the Director of the movie."<<endl;  
  33.     cin>>p->Director;  
  34.   
  35.     if(head==NULL)  
  36.     {  
  37.     head=p;  
  38.     }  
  39.     else  
  40.     {  
  41.     q->next=p;  
  42.     }  
  43.     q=p;  
  44.     cout<<"Please input the length of the movie."<<endl;  
  45.     cin>>Time;  
  46.     }  
  47.     if(head!=NULL)  
  48.     q->next=NULL;  
  49.     return head;  
  50.   
  51. }//end of CREATE()  
  52.   
  53.   
  54. void DisplayList(ActList* head)  
  55. {//start of display  
  56.     cout<<"show the list of programs."<<endl;  
  57.     while(head!=NULL)  
  58.     {  
  59.         cout<<head->Mtime<<"\t"<<head->ActName<<"\t"<<head->Director<<"\t"<<endl;  
  60.         head=head->next;  
  61.     }  
  62. }//end of display  
  63.   
  64.   
  65. ActList* ReverseList2(ActList* head)  
  66. {  
  67.     //ActList* temp=new ActList;  
  68.  if(NULL==head|| NULL==head->next) return head;      
  69.     ActList* p;  
  70.     ActList* q;  
  71.     ActList* r;  
  72.     p = head;    
  73.     q = head->next;  
  74.     head->next = NULL;  
  75.     while(q){  
  76.         r = q->next; //  
  77.         q->next = p;      
  78.         p = q; //  
  79.         q = r; //  
  80.     }  
  81.     head=p;  
  82.     return head;      
  83. }  
  84.   
  85. ActList* ReverseList3(ActList* head)  
  86. {  
  87.     ActList* p;  
  88.     ActList* q;  
  89.     p=head->next;  
  90.     while(p->next!=NULL){  
  91.         q=p->next;  
  92.         p->next=q->next;  
  93.         q->next=head->next;  
  94.         head->next=q;  
  95.     }  
  96.   
  97.     p->next=head;//相当于成环  
  98.     head=p->next->next;//新head变为原head的next  
  99.     p->next->next=NULL;//断掉环  
  100.     return head;    
  101. }  
  102. int main(int argc, char* argv[])  
  103. {  
  104. //  DisplayList(Create());  
  105. //  DisplayList(ReverseList2(Create()));  
  106.     DisplayList(ReverseList3(Create()));  
  107.     return 0;  
  108. }  


方法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指针呢?想到了两个办法。

[cpp]  view plain copy
print ?
  1. // 递归版的第一种实现,借助类的成员变量m_phead来表示新链表的头指针。  
  2. struct ListNode{  
  3.     int val;  
  4.     ListNode* next;  
  5.     ListNode(int a):val(a),next(NULL){}  
  6. };  
  7.   
  8. class Solution{  
  9.      ListNode* reverseLinkedList4(ListNode* head){ //输入: 旧链表的头指针  
  10.         if(head==NULL)  
  11.             return NULL;  
  12.         if(head->next==NULL){  
  13.             m_phead=head;  
  14.             return head;  
  15.         }  
  16.         ListNode* new_tail=reverseLinkedList4(head->next);  
  17.         new_tail->next=head;  
  18.         head->next=NULL;  
  19.         return head; //输出: 新链表的尾指针  
  20.      }  
  21.     ListNode* m_phead=NULL;//member variable defined for reverseLinkedList4(ListNode* head)  
  22. };  


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

[cpp]  view plain copy
print ?
  1. struct ListNode{  
  2.     int val;  
  3.     ListNode* next;  
  4.     ListNode(int a):val(a),next(NULL){}  
  5. };  
  6.   
  7. class Solution{  
  8.     ListNode* reverseLinkedList5(ListNode* head, ListNode* & new_head){ //输入参数head为旧链表的头指针。new_head为新链表的头指针。  
  9.         if(head==NULL)  
  10.             return NULL;  
  11.         if(head->next==NULL){  
  12.             new_head=head; //当处理到了旧链表的尾指针,也就是新链表的头指针时,对new_head进行赋值。因为是引用型参数,所以在接下来调用中new_head的值逐层传递下去。  
  13.             return head;  
  14.         }  
  15.         ListNode* new_tail=reverseLinkedList5(head->next,new_head);  
  16.         new_tail->next=head;  
  17.         head->next=NULL;  
  18.         return head; //输出参数head为新链表的尾指针。  
  19.     }  
  20. };  

http://chatgpt.dhexx.cn/article/6KZOOtgF.shtml

相关文章

java链表的反转

链表的反转思想其实就是交换&#xff0c;定义两个游标分别为left和right&#xff0c; right指向链表头指针的下一个目的是当反转链表时断开链表时可以找到下一个链表的头&#xff0c;left指向链表头指针的前一个目的是反转链表时可以找到要反转的那个一个节点。 说一下顺序&…

单向链表反转(含图解)

前言 上次讲解了单向链表的原理《Java实现单向链表功能》&#xff0c;今天拓展一下实现链表的翻转。 下面直接上代码。 链表初始化 public class LinkedArray<T extends Number>{//链表的头节点private Entry<T> head;//节点实体类static final class Entry<T&…

链表(反转链表)

反转链表 文章目录 反转链表总结 反转链表 描述 给定一个单链表的头结点pHead(该头节点是有值的&#xff0c;比如在下图&#xff0c;它的val是1)&#xff0c;长度为n&#xff0c;反转该链表后&#xff0c;返回新链表的表头。 数据范围&#xff1a; 0\leq n\leq10000≤n≤1000…

链表反转详解图解

在实现反转之前&#xff0c;先回顾链表操作的一些重点。 现链表节点是以下形式&#xff1a; struct Node {int data;Node* next; }; 解决链表问题一定要理解深刻&#xff0c;一些要注意的点&#xff1a; 链表中每一个节点都是物理内存中实际存在的&#xff0c;物理节点本身…

Java链表-链表反转

基本思想 定义两个空指针&#xff08;pre和next&#xff09;&#xff0c;如果头指针指的值不为空&#xff0c;就让next存头节点的下一个节点的值&#xff08;head.next&#xff09;&#xff0c;再把pre指针的值赋到head.next&#xff0c;再把头节点的值赋到pre&#xff0c;再把…

算法基础——链表反转

一、单链表反转 &#xff08;1&#xff09;创建单链表结构类 public class Node {public int value;//当前节点的值public Node next;//next储存下一个节点地址值public Node(int value) {this.valuevalue;} } 不知道有没有小伙伴像我一样的疑惑&#xff0c;为什么单链表结构…

链表反转(C++)

思路图 这是在刷 LeetCode 看到的一个方法&#xff0c;我觉得特别简单好记&#xff0c;不管单链表还是双链表上来p1、p2、p3 直接反转。 代码实现 单链表反转 struct ListNode {int val;ListNode *next;ListNode() : val(0), next(nullptr) {}ListNode(int x) : val(x), n…

详解:链表反转

链表反转是链表算法题中较为基础的一道题&#xff0c;但对于初学者来说&#xff0c;由于对链表的结构不是很熟悉&#xff0c;一时间无从下手&#xff0c;甚至看别的的阶梯代码都会觉得很晕&#xff0c;看不懂一堆变量都是做什么的。我将会详细描述链表反转的操作&#xff0c;希…

链表反转【递归法】

目录 前言一、解题思路1.找到链表的尾部两个数据&#xff08;4、5&#xff09;2.创建逆向指针3.断开正向指针4.递归5.递归的具体过程向前移动&#xff1a;第一次&#xff1a;创建逆向指针&#xff1a;断开正向指针&#xff1a; 第二次&#xff1a;创建逆向指针&#xff1a;断开…

【C++】3.数据结构与算法:链表反转

链表反转是C面试经常会考的一道题目&#xff0c;下面介绍2种解法&#xff0c;分别是非递归法和递归法。 理论 1.非递归法&#xff08;迭代反转&#xff09; 创建3个指针pre cur nex&#xff0c;每个循环指针各向后移动一个节点。 2.递归法 通过不断压栈&#xff0c;然后退栈…

C语言实现链表反转(上)

链表反转是非常经典的题目&#xff0c;这里让我们用C语言来实现一下链表的反转 这里以无头不循环单向链表为例子&#xff08;因为这是链表中用的比较多的链表结构&#xff09; 这里首先我们先定义一个链表结构 方法一&#xff1a;用三个指针来实现指针的反转&#xff1a; 1.…

Java实现链表反转的两种思路

Java实现链表反转的两种思路 题目迭代递归 题目 将单链表的连接顺序反转过来 输入:1->2->3->4->5 输出:5->4->3->2->1 迭代 迭代&#xff0c;即遍历整个链表的节点&#xff0c;在每个节点上进行操作。每个节点之间都需要进行三个步骤&#xff1a;1.保…

Java之链表的反转

反转API设计&#xff1a; public void reverse():对整个链表反转 public Node reverse(Node curr):反转链表中的某个结点&#xff0c;并把反转后的curr结点返回 使用递归可以完成反转&#xff0c;递归反转其实就是从原链表的第一个存数据的结点开始&#xff0c;依次递归调用反转…

Golang 实现【链表反转】

题目 Golang 实现【链表反转】 如何反转一个单链表。 题目示例 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL 链表结构 type ListNode struct {Val intNext *ListNode }第一种实现 解题思路&#xff1a; 利用指针交互的思路 复杂度…

链表反转

转载&#xff1a;https://blog.csdn.net/fx677588/article/details/72357389 因本人日常是java开发&#xff0c;所以翻译成java语言代码&#xff0c;略有改动 链表的翻转是程序员面试中出现频度最高的问题之一&#xff0c;常见的解决方法分为递归和迭代两种。最近在复习的时候…

使用递归实现链表反转

链表反转&#xff08;图解&#xff09; 文章目录 链表反转&#xff08;图解&#xff09;前言一、链表反转二、递归思想三、具体实现1.反转方法API2.具体实现代码3.方法测试 四、方法调用过程总结 前言 链表反转是面试中的一个高频题目&#xff0c;可以通过多种方法实现&#x…

单向链表的反转(c++实现)

目录 前言单向链表的反转实现代码 总结更新 前言 本篇文章接着前文单链表的插入、删除&#xff08;c实现&#xff09;实现链表的反转&#xff0c;主要也即是在前文的基础上完成了一个InvertList()函数。 单向链表的反转 通过前面两篇文章的学习&#xff0c;已经对于链表的操…

C语言 单链表的反转

C语言 单链表的反转 一、简述 记--简单的将单链表的数据顺序进行反转。如将原来的顺序1 2 3 4 5 6 7 反转为&#xff1a;7 6 5 4 3 2 1 二、方式1&#xff1a;头插法 2.1 头插法1--类似新建链表 2.1.1 思路&#xff1a;断开链表头&#xff0c;然后以头插法的方式将原链表的数…

详解反转链表

LeetCode链接 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 情况一&#xff1a;头结点为空 情况二&#xff1a;链表只有一个节点 情况三&#xff1a;链表多于1个节点。 思路&#xff1a;让当前节点指向前一个节点。 如何才能做到当前…

详解链表反转问题

文章目录 链表反转问题详解前言一、整个链表反转1.栈2.头插法3.递归4.三指针法以上部分参考链接: 链接: [link](https://blog.csdn.net/Ezrealwj/article/details/119702058?ops_request_misc%257B%2522request%255Fid%2522%253A%2522166744018216782428679986%2522%252C%2522…