問題
如何檢測一個單鏈表中是否有環,例以下圖的例子。html
解決思路1:快慢指針法
這是最多見的方法。思路就是有兩個指針P1和P2,同時從頭結點開始往下遍歷鏈表中的全部節點。java
P1是慢指針,一次遍歷一個節點。
P2是快指針,一次遍歷兩個節點。node
若是鏈表中沒有環,P2和P1會前後遍歷完全部的節點。git
若是鏈表中有環,P2和P1則會前後進入環中,一直循環,並必定會在在某一次遍歷中相遇。github
所以,只要發現P2和P1相遇了,就能夠斷定鏈表中存在環。面試
實現代碼
public class LinkADT<T> {數據結構
/**
* 單鏈表節點
*
* @author wangtao
* @param <T>
*/
private static class SingleNode<T> {
public SingleNode<T> next;
public T data;oop
public SingleNode(T data) {
this.data = data;
}this
public T getNextNodeData() {
return next != null ? next.data : null;
}
}.net
/**
* 判斷是否有環 快慢指針法
*
* @param node
* @return
*/
public static boolean hasLoopV1(SingleNode headNode) {
if(headNode == null) {
return false;
}
SingleNode p = headNode;
SingleNode q = headNode.next;
// 快指針未能遍歷完全部節點
while (q != null && q.next != null) {
p = p.next; // 遍歷一個節點
q = q.next.next; // 遍歷兩個個節點
// 已到鏈表末尾
if (q == null) {
return false;
} else if (p == q) {
// 快慢指針相遇,存在環
return true;
}
}
return false;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
解決思路2:足跡法
順序遍歷鏈表中全部的節點,並將全部遍歷過的節點信息保存下來。若是某個節點的信息出現了兩次,則存在環。
實現代碼
public class LinkADT<T> {
/**
* 單鏈表節點
*
* @author wangtao
* @param <T>
*/
private static class SingleNode<T> {
public SingleNode<T> next;
public T data;
public SingleNode(T data) {
this.data = data;
}
public T getNextNodeData() {
return next != null ? next.data : null;
}
}
// 保存足跡信息
private static HashMap<SingleNode, Integer> nodeMap = new HashMap<>();
/**
* 判斷是否有環 足跡法
*
* @param node
* @return
*/
public static boolean hasLoopV2(SingleNode node, int index) {
if (node == null || node.next == null) {
return false;
}
if (nodeMap.containsKey(node)) {
return true;
} else {
nodeMap.put(node, index);
return hasLoopV2(node.next, ++index);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
總結
分別從時間複雜度與內存複雜度比較兩種方法。快慢指針法的時間複雜度更高,內存複雜度更低。除此以外,足跡法額外引入了其它的數據結構:散列表。
從面試的角度看,快慢指針法更符合面試的意圖。而從實際工做的角度看,快慢指針法更難理解,代碼也很差寫,我更推薦用足跡法。
完整代碼請參考:
https://github.com/wanf425/Algorithm/blob/master/src/com/wt/adt/LinkADT.java
博文地址https://www.taowong.com/blog/2018/10/07/data-strutctures-and-algorithm-02.html--------------------- 做者:Tao的博客 來源:CSDN 原文:https://blog.csdn.net/wanf425/article/details/83048761