單鏈表反轉 非遞迴 遞迴方式實現

2021-08-20 18:16:57 字數 2406 閱讀 1280

鍊錶的翻轉是程式設計師面試中出現頻度最高的問題之一,常見的解決方法分為遞迴和迭代兩種。最近在複習的時候,發現網上的資料都只告訴了怎麼做,但是根本沒有好好介紹兩種方法的實現過程與原理。所以我覺得有必要好好的整理一篇博文,來幫忙大家一步步理解其中的實現細節。

我們知道迭代是從前往後依次處理,直到迴圈到鏈尾;而遞迴恰恰相反,首先一直迭代到鏈尾也就是遞迴基判斷的準則,然後再逐層返回處理到開頭。總結來說,鍊錶翻轉操作的順序對於迭代來說是從鏈頭往鏈尾,而對於遞迴是從鏈尾往鏈頭。下面我會用詳細的**來剖析其中實現的細節。

1、非遞迴(迭代)方式

迭代的方式是從鏈頭開始處理,如下圖給定乙個存放5個數的鍊錶。

首先對於鍊錶設定兩個指標:

然後依次將舊鍊錶上每一項新增在新鍊錶的後面,然後新鍊錶的頭指標newh移向新的煉表頭,如下圖所示。此處需要注意,不可以上來立即將上圖中p->next直接指向newh,這樣存放2的位址就會被丟棄,後續鍊錶儲存的資料也隨之無法訪問。而是應該設定乙個臨時指標tmp,先暫時指向p->next指向的位址空間,儲存原鍊錶後續資料。然後再讓p->next指向newh,最後p=tmp就可以取回原鍊錶的資料了,所有迴圈訪問也可以繼續展開下去。

指標繼續向後移動,直到p指標指向null停止迭代。

最後一步:

2、非遞迴實現的程式

node*

reverselist(node*

h) return

newh;

}

3、遞迴方式

我們再來看看遞迴實現鍊錶翻轉的實現,前面非遞迴方式是從前面數1開始往後依次處理,而遞迴方式則恰恰相反,它先迴圈找到最後面指向的數5,然後從5開始處理依次翻轉整個鍊錶。

首先指標h迭代到底如下圖所示,並且設定乙個新的指標作為翻轉後的鍊錶的頭。由於整個鍊錶翻轉之後的頭就是最後乙個數,所以整個過程newh指標一直指向存放5的位址空間。

然後h指標逐層返回的時候依次做下圖的處理,將h指向的位址賦值給h->next->next指標,並且一定要記得讓h->next =null,也就是斷開現在指標的鏈結,否則新的鍊錶形成了環,下一層h->next->next賦值的時候會覆蓋後續的值。

繼續返回操作:

上圖第一次如果沒有將存放4空間的next指標賦值指向null,第二次h->next->next=h,就會將存放5的位址空間覆蓋為3,這樣鍊錶一切都大亂了。接著逐層返回下去,直到對存放1的位址空間處理。

返回到頭:

4、迭代實現的程式

node*

in_reverselist(node*

h)

5、整體實現的程式:

#include

<

iostream>

using namespace std;

struct node

};/***非遞迴方式***/

node*

reverselist(node*

h) return

newh;

}/***遞迴方式***/

node*

in_reverselist(node*

h)int main()

使用單鏈表反轉的遞迴和非遞迴實現方式

思路為將節點從前到後依次放到表頭,最後最後的節點到了最前面,最前面的節點到了最後面 listnode reverselist listnode head return head 遞迴方式 listnode reverselist2 listnode head 完整的 如下 反轉鍊錶.cpp 定義控制...

java非遞迴實現單鏈表反轉

今天晚上看了it名企演算法與資料結構最優解的關於單鏈表的反轉問題,剛開始自己也理解了一會。後面突然就豁然開朗了。首先,我們申明乙個鍊錶類。鍊錶類 class node 因為在對鍊錶進行反轉的時候,需要更新每乙個node的 next 值,但是,在更新 next 的值前,我們需要儲存 next 的值,否...

單鏈表反轉(遞迴和非遞迴)

單鏈表反轉有遞迴和非遞迴兩種演算法。下面定義節點 cpp view plain copy typedef struct listnodelistnode 在遞迴演算法中的做法是 1找到最後乙個節點和倒數第二個節點,把最後乙個節點設為頭節點的後繼 2反轉這兩個節點 3倒數第三個和第四個節點重複執行步驟...