本文主要以圖的方式,來呈現鏈表反轉推演的具體過程,以助於理解,保持思路的清晰。
主要采用兩種方法實現單鏈表反轉:
(1)通過循環,通過三個指針對鏈表進行遍歷,並逐個反轉;
(2)使用遞歸的方法進行反轉。
1. 循環反轉
廢話不多說,先上圖:
操作過程:
① 初始化pNext至當前節點的下一個節點,為斷鏈做准備
② 判斷下一個節點是否為NULL,若為NULL則為尾節點,即反轉后的頭指針pNewHead指向該節點
③ 反轉當前節點
④ 當前節點反轉完成后,准備下一輪反轉操作,pPre前進至當前節點
⑤ pNow前進一個節點
相關代碼如下:
struct node { int data; struct node *next; }; typedef struct node LIST;
LIST * reverseList(LIST *phead) { LIST *pnow = phead; LIST *ppre = NULL; LIST *pnext = NULL; LIST *newhead = NULL; //開始遍歷鏈表,若鏈表為空,返回NULL while(NULL != pnow){ //若當前指針非NULL,則將pnext初始化為當前節點的下一個 pnext = pnow->next; //鏈表只有一個元素,無需執行翻轉操作 if(NULL == pnext){ newhead = pnow; } //當前節點指向前一個節點ppre pnow->next = ppre; //前一個節點ppre向后移動一個節點 ppre = pnow; //當前節點pnow向后移動一個節點 pnow = pnext; } printf("Reverse done!\n"); return newhead; }
2. 遞歸反轉
理解對鏈表的反轉,首先對遞歸的過程要有一個清晰的認識,要能找到:
① 遞歸的終止條件:找到尾節點
② 前后相鄰兩個過程的關系:原來后一個節點的next指針指向前一個節點
關於遞歸的內容請網上搜索相關內容。
相關操作過程如下:
首先,通過終止條件,找到尾節點;然后,依次執行反轉操作,最終實現全部反轉。(圖中,pCur(n)代表當前處於第n次遞歸處理過程中)
需要注意的是,在每次執行完反轉操作后,要將當前節點的next指針指向Null,即 current->next = NULL; ,否則鏈表會亂掉,詳細分析見下圖
假設當前操作指針指向【節點2】,並且在上一輪遞歸中,沒有執行current->next = NULL; ,此時【節點3】->next = 【節點4】(見灰色箭頭),此時,若執行代碼current->next->next = current; 意圖反轉【節點3】時,current->next->next卻依然指向【節點4】,會破壞原【節點4】的指向(見紅色箭頭),從而失去對鏈表的控制。
相關代碼如下:
LIST *reverseList2(LIST *phead) { LIST *current = phead; //當檢測到鏈表為空,或者已經檢測到尾節點時,滿足終止條件,停止向下遞歸 if(NULL == current || NULL == current->next){ return current; } //執行遞歸操作,尋找尾節點 LIST *newhead = reverseList2(current->next); //反轉操作,目的是完成當前節點的下一個節點,完成指向當前節點的操作 current->next->next = current; //該語句很重要! current->next = NULL; printf("Reverse2 done!\n"); return newhead; }
僅一家之言,望多交流,如有錯漏,還請指教!
另,做圖不易,轉發請注明出處 https://www.cnblogs.com/luego/p/11421590.html
本文參考:
https://www.cnblogs.com/Pushy/p/8455862.html