看图理解单链表的反转

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

方法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. p->next=head;//相当于成环
  13. head=p->next->next;//新head变为原head的next
  14. p->next->next=NULL;//断掉环
  15. return head;
  16. }

附:

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

[cpp] view plain copy

print?

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

方法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. class Solution{
  8. ListNode* reverseLinkedList4(ListNode* head){ //输入: 旧链表的头指针
  9. if(head==NULL)
  10. return NULL;
  11. if(head->next==NULL){
  12. m_phead=head;
  13. return head;
  14. }
  15. ListNode* new_tail=reverseLinkedList4(head->next);
  16. new_tail->next=head;
  17. head->next=NULL;
  18. return head; //输出: 新链表的尾指针
  19. }
  20. ListNode* m_phead=NULL;//member variable defined for reverseLinkedList4(ListNode* head)
  21. };

第二个办法是,增加一个引用型参数 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. class Solution{
    7. ListNode* reverseLinkedList5(ListNode* head, ListNode* & new_head){ //输入参数head为旧链表的头指针。new_head为新链表的头指针。
    8. if(head==NULL)
    9. return NULL;
    10. if(head->next==NULL){
    11. new_head=head; //当处理到了旧链表的尾指针,也就是新链表的头指针时,对new_head进行赋值。因为是引用型参数,所以在接下来调用中new_head的值逐层传递下去。
    12. return head;
    13. }
    14. ListNode* new_tail=reverseLinkedList5(head->next,new_head);
    15. new_tail->next=head;
    16. head->next=NULL;
    17. return head; //输出参数head为新链表的尾指针。
    18. }
    19. };
时间: 2024-08-06 03:45:25

看图理解单链表的反转的相关文章

单链表的反转

如何把一个单链表进行反转? 方法1:将单链表储存为数组,然后按照数组的索引逆序进行反转. 方法2:使用3个指针遍历单链表,逐个链接点交替使用指针改变链表的指向进行反转. 方法3:从第3个节点到第N-1个节点,依次逐节点插入到第1个节点(head节点)之后,再将第N个节点指向head(成环),然后将此时head的下一个节点设为head,最后将原head指向NULL. 方法4:   递归(没搞懂~) 方法2: ActList* ReverseList2(ActList* head) {   //Ac

秒懂单链表及其反转(reverse)

什么是链表,这种数据结构是由一组Node组成的,这群Node一起表示了一个序列.链表是最普通,最简单的数据结构,它是实现其他数据结构如stack, queue等的基础. 链表比起数组来,更易于插入,删除. Node可以定义如下: typedef int element_type; typedef struct node *node_ptr; struct node { element_type element; node_ptr next; }; 另外关于要不要头节点这个问题,我建议加上头节点,

单链表的反转问题

单链表的反转问题 单链表反转问题经常会遇到.在此记录一下,以便查阅方便. 如果反转一个有头结点的使用下面的方法比较合适. //反转单链表,此单链表带有头节点. //思想:使用tmp临时指针保存头结点与链表的关系 typedef struct ListNode  { int data; struct ListNode * next; }ListNode,*LinkList; void ReverseList(ListNode* Head) { ListNode *current,*tmp; cur

用两种递归思路与循环实现单链表的反转

typedef struct ListNode{ int data; struct ListNode *next; }ListNode; //递归一 ListNode *ReverseList (ListNode *pHead, ListNode *nHead = NULL) { //每次取下第一个节点头插法创建新链表 //nHead为反转后链表的头节点 if(pHead == NULL) return NULL; ListNode *pNext = pHead -> next; pHead -

[算法]实现单链表的反转

实现链表的反转 解题思路: 为了正确反转一个链表,需要调整指针的指向.举例说明,例如i,m,n是三个相邻的结点,假设经过若干步操作,已经把结点i之前的指针调整完毕,这些结点的next指针都指向前面一个结点.现在遍历到结点m,当然需要调整结点的next指针,让它指向结点i,但需要注意的是,一旦调整了指针的指向,链表就断开了,因为已经没有指针指向结点n,没有办法再遍历到结点n了,所以为了避免指针断开,需要在调整m的next之前要把n保存下来.接下来试着找到反转后链表的头结点.不难分析出翻转后链表的头

线性表总结(单链表的反转)

主要总结单链表反转的几种方法 第一种方法貌似是递归,不太懂,第二种方法使用三个指针逐一完成逆置 结构体定义:class ListNode { int val; ListNode next; ListNode(int x) { //这步没看懂,是结构体里引用了自己吗 val = x; next = null; } } 1 // 1.就地反转法 2 public ListNode reverseList1(ListNode head) { 3 if (head == null) 4 return h

单链表的反转 python实现实例

单链表反转实现 1.递归实现 根据递归,递归到最后一个节点(条件为head3为非空,其下一个指向为空),将其next指向前一个结点,前一个结点的指向为None. def recurse(head, newhead): # 递归,head为原链表的头结点,newhead为反转后链表的头结点 if head is None: return if head.next is None: newhead = head else: newhead = recurse(head.next, newhead)

单链表的反转非递归算法

定义单链表的结点 typedef struct ListNode{ int value; ListNode *next; }ListNode; 我们采用的单链表是带头结点的. 需要遍历一遍链表,在遍历过程中,把遍历的节点一次插入到头部.在这个过程之后,第一个节点成了最后节点,因此要特殊处理,改其后继为NULL. void Inversion(ListNode* head) { if(head->next == NULL) return; //带头结点的单链表,当单链表为空时 if(head->

小代码 反转单链表和 反转前K个节点的单链表

 /********************       WZ  ASUST  2016 代码与反思    ********************/ #include<iostream> #include<assert.h> #include<vector>//容器--类模板 #include<stdlib.h>//利用随机值 #include<time.h> using namespace std;   #define N 1000  #de