定義一個方法(函數),實現輸入一個鏈表的頭結點,然后可以反轉這個鏈表的方向,並輸出反轉之后的鏈表的頭結點。
typedef struct Node{ int data; Node *next; } Node, *List;
鏈表類的問題,涉及到了很多指針的操作,需要嚴謹的分析,全面的分析問題之后,在開始寫代碼,磨刀不誤砍柴工!反轉鏈表,直接的想法,就是把鏈表中指針的方向反轉就可以了,如圖所示:
假設 i 結點之前,我們把所有的結點的指針都已經反轉了,那么自然 i 和以后的結點鏈接發生了斷裂!如下圖;
這樣的話,無法繼續遍歷 i 以后的結點了,那么自然想到,在斷鏈之前,提前保存之前的狀態。那么自然想到定義三個指針,分別指向當前結點 i,i 的后繼 j,i 的前驅 h 結點。保存斷鏈之前的三個結點的連接狀態。然后,假設沒問題了,那么繼續反轉完畢,最后鏈表的尾結點就是反正鏈表的頭結點了,也就是 next 為 null 的結點,是原始鏈表的尾結點。
#include <iostream> using namespace std; typedef struct Node{ int data; Node *next; } Node, *List; Node * reverseList(List head){ //定義三個指針,保存原來的連接的狀態 //當前結點指針 Node *pnow = head; //當前結點的前驅指針,初始化是 NULL Node *pre = NULL; //當前結點的后繼指針,初始化也是 null Node *pnext = NULL; //定義尾指針 Node *tail = NULL; //開始遍歷鏈表 while(pnow != NULL){ //如果當前結點不是 null,那么初始化 pnext 指針指向當前結點的下一個結點 pnext = pnow->next; //如果找到了尾結點,初始化 tail 指針 if(NULL == pnext){ tail = pnow; } //進行鏈表的反轉,當前結點的 next 指針指向前一個結點,實現鏈表方向的反轉,此時發生了斷鏈 pnow->next = pre; //勿忘斷鏈的情形,需要使用 pre 指針保存狀態,pre 等價於是后移一個結點 pre = pnow; //pnow 后移一個結點 pnow = pnext; } return tail; }
定義的這個三個指針,目的就是防止斷鏈之后無法繼續遍歷鏈表以后的結點,實現全部的反轉。當 pnow 的 next 指向 pnow 的前驅pre(初始化是 null)的時候,已經實現了 pnow 和前驅pre的方向反轉,但是 pnow 此時就和后繼pnext斷鏈了,那么使用 pre 后移的方式,指向 pnow,同時 pnow 也后移,指向 pnext,而 pnext 繼續指向更新之后的 pnow 的 next 結點即可。從而實現了狀態的保存,繼續遍歷全部結點,實現鏈表反轉。
注意關於鏈表問題的常見注意點的思考:
1、如果輸入的頭結點是 NULL,或者整個鏈表只有一個結點的時候
2、鏈表斷裂的考慮
下面看看遞歸的實現方式
遞歸的方法其實是非常巧的,它利用遞歸走到鏈表的末端,然后再更新每一個node的next 值 ,實現鏈表的反轉。而newhead 的值沒有發生改變,為該鏈表的最后一個結點,所以,反轉后,我們可以得到新鏈表的head。
//遞歸方式 Node * reverseList(List head) { //如果鏈表為空或者鏈表中只有一個元素 if(head == NULL || head->next == NULL) { return head; } else { //先反轉后面的鏈表,走到鏈表的末端結點 Node *newhead = reverseList(head->next); //再將當前節點設置為后面節點的后續節點 head->next->next = head; head->next = NULL; return newhead; } }
程序剛開始執行,if 語句失效,進入 else 語句,然后執行Node *newhead = reverseList(head->next);第二個結點的指針參數傳入遞歸函數,一直到,最后一個結點的指針參數傳入遞歸函數,if 語句有效head->next == NULL,返回當前的head 給 newhead 指針指向,如圖:
其實在遞歸函數棧內,按照后進先出的順序,執行一級級的遞歸函數,返回末位結點給 newhead 之后,執行遞歸棧里的第二個遞歸函數,發生如圖
返回 newhead,也就是新的反轉之后的鏈表(臨時的),然后進入到遞歸工作棧里的第一個遞歸函數,如圖:
返回 newhead,也就是反轉之后的鏈表,此時遞歸工作棧的函數全部執行,返回的結點就是反轉之后的鏈表的頭結點(之前的尾結點)
歡迎關注
dashuai的博客是終身學習踐行者,大廠程序員,且專注於工作經驗、學習筆記的分享和日常吐槽,包括但不限於互聯網行業,附帶分享一些PDF電子書,資料,幫忙內推,歡迎拍磚!