一、快慢指针说明
快慢是指移动步数的长短,也就是每次向前移动速度的快慢。如,指定快指针每次沿着链表向前移动2步,指定慢指针每次沿着链表向前移动1步。
二、快慢指针的应用
1、判断单链表是否为循环链表
首先设置快慢指针的起点为链表的头结点,快指针每次向前移动2步,慢指针每次向前移动1步。如果该链表为循环链表,则快指针会在不久之后追上慢指针;如果是单链表,则快指针会先到达链表的末尾。利用快慢指针解决这个问题还有一个好处是不必预先知道链表的长度。逻辑关系简单明了:快指针追上慢指针=>循环链表,快指针到达链尾=>单链表。
1 #include<iostream>
2 using namespace std;
3 /* --- global variable --- */
4 int n;
5 int i;
6
7 /* --- linked list struct --- */
8 struct Node
9 {
10 int data; //node information
11 Node* next = NULL; //next pointer
12 };
13
14 /* --- function prototypes --- */
15 //create Circular/single linked list
16 void CreatSing(Node *&head); //'&' means to change head
17 void CreatCir(Node *&head);
18 //judge the list
19
20 void isCirOrSing(Node *head);
21
22 /* --- main function --- */
23 int main()
24 {
25
26 //define two head
27 Node* headS = new Node();
28 Node* headC = new Node();
29
30 //create and judge single linked list
31 CreatSing(headS);
32 isCirOrSing(headS);
33
34 cout<<endl<<" ---------- Luxuriant line ---------- "<<endl<<endl;
35
36 //create and judge circular linked list
37 CreatCir(headC);
38 isCirOrSing(headC);
39
40
41 return 0;
42 }
43
44 /* ---the key function--- */
45 void isCirOrSing(Node *head)
46 {
47 Node *fast; //fast pointer, 2 steps/time
48 Node *slow; //slow pointer, 1 step/time
49 fast = slow = head; //start at head
50 while(1)
51 {
52 //fast reach NULL => single
53 if(fast->next==NULL||fast->next->next==NULL)
54 {
55 cout<<" single linked list !"<<endl;
56 break;
57 }
58 //fast catch slow => circular
59 else if(fast->next==slow||fast->next->next==slow)
60 {
61 cout<<" circular linked list !"<<endl;
62 break;
63 }
64 else
65 {
66 fast = fast->next->next; //2 steps/time
67 slow = slow->next; //1 step/time
68 }
69 }
70 }
71
72 void CreatSing(Node *&head)
73 {
74 Node* p = new Node();
75 cout<<"input linked list number: ";
76 cin>>n;
77
78 head =p;
79 cout<<"input linked list data list: ";
80 for(i=0;i<n-1;i++)
81 {
82 cin>>p->data; //input data
83 p->next = new Node();
84 p = p->next; //link to next
85 }
86 cin>>p->data;
87
88 //print to check
89 cout<<endl;
90 Node* q;
91 q = head;
92 int x = 10;
93 while(q!=NULL)
94 {
95 cout<<q->data<<"->";
96 q = q->next;
97 x--;
98 }
99 cout<<"[NULL] "; //link NULL to the end
100 q = NULL;
101 }
102
103 void CreatCir(Node *&head)
104 {
105 Node* p = new Node();
106 cout<<"input linked list number: ";
107 cin>>n;
108
109 head =p;
110 cout<<"input linked list data list: ";
111 for(i=0;i<n;i++)
112 {
113 cin>>p->data; //input data
114 if(i==n-1) //link the end to head
115 p->next = head;
116 else
117 {
118 p->next = new Node();
119 p = p->next; //link to next
120 }
121 }
122
123 //print to check
124 cout<<endl;
125 Node* q;
126 q = head;
127 int x = 10; //Output the length of 10 laps
128 while(x!=0)
129 {
130 cout<<q->data<<"->";
131 q = q->next;
132 x--;
133 }
134 cout<<"... ";
135 q = NULL;
136 }
运行输出结果:
2、有序链表中寻找中位数
快指针的移动速度是慢指针的2倍,所以快指针到达链表尾巴时,慢指针到达链表中点。
有两种情况需要分开考虑,即链表为偶数长度时,和链表为计数长度时。(head结点依然存储数据)
链表长度为偶数时,快指针只能到达链表的倒数第二个结点;则慢指针的位置为上中位数;因此返回(上中位数+下中位数)/2。
链表长度为奇数时,快指针就能到达链表的最后一个结点;则慢指针的位置就是中位数;因此直接返回慢指针的值。
例如,链表长度为4时,fast第一次移动后指向倒数第二个结点(data=3),slow第一次移动后指向第二个结点(data=2);
进入判断fast->next->next是否为NULL,判断成立,当前slow位置在第二个结点处(data=2),因此返回(slow->data)+(slow->next->data)/2=2.5,即为所求中位数。
又例如,链表长度为3时, fast第一次移动后指向最后一个结点(data=3),slow第一次移动后指向第二个结点(data=2);
进入判断fast->next是否为NULL,判断成立,当前slow位置在第二个结点处(data=2),因此返回(slow->data)=2,即为所求中位数。
代码实现:
1 #include<iostream>
2 using namespace std;
3 /* --- global variable --- */
4 int n;
5 int i;
6
7 /* --- linked list struct --- */
8 struct Node
9 {
10 int data; //node information
11 Node* next = NULL; //next pointer
12 };
13
14 /* --- function prototypes --- */
15 void CreatSing(Node *&head); //'&' means to change head
16 double findMedian(Node *head);
17
18 /* --- main function --- */
19 int main()
20 {
21 int x=2; //print twice
22 while(x!=0)
23 {
24 x--;
25
26 //define a head
27 Node* head = new Node();
28 //create a single linked list
29 CreatSing(head);
30 //find median
31 double result = findMedian(head);
32 //print the median
33 cout<<" median = "<<result<<endl;
34 cout<<endl<<" ---------- Luxuriant line ---------- "<<endl<<endl;
35 head = NULL;
36 }
37
38 return 0;
39 }
40
41 /* ---the key function--- */
42 double findMedian(Node *head)
43 {
44 Node *fast; //fast pointer, 2 steps/time
45 Node *slow; //slow pointer, 1 step/time
46 fast = slow = head; //start at head
47 while(1)
48 {
49 if(fast->next==NULL) //odd
50 return (slow->data);
51 else if(fast->next->next==NULL) //even
52 return ((slow->data)+(slow->next->data))/2.0;
53 else
54 {
55 fast = fast->next->next; //2 steps/time
56 slow = slow->next; //1 step/time
57 }
58 }
59 }
60
61 void CreatSing(Node *&head)
62 {
63 Node* p = new Node();
64 cout<<"input linked list number: ";
65 cin>>n;
66
67 head = p;
68 cout<<"input linked list data list: ";
69 for(i=0;i<n-1;i++)
70 {
71 cin>>p->data; //input data
72 p->next = new Node();
73 p = p->next; //link to next
74 }
75 cin>>p->data;
76
77 //print to check
78 cout<<endl;
79 Node* q;
80 q = head;
81 int x = 10;
82 while(q!=NULL)
83 {
84 cout<<q->data<<"->";
85 q = q->next;
86 x--;
87 }
88 cout<<"[NULL] "; //link NULL to the end
89 q = NULL;
90 }
运行输出结果: