一 單鏈表 帶環單鏈表的詳細講解

2021-08-22 02:18:30 字數 3046 閱讀 4784

今天看了一篇關於帶環單鏈表精講的文章,在這裡給大家做乙個總結。之前看過很多有關單鏈表帶環的文章,但是有些文章講的太文章化,不容易理解,理論性太強。接下來我會用最簡單通俗易懂的語言解析這個問題。

當你拿到乙個單鏈表的資料資訊時,我相信大部分的人都會選擇去判斷一下這個單鏈表是否有環?這也是最基本的反應。下面我給出單鏈表的資料結構:

typedef int elemtype;

//頭節點中的data域存放是鍊錶的長度

typedef struct listnode

listnode,*plistnode;

鍊錶的具體操作這裡就不詳細列出了,在我的前幾篇部落格中都有詳細的**。一:那麼我們接下來分析,如何判斷乙個鍊錶是否有環呢?我們採用假設的方法,我們先假設該鍊錶就是乙個帶環的單鏈表,那麼我們來分析:

有的同學會想到說,既然這個鍊錶是帶環的,那麼從頭開始遍歷鍊錶,直至找到某兩個節點的位址一樣,或者遍歷到null。這是腦子直的人的想法也是最最簡單易懂的方法 。

在單鏈表的很多處理的過程中我們都會採用一種很有效的處理方式:輔助指標(快慢指標),就像古人說的三個臭皮匠頂過乙個諸葛亮。我們讓快指標每次走兩個單位,慢指標每次走乙個單位,我們可以發現,當fast != null&&fast->next !=null,時只要fast = slow那麼這個鍊錶就是帶環的,反之不滿足上述條件,就是不帶環的鍊錶。

//函式名:isloop

//函式功能:判斷是不是帶環的鍊錶

//函式引數:鍊錶的頭節點指標

bool isloop(plistnode plist)//plist 為頭結點

}//存在兩種情況,①pf或者pf->m_pnext為空②pf=ql

//然後下面的**就是對這兩種情況的解釋

if(pf == null || pf->m_pnext == null)

else

}

我相信大部分的同學,在判斷完成後,肯定心裡竊竊歡喜,便把這道題目拋擲腦後了。當時對於初學者的作者來說也是這樣,但是後來作者又想了幾個值得思考的問題

二:既然我們確定這是個帶環的鍊錶那麼這個鍊錶的入口點在**呢?怎樣確定這個入口點呢?

做法1:思想

當可以破壞鍊錶結構的時間,我們可以從快慢指標相交的位置將其減斷,這樣就形成了交叉鍊錶。然後呢我們先求出兩個鍊錶的長度求出來,len1  len2然後用長的減去短的得到差值len然後此時快慢指標同時只走一步,且長的那個鍊錶從len開始走,慢的從頭開始走然後相互比較,相等的就是入口點。

做法2:

當初我查閱了很多資料,一直以為這是乙個很深奧的數學公式推導問題,並且很多資料也就是朝這方面解釋的。但是我問了自己的c++老師他給出了最簡單易懂的演算法:

首先我們來看最簡單的一種情況:

首先我們可以很確定的一件事:那就是fast和slow走的步數一樣,但是由於fast一次走兩步,所以fast走過的長度是slow的兩倍。

同時我們模擬出最簡單的情況:我們假設不在環的直線部分是很短的(因為這裡有乙個臨界值)那樣的話fast只在環中走了一圈,藍色就是slow所走的路徑,綠色就是fast所走的路徑,同時呢在下面那張圖中紅色部分就是fast比slow多走 的那部分。

同時呢由於len fast = 2 * len slow,所以呢紅色部分和slow的藍色路徑一樣,

同時呢我們發現他們有共同的部分,去掉共同部分。我們得到乙個很重要的資訊:

從起點到入口點   和   相遇點到入口點  的長度一樣,這就是我們的演算法。

還有一種普通的情況那就是,當直線部分很長,超過了那個臨界點。此時fast比slow在環內多走了n圈,但是上面的理論對於這種普通的情況仍然使用,只不過是fast在環內走了很多圈。

**實現;

//環的入口點

//函式名:findetrance

//函式功能:找到環的入口點並且返回該節點的指標

plistnode findetrance(plistnode plist)

} //分為兩種情況

if(fast == null && fast->m_pnext == null)

//是環的前提下,此時快指標已經追上慢指標

slow = plist;//從此時開始快慢各走一步下次相遇即是環的入口點

while(slow != fast)

return slow;

}

三:既然我們現在也知道了環的入口點,那麼還有什麼可以探尋的呢?

我們想要知道環的長度:

演算法分析:當fast和slow第一次在相遇點相遇時,此後他們人生的道路只能在那個環裡度過了,同時我們還可以得到乙個結論

那就是,相對慢指標來說,他從相遇點,到下一次相遇時剛好慢指標走了環的長度,

這就是解決此問題的演算法:

**如下:

//計算環的長度,第一次相遇開始計數,第二次停止計數

//函式名:length

//函式功能:計算鍊錶環的長度

//函式返回值:環的長度

int length(plistnode plist)

if(fast == slow && again == false)

//第一次到第二次相遇,通過慢指標來計數

if(begin == true)

}return length;

}

到現在,我整理的單鏈表的內容已經基本完整了。

如果有什麼錯誤或者意見希望大家多多提出。

單鏈表帶環問題

判斷單鏈表是否帶環?若帶環,求環的長度?求環的入口點?1 2 3 4 5 6 7 8 9 不帶環 鍊錶遍歷一次,到最後的節點的下乙個節點會指向null,此時鍊錶不帶環。帶環 在判斷鍊錶是否帶環之前,應該先判斷鍊錶是否為空。空鍊錶肯定不帶環。只要鍊錶帶環,對鍊錶進行遍歷就會形成死迴圈,沒有出口。這是就...

有關單鏈表帶環的問題

1.檢查鍊錶是否帶環,若帶求長度,環入口點。設定兩個快慢指標開始時指向起始位置,開始出發,如果這兩個指標相交,那麼存在環 從交點出發,當再次回到此點便可統計環長度 對與於環入口點,假設快指標每次走兩個位置,慢一直走乙個,如圖所示 則只需乙個從起始點,乙個從交點移動,必會相交。2.檢查兩煉表否相交 鍊...

面試題 單鏈表帶環問題

關於單鏈表帶環問題 1 怎樣判斷乙個單鏈表是否帶環 2 如果帶環,環的長度怎麼計算 3 如果帶環,怎麼求環的入口 1 怎樣判斷乙個單鏈表是否帶環 我們知道,單鏈表如果帶環,那麼從煉表頭開始遍歷就會進入死迴圈。其實我們可以用上篇部落格中提到的兩個指標移動的思想來求解,在這裡可以讓兩個指標移動速度不同,...