問題:
乙個鍊錶要麼以null結尾(非迴圈的),要麼以迴圈結尾(迴圈的),請編寫乙個函式,接受鍊錶的頭指標作為引數,確定該鍊錶是迴圈的還是非迴圈的。如果鍊錶是迴圈的,函式返回true,如果是非迴圈的,函式返回false。注意,不能以任何方式修改鍊錶。
解答:
這兩種鍊錶的區別在與它們的末尾。在非迴圈鍊錶中,末尾節點是以null結束的,因此只要遍歷鍊錶,直到找到乙個以null結尾的節點就行;但在非迴圈鍊錶中,僅僅遍歷鍊錶,就會陷入死迴圈中。
所以我們先研究一下末尾節點。對於迴圈鍊錶中末尾節點指向的節點,還有另乙個指標(頭指標)指向它。這意味著有兩個指標指向了同乙個節點,這個節點是唯一乙個有兩個元素指向的節點。根據這一特徵,我們可以遍歷該鍊錶,檢查每個節點,確定是否有兩個節點指向它,如果有,則該鍊錶肯定是迴圈鍊錶,否則,該鍊錶是非迴圈的,則最終會遇到乙個null指標。不幸的是,我們很難檢查指向每乙個元素的節點數。
除了檢查是否有兩個指標指向同一節點之外,我們還可以檢查是否曾經遇到過某個節點。如果發現乙個曾經遇到過的節點,就表明這是乙個迴圈的鍊錶;如果遇到null指標,就表明這是乙個非迴圈鍊錶。現在關鍵是怎樣判斷是否遇到過某個節點呢,最簡單的就是遍歷每個元素時作標記,但題目不允許我們修改該鍊錶。
那麼我們可以利用鍊錶已有的東西,因為我們知道鍊錶的當前節點和鍊錶的頭指標,因此可以將當前節點的next指標與前面所有的節點直接進行比較。如果對於第i個節點,比較它的next指標,看是否指向了1到i-1號節點之中的某乙個。如果出現相等的情況,說明這是乙個迴圈鍊錶。但這個演算法的時間複雜度是o(n2)。
我們有一種使用兩個指標的更好的演算法,交替移動兩個指標,且兩個指標的移動速度不一樣。在非迴圈鍊錶中,較快的指標會先到達末尾;在迴圈鍊錶中,兩個指標會陷入無限迴圈,較快的指標最終會趕上並超過較慢的指標。如果較快的指標最終超過了較慢的指標,說明這是乙個迴圈鍊錶。如果它遇到乙個null指標,說明這是乙個非迴圈鍊錶。
演算法的實現**如下:
#include
struct
listnode ;
void
initlist(listnode** plist)
void
insertlist(listnode* plist,
intdata)
bool
determintermination(listnode *head)
} intmain()
if(determintermination(plisthead) ==
true)
std::cout<<
"1)單向鍊錶是迴圈的"
<
else
std::cout<<
"1)單向鍊錶是非迴圈的"
<
listnode* ptmp = plisthead;
while
(ptmp->m_pnext != null)
ptmp->m_pnext = plisthead->m_pnext;
//連線成迴圈鍊錶
if(determintermination(plisthead) ==
true)
std::cout<<
"2)單向鍊錶是迴圈的"
<
else
std::cout<<
"2)單向鍊錶是非迴圈的"
<
system(
"pause");
return0;
}
複雜度分析:
如果鍊錶是非迴圈的,較快的指標會在檢查了n個節點之後到達鍊錶的末尾,而較慢的指標只遍歷了1/2的節點。因此總共遍歷了3/2的節點,時間複雜度是o(n)。
如果鍊錶是迴圈的,較慢的指標永遠也不會遍歷超過一次。當較慢的指標檢查了n個節點時,較快的指標已經檢查了2n個節點,並超過了較慢的指標。最壞情況下,需要檢查3n個節點,時間複雜度是o(n)。
因此,不論鍊錶是迴圈的還是非迴圈的,這種兩個指標的方法都比乙個指標的方法好很多。
鍊錶演算法四之迴圈鍊錶
前面介紹了單鏈表的一些練習題,本節介紹迴圈鍊錶,顧名思義,肯定得迴圈起來,就是表中的最後乙個結點的指標指向頭結點,使整個鍊錶形成乙個環。根據前面單鏈表中介紹的頭插法和尾插法,稍微思考一下,就知道再迴圈鍊錶中應該選擇用尾插法這種方式來建立迴圈鍊錶,因為尾插法每次都是在鍊錶的末尾插入新的元素。和原來的尾...
演算法之鍊錶回文鍊錶判斷
問題描述 編寫乙個函式,檢查輸入的鍊錶是否是回文的。示例 輸入 1 2 輸出 false 輸入 1 2 2 1 輸出 true 方法一 要求時間複雜度為o n 空間複雜度為o 1 1.獲取中間位置 獲取中間位置,可以通過快慢指標實現 2.從中間位置一次向兩側對比 從中間向兩側對比,需要將左半部分進行...
鍊錶之迴圈鍊錶
單向鍊錶 鍊錶之單向鍊錶 迴圈鍊錶是單向鍊錶的變化形式。單向鍊錶的尾部的指標域是空的,而迴圈鍊錶的尾部指標是指向鍊錶的頭結點的,其結構如圖一所示。圖 一循 環鏈表結 構圖一 迴圈鍊錶結構 圖一迴圈鍊錶 結構從上面結構可以看出,迴圈鍊錶的節點形成了乙個圈。在進行遍歷時,可以從任意節點開始。如果記錄了尾...