鍊錶是程式設計中最常見的資料結構,當我們遍歷鍊錶時如果鍊錶中存在閉環(如下圖),會造成無限迴圈的情況。為了解決這個問題我們需要在遍歷之前對鍊錶做環檢測。
我們設定兩個指標如下圖
然後快指標每次移動兩個節點,慢指標每次移動乙個節點,就像兩個人在操場上跑,乙個跑得快乙個跑得慢,那麼如果一直跑下去兩人總會相遇。當兩個指標相遇就代表鍊錶存在閉環。此時的**實現應該是這樣的:
linkednode
*checkcycle()
}return
nullptr
;}
這個時候我們已經可以確定鍊錶是否有閉環,那麼在進一步我們還可以找到閉環的入口。就是上圖6的節點。
如下圖所示,設煉表中環外部分的長度為 l。指標進入環後,又走了 e的距離與 fast 相遇。此時,fast 指標已經走完了環的 n 圈,環長c。由於我們設定快指標是慢指標的2倍速度。因此有:r+e=n*c,演算過程如下:
由以上結果可知:如果此時第三個指標以和慢指標一樣的速度從煉表頭開始出發,它和慢指標一定會在c點相遇,那麼可以得知它們的第一次相遇點就是環入口。進一步完善上面的**:
linkednode
*checkcycle()
std::cout <<
"環入口值: "
<< fast-
>value << std::endl;
return fast;}}
return
nullptr
;}
/*
list的單向鍊錶實現
*/template
<
class
t>
class
linkednode
linkednode()
};template
<
class
t>
class
linkedlist
// 尾插法
bool
add(linkednode
*node)
temp-
>next = node;
return
true;}
bool
add(t t)
intsize()
linkednode
*temp;
temp =
this
->head;
int size =0;
while
(temp !=
nullptr
)return size;
} linkednode
*checkloop()
std::cout <<
"環入口值: "
<< fast-
>value << std::endl;
return fast;}}
return
nullptr;}
// 遍歷操作
void
foreach
(void
(*fun)
(t item,
int index)
)const
}// 對映操作
template
<
typename v>
linkedlist
map(v(
*fun)
(t item,
int index)
)return newlist;}}
;
鍊錶快慢指標
public listnode removenthfromend listnode head,int n 為了找到要刪除的節點的前乙個節點,所以此處讓fast.next null while fast.next null 此時head為倒數第n個節點的前乙個節點。slow.next slow.nex...
快慢指標判斷鍊錶是否有環
關於鍊錶是否有環,其實是一系列問題,主要包括以下幾個 使用快慢指標fast和slow,fast每次走兩步,slow每次走一步,如果有環,肯定會相遇,如果沒有,則指標fast遇到null退出。追及相遇問題。在環上相遇後,記錄第一次相遇點為pos,之後指標slow繼續每次走1步,fast每次走2步。在下...
鍊錶演算法 檢測環
給定乙個單鏈表,判斷其中是否有環,已經是乙個比較老同時也是比較經典的問題,在網上蒐集了一些資料,然後總結一下大概可以涉及到的問題,以及相應的解法。首先,關於單鏈表中的環,一般涉及到一下問題 1.給乙個單鏈表,判斷其中是否有環的存在 2.如果存在環,找出環的入口點 3.如果存在環,求出環上節點的個數 ...