鏈表:是不基於物理連接的列表,是靠前對象引用後邊對象組成一串對象。(如下)
鏈表中出現了環,就是我們中的最後一個引用又指回了鏈中的一個對象。(如下)
我們就是想判斷出鏈表中是否有環,不判斷的話,我們就可能在取鏈中數據時進入死循環。
該如何判斷這個列表中是否有環,只要我們判斷在這個鏈子是否有相同的指向。也就是兩個對象的next指的對象一樣。
先寫個對象
public class NodeVo {
NodeVo next;
public NodeVo getNext() {
return next;
}
public void setNext(NodeVo next) {
this.next = next;
}
}
用兩個指針,在鏈表上循環。每循環一次,一個指針走兩格,一個走一格。如果有環的話最終兩個對象會相同。就好像,我們在操場跑步一樣,只要我們在繞着環行跑道跑,跑的快的一定會追上跑的慢的。這樣我們減少了,一個對象循環對比整個鏈上對象的尷尬。
首先:我們必須知道如果鏈表中出現null,說明一定沒有環。所有判斷有環的代碼如下
public boolean glp(NodeVo nodeVo) {
NodeVo fast = nodeVo, low = nodeVo;
while (fast.getNext() != null && low.getNext().getNext() != null){
fast=fast.getNext();
low=low.getNext().getNext();
if(fast==low)
break;
}
if(fast==null||low==null)
return false;
return true;
}
那如何找環的入口呢?(進入函數課程---啦啦啦!!!開心不?)
設low的路程爲 S,
fast的路程則爲 2S,
環的長度爲 R,
鏈表開始到環口 A,
環口到遇到的長度爲 X,
那麼 S=A+X,
2S=S+nR, (n fast可能已經在環中轉了幾圈,low才進圈)
A+X=(n-1)R+L-A;
A=(n-1)R+L-X-A;
所以,假設我們的n=1,首節點到入口點的長度等於相交點到入口點的距離。所以,我們找兩個對象分別從首節點和相交點開始走,每次走一格。相遇的就是相交點。
public NodeVo getNode(NodeVo nodeVo1, NodeVo nodeVo2) {
while (nodeVo1 != nodeVo2) {
nodeVo1 = nodeVo1.getNext();
nodeVo2 = nodeVo2.getNext();
}
return nodeVo1;
}