1. 程式人生 > >圖解單向連結串列反轉

圖解單向連結串列反轉

如何把一個單鏈表進行反轉?

方法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

第三次迴圈。。。。。

具體程式碼如下

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="<<m->val<<" ,p="<<p->val<<" ,r="<<r->val<<std::endl;             //else                 //std::cout<<"m="<<m->val<<" ,p="<<p->val<<" ,r=NULL"<<std::endl;         }         head=p->next;         tail->next=p;         p->next=NULL;         tail=p;         return head; // bug1 忘記了return     }

方法3

還是先看圖,

從圖上觀察,方法是:對於一條連結串列,從第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 <iostream> 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."<<endl;     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."<<endl;     cin>>p->ActName;     cout<<"Please input the Director of the movie."<<endl;     cin>>p->Director;       if(head==NULL)     {     head=p;     }     else     {     q->next=p;     }     q=p;     cout<<"Please input the length of the movie."<<endl;     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."<<endl;     while(head!=NULL)     {         cout<<head->Mtime<<"\t"<<head->ActName<<"\t"<<head->Director<<"\t"<<endl;         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為新連結串列的尾指標。     } };

---------------------  作者:feliciafay  來源:CSDN  原文:https://blog.csdn.net/feliciafay/article/details/6841115?utm_source=copy  版權宣告:本文為博主原創文章,轉載請附上博文連結!