1 // 链表节点
2 struct ListNode
3 {
4 int value;
5 ListNode* next;
6 };
7
8 // 求单链表中结点的个数 注意链表判断是否为空 时间复杂度O(n)
9 size_t GetListLength(ListNode* head)
10 {
11 if(!head)
12 {
13 return 0;
14 }
15
16 size_t length = 0;
17 ListNode* current = head;
18
19 while (current != NULL)
20 {
21 ++length;
22 current = current->next;
23 }
24
25 return length;
26 }
27
28 // 反转单链表 时间复杂度O(n)
29 ListNode* ReverseList(ListNode* head)
30 {
31 // 如果链表为空或只有一个结点,无需反转,直接返回原链表头指针
32 if(head == NULL && head->next == NULL)
33 {
34 return NULL;
35 }
36
37 ListNode* new_head = NULL; // 链表反转后新链表的头结点
38 ListNode* current = head;
39
40 while (current != NULL)
41 {
42 ListNode* tmp = current; // 保存当前结点
43 current = current->next;
44 tmp->next = new_head; // 插入到新的头结点之前
45 new_head = tmp;
46 }
47
48 return new_head;
49 }
50
51 // 查找单链表中倒数第K个数(k>0)
52 /*主要思路就是使用两个指针,先让前面的指针走到正向第k个结点,这样前后两个指针的距离差是k-1,
53 之后前后两个指针一起向前走,前面的指针走到最后一个结点时,后面指针所指结点就是倒数第k个结点。*/
54 ListNode* GetReverseKthNode(ListNode* head, size_t k)
55 {
56 if(k == 0 || head == NULL)
57 {
58 return NULL;
59 }
60
61 ListNode* ahead = head;
62 ListNode* back = head;
63
64
65 while (k > 1 && ahead != NULL) // 前面的指针先走到正向第k个结点
66 {
67 ahead = ahead->next;
68 --k;
69 }
70
71 if(k > 1 || ahead == NULL) //结点数目小于k 返回NULL
72 {
73 return NULL;
74 }
75
76 while(ahead->next != NULL) // 前后两个指针一起向前走,直到前面的指针指向最后一个结点
77 {
78 back = back->next;
79 ahead = ahead->next;
80 }
81
82 return back; // 后面的指针所指结点就是倒数第k个结点
83 }
84
85 //查找单链表的中间结点 若链表长度为n(n>0),则返回第n/2+1个结点
86 //设置两个指针,只不过这里是,两个指针同时向前走,前面的指针每次走两步,
87 //后面的指针每次走一步,前面的指针走到最后一个结点时,后面的指针所指结点就是中间结点,即第(n/2+1)个结点。
88 //注意链表为空,链表结点个数为1和2的情况。时间复杂度O(n)。
89 ListNode* GetMiddleNode(ListNode* head)
90 {
91 if(head == NULL || head->next == NULL) // 链表为空或只有一个结点,返回头指针
92 {
93 return NULL;
94 }
95
96 ListNode* ahead = NULL;
97 ListNode* back = NULL;
98
99 while(ahead->next != NULL) // 前面指针每次走两步,直到指向最后一个结点,后面指针每次走一步
100 {
101 ahead = ahead->next;
102 back = back->next;
103 if(ahead->next != NULL)
104 {
105 ahead = ahead->next;
106 }
107 }
108
109 return back;
110 }
111
112 // 从尾到头打印单链表
113 // 对于这种颠倒顺序的问题,我们应该就会想到栈,后进先出。
114 void ReversePrintList(ListNode* head)
115 {
116 std::stack<ListNode*> stack;
117 ListNode* node = head;
118
119 while(node != NULL)
120 {
121 stack.push(node);
122 node = node->next;
123 }
124
125 while(!stack.empty())
126 {
127 node = stack.top();
128 cout << node->value;
129 stack.pop();
130 }
131 }
132
133 // 从尾到头打印单链表递归版本
134 void ReversePrintList_recursion(ListNode* node)
135 {
136 if(node == NULL)
137 {
138 return;
139 }
140 else
141 {
142 ReversePrintList_recursion(node->next);
143 cout << node->value;
144 }
145 }
146
147 // 两个单链表Head1和Head2 各自有序,把它们合并成一个链表依然有序
148 // 注意两个链表都为空,和其中一个为空时的情况
149 ListNode* MergeSortedList(ListNode* head_1, ListNode* head_2)
150 {
151 if(head_1 == NULL)
152 {
153 return head_2;
154 }
155 if(head_2 == NULL)
156 {
157 return head_1;
158 }
159
160 ListNode* new_head = NULL; // 合并后新链表的头结点
161
162 /* 先让new_head指向head1和head2值小的那个 */
163 if(head_1->value <= head_2->value)
164 {
165 new_head = head_1;
166 head_1 = head_1->next;
167 new_head->next = NULL;
168 }
169 else
170 {
171 new_head = head_2;
172 head_2 = head_2->next;
173 new_head->next = NULL;
174 }
175
176 /* 依次比较head1中head2中的值,哪个小就插入到新链表中 */
177 ListNode* tmp = new_head;
178 while(head_1 != NULL && head_2 != NULL)
179 {
180 if(head_1->value <= head_2->value)
181 {
182 tmp->next = head_1;
183 head_1 = head_1->next;
184 tmp = tmp->next;
185 tmp->next = NULL;
186 }
187 else
188 {
189 tmp->next = head_2;
190 head_2 = head_2->next;
191 tmp = tmp->next;
192 tmp->next = NULL;
193 }
194 }
195
196 /* head1与head2中长的链表剩余的部分插入到新链表中 */
197 if(head_1 != NULL)
198 {
199 tmp->next = head_1;
200 }
201 else if(head_2 != NULL)
202 {
203 tmp->next = head_2;
204 }
205
206 return new_head;
207 }
208
209 // 判断链表是否有环
210 // 如果一个链表中有环,也就是说用一个指针去遍历,是永远走不到头的。
211 // 因此,我们可以用两个指针去遍历,一个指针一次走两步,一个指针一次走一步,如果有环,两个指针肯定会在环中相遇。
212 // 时间复杂度为O(n)
213 bool hasCircle(ListNode* head)
214 {
215 ListNode* fast = head;
216 ListNode* slow = head;
217
218 while(fast != NULL && fast->next != NULL)
219 {
220 fast = fast->next->next;
221 slow = slow->next;
222
223 if(fast == slow)
224 {
225 return true;
226 }
227 }
228
229 return false;
230 }