ʕ·͡ˑ·ཻ ʕ•̫͡• ʔ•̫͡•ཻʕ•̫͡•ʔ•͓͡•ʔ

  快慢指针中的快慢指的是移动的步长,即每次向前移动速度的快慢,在使用快慢指针时可以让快指针每次沿链表向前移动2,慢指针每次向前一次。

 快慢指针的应用

  (一)寻找链表中心

​ 原理:快指针的移动速度是慢指针移动速度的两倍,因此当快指针到达表尾时慢指针到达中点,但要分奇偶情况讨论。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
while(fast && slow){

​ if(fast->next == NULL){

​ return slow->data;

}

​ else if(fast->next != NULL&&fast->next->next == NULL){

​ return (slow->data + slow->next->data)/2;

}

​ else {

​ fast = fast->next->next;

​ slow = slow->next;

}

}

  (二)判断单链表中是否存在环

原理:类似于在操场上跑步,快指针的速度是慢指针移动速度的两倍,让两个指针都从链表头开始遍历,如果快指针最后指向空,则说明并没有环;如果最终快慢指针相等,则说明快指针追了上慢指针存在环。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
bool JudgeCircle(LNode *head){

​ if(head==NULL) return false;

​ LNode *slow = head;

​ LNode *fast = head;

​ while(fast != NULL && fast->next->next != NULL){

​ slow = slow->next;

​ fast = fast->next->next;

​ if(slow == fast) return true;

}

​ return false;

}

  (三)判断两个单链表是否相交

原理:首先利用快慢指针判断链表是否存在环。

(1)如果都不存在环,则如果两个单向链表有公共节点,也就是两个链表从某一节点开始,他们的p->next都指向同一个节点,每个节点只有一个p->next。因此从第一个公共节点开始,之后它们所有节点都是重合的。因此,首先两个链表各遍历一次,求出两个链表的长度L1、L2,然后可以得到它们的长度差L。然后现在长的链表上遍历L个节点,之后再同步遍历,于是在遍历中,第一个相同的节点就是第一个公共的节点。此时,若两个链表长度分别为M,N,则时间复杂度为O(M+N).

(2)如果一个存在环,另外一个不存在环,则这两个链表是不可能相交的。

(3)如果利用快慢指针发现两个链表都存在环,则判断任意一个链表上快慢指针相遇的那个节点,在不在另外一个链表上,如果在,则相交,不在,则不相交。

第一种情况实现代码:

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
void Intersect(LinkList L1, LinkList L2) {
if (L1 == NULL || L2 == NULL) {
exit();
}
LinkList p = L1;
LinkList q = L2;
int length1 = 0;
int length2 = 0;
int len = 0;

while (p->next) {
length1 ++;
p = p->next;
}
while (q->next) {
length2 ++;
q = q->next;
}

cout<<p<<q;

cout<<length1<<length2;

if (p == q) {
cout<<"相交";
if (length1 > length2) {
len = length1 - length2;
p = L2;
q = L1;
}
else {
len = length2 - length1;
p = L1;
q = L2;
}

while (len) {
q = q->next;
len--;
}
while (p != q) {
p = p->next;
q = q->next;
}
cout<<p->data;

}

else {
cout<<"不相交";
}

}

 总结

上边的题是我在写LeetCode的时候发现挺有意思的就做了个汇总(当然还有一些其他的题目我想了好久,后边有时间再写),类似的题目还有寻找环的入口以及输出链表中倒数第K个节点。原理其实都差不多所以这两个题我就没有写上来。(参考来源于csdn,博客园,百度百科)