快慢指標也是面試中的乙個常考知識點,主要是鍊錶的問題中應用較多。
設定兩個指標(fast, slow),初始值都指向頭,slow每次前進一步,fast每次前進二步,如果鍊錶存在環,則fast必定先進入環,而slow後進入環,兩個指標必定相遇。(當然,fast先行頭到尾部為null,則為無環鏈表)程式如下:
01
int
i***itsloop(linklist l)
12
}
13
return
((fast == null) || (fast->next == null));
14
}
當fast若與slow相遇時,slow肯定沒有走遍歷完鍊錶,而fast已經在環內迴圈了n圈(1<=n)。假設slow走了s步,則fast走了2s步(fast步數還等於s 加上在環上多轉的n圈),設環長為r,則:
1
2s = s + nr
2
s= nr
設整個鍊錶長l,入口環與相遇點距離為x,起點到環入口點的距離為a。
1
a + x = nr
2
a + x = (n – 1)r +r = (n-1)r + l - a
3
a = (n-1)r + (l – a – x)
(l – a – x)為相遇點到環入口點的距離,由此可知,從煉表頭到環入口點等於(n-1)迴圈內環+相遇點到環入口點,於是我們從
煉表頭、與相遇點分別設乙個指標,
每次各走一步,兩個指標必定相遇,且相遇第一點為環入口點。程式描述如下:
01
node* findloopport(node *head)
10
}
11
if
((fast == null) || (fast->next == null))
14
slow = head;
15
while
(slow != fast)
19
return
slow;
20
}
圖里,ab=p,bd=c,由於慢指標走了n步,快指標走了2n步,所以慢指標再走n步還是到達d點。
【db=c只是說,慢指標在環內走了c這麼遠,不一定是不到一圈,也可能慢指標在環內走了幾圈之後才到達d點,此時我們假定bd長度是這路徑的總長為c
】所以,得到如下解決辦法:
在快慢指標相遇之後,讓快指標重新指向煉表頭,慢指標還在p+c位置,然後二者同時走p步,每次走一步。走完之後二者相遇的位置就是環入口了。
普通方法:先遍歷一遍單鏈表確定其長度l後,再從頭節點出發迴圈l/2次即可查詢到單鏈表的中間節點。該問題如果採用普通的方法雖然簡單,但是查詢效率太低。
快慢指標: 設定兩個指標*fast、*slow都指向單鏈表的頭節點,其中*fast的移動速度是*slow的2倍,當*fast指向末尾節點的時候,slow正好就在中間了,可以大大提高查詢的效率。
當然,此時演算法 還要考慮鍊錶結點個數的奇偶數因素,當快指標移動x次後到達表尾(1+2x),說明鍊錶有奇數個結點,直接返回慢指標指向的資料即可。如果快指標是倒數第二個結點,說明鍊錶結點個數是偶數,這時 可以 實際情況 返回上中位數或下中位數或(上中位數+下中位數)的一半。
快慢指標在鍊錶中的應用
快慢指標指的是定義兩個指標,這兩個指標的移動速度一快一慢,以此來製造出自己想要的差值,這個差值可以讓 我們找到鍊錶上相應的結點。一般情況下,快指標的移動步長為慢指標的兩倍 利用快慢指標,我們把乙個鍊錶看成乙個跑道,假設a的速度是b的兩倍,那麼當a跑完全程後,b剛好跑一半,以 此來達到找到中間節點的目...
快慢指標在鍊錶的應用
快慢指標中的快慢指的是移動的步長,即每次向前移動速度的快慢。例如可以讓快指標每次沿鍊錶向前移動2,慢指標每次向前移動1次。1 判斷單鏈表是否為迴圈鍊錶 演算法 讓快慢指標從煉表頭開始遍歷,快指標向前移動兩個位置,慢指標向前移動乙個位置 如果快指標到達null,說明鍊錶以null為結尾,不是迴圈鍊錶。...
鍊錶快慢指標
public listnode removenthfromend listnode head,int n 為了找到要刪除的節點的前乙個節點,所以此處讓fast.next null while fast.next null 此時head為倒數第n個節點的前乙個節點。slow.next slow.nex...