由于最近太忙,几个链表的题目都写在了一个解决方案里了,代码可能有点乱,以下先提交代码,思路都在注释里,后期有时间了再整理笔记
1 // printListFromTailToHead.cpp: 定义控制台应用程序的入口点。
2 //
3
4 #include "stdafx.h"
5 #include<iostream>
6 #include<vector>
7 #include<queue>
8 #include<set>
9 #include<stack>
10 #include<malloc.h>
11 #include<map>
12 #include<debugapi.h>
13 using namespace std;
14
15 #define N 40
16 struct ListNode {
17 int val;
18 struct ListNode *next;
19
20 };
21 struct RandomListNode {//复杂链表
22 int label;
23 struct RandomListNode *next, *random;
24 RandomListNode(int x) :
25 label(x), next(NULL), random(NULL) {
26 }
27 };
28 class Solution {
29 public:
30 vector<int> printListFromTailToHead(ListNode *head) {//将链表逆序打印
31 /*思路
32 通常,这种情况下,我们不希望修改原链表的结构。返回一个反序的链表,这就是经典的“后进先出”,我们可以使用栈实现
33 这种顺序。每经过一个结点的时候,把该结点放到一个栈中。
34 当遍历完整个链表后,再从栈顶开始逐个输出结点的值,给一个新的链表结构,这样链表就实现了反转。*/
35 stack<int> nodes;
36 ListNode *node = head;
37 vector<int> result;
38 while (node != NULL) {
39 nodes.push(node->val);
40 node = node->next;
41 }
42 while (!nodes.empty()) {
43 result.push_back(nodes.top());
44 nodes.pop();
45 }
46 return result;
47 }
48 ListNode* CreateListNode(int num, int nodes[]) {//创建链表
49 ListNode *p, *q;
50 ListNode *listnode;
51 listnode = (ListNode *)malloc(sizeof(ListNode));//分配空间,也可以用c++的new
52 listnode->next = NULL;
53 p = listnode;
54 for (int i = 0; i<num; i++) {
55 q = (ListNode *)malloc(sizeof(ListNode));
56 q->val = nodes[i];
57 p->next = q;
58 p = q;
59 }
60 p->next = NULL;
61 return listnode;
62 }
63 ListNode* CreateListNodeWithHead(int num, int nodes[]) {//创建链表
64 ListNode *p, *q;
65 ListNode *listnode;
66 listnode = (ListNode *)malloc(sizeof(ListNode));//分配空间,也可以用c++的new
67 //listnode->next = NULL;
68 p = listnode;
69 for (int i = 0; i<num; i++) {
70 q = (ListNode *)malloc(sizeof(ListNode));
71 q->val = nodes[i];
72 p->next = q;
73 p = q;
74 }
75 listnode = listnode->next;//这里将头结点指向下一个结点,是为了使头结点数值有意义,注意与上一个创建方法的代码的两处区别
76 p->next = NULL;
77 return listnode;
78 }
79 void PrintListNode(ListNode *listnode) {//遍历输出链表
80 ListNode *p = listnode->next;//因为创建的链表头结点数值为空,所以要从头结点下一个结点开始打印
81 //cout <<"test"<< listnode->val<<"test";
82 while (p!= NULL) {
83 cout << p->val;
84 p = p->next;
85 }
86 cout << endl;
87 }
88 void PrintReverseListNode(ListNode *listnode) {//遍历输出逆置后的链表,因为逆置之后的头结点数值非空,所以要从头结点开始打印
89 ListNode *p = listnode;
90 //cout << "test" << listnode->val << "test";
91 while (p->next!= NULL) {//在逆置的时候,逆置后的链表的尾结点是原链表的头结点,所以输出的时候不要把尾结点输出
92 cout << p->val;
93 p = p->next;
94 }
95 cout << endl;
96 }
97 ListNode* FindKthToTail(ListNode *plistnode,int k) {//找到链表中倒数第k个元素
98 /*思路
99 我们可以定义两个指针。第一个指针从链表的头指针开始遍历向前走k-1,第二个指针保持不动;从第k步开始,
100 第二个指针也开始从链表的头指针开始遍历。由于两个指针的距离保持在k-1,
101 当第一个(走在前面的)指针到达链表的尾结点时,第二个指针(走在后面的)指针正好是倒数第k个结点。*/
102 if (plistnode == NULL || k ==0) {
103 return NULL;
104 }
105 ListNode *palistnode;
106 ListNode *pblistnode;
107 palistnode = plistnode;
108 pblistnode = plistnode;
109 for (int i = 0; i < k-1; i++) {
110 if(palistnode->next != NULL) {
111 palistnode = palistnode->next;
112 }
113 else {
114 return NULL;
115 }
116 }
117 while (palistnode->next != NULL) {
118 palistnode = palistnode->next;
119 pblistnode = pblistnode->next;
120 }
121 return pblistnode;
122 }
123 ListNode* ReverseList(ListNode *head) {//将链表逆置
124 /*思路
125 这个很简单,我们使用三个指针,分别指向当前遍历到的结点、它的前一个结点以及后一个结点。
126 在遍历的时候,做当前结点的尾结点和前一个结点的替换。
127 */
128 ListNode *Cur, *Nex, *Pre;
129 if (head == NULL)
130 return NULL;
131 if (head->next == NULL)
132 return head;
133 Cur = head;
134 Nex = NULL;
135 Pre = NULL;
136 while (Cur != NULL) {
137 Nex = Cur->next;
138 Cur->next = Pre;
139 Pre = Cur;
140 Cur = Nex;
141 }
142 return Pre;
143 }
144 ListNode* Merge(ListNode *listnode1, ListNode *listnode2) {//合并两个有序链表,还可以使用递归算法合并两个有序链表
145
146 if (listnode1== NULL)
147 return listnode2;
148 if (listnode2 == NULL)
149 return listnode1;
150 ListNode *p = listnode1->next;//因为这两个链表创建的时候头结点数值为空,所以要从头结点下一个结点开始遍历
151 ListNode *q = listnode2->next;
152 ListNode *result;
153 ListNode *t;
154 result = (ListNode *)malloc(sizeof(ListNode));
155 result->next = NULL;
156 ListNode *temp = result;
157 while (p != NULL&&q != NULL) {
158 if (p->val < q->val) {
159 t= (ListNode *)malloc(sizeof(ListNode));
160 t->val = p->val;
161 temp->next = t;
162 temp = t;
163 p = p->next;
164 }
165 else {
166 t = (ListNode *)malloc(sizeof(ListNode));
167 t->val = q->val;
168 temp->next = t;
169 temp = t;
170 q = q->next;
171 }
172 }
173 while (p != NULL) {
174 t = (ListNode *)malloc(sizeof(ListNode));
175 t->val = p->val;
176 temp->next = t;
177 temp = t;
178 p = p->next;
179 }
180 while (q != NULL) {
181 t = (ListNode *)malloc(sizeof(ListNode));
182 t->val = q->val;
183 temp->next = t;
184 temp = t;
185 q = q->next;
186 }
187 temp->next = NULL;
188 return result;
189 }
190 ListNode* MergeWithRecursion(ListNode *listnode1, ListNode *listnode2) {//递归合并两个有序链表
191 if (listnode1 == NULL)
192 return listnode2;
193 if (listnode2 == NULL)
194 return listnode1;
195 ListNode *listnode =NULL;
196 if (listnode1->val < listnode2->val) {
197 listnode = listnode1;
198 listnode->next = MergeWithRecursion(listnode1->next, listnode2);
199 }
200 else {
201 listnode = listnode2;
202 listnode->next = MergeWithRecursion(listnode1, listnode2->next);
203 }
204 return listnode;
205 }
206 RandomListNode* CloneWithMap(RandomListNode *pHead) {//复制复杂的链表:节点可以有两个指向,一个指向下一节点,一个指向随机节点
207 /*
208 方法一思路:首先复制原链表普通指针域,一次遍历即可,复制过程中将新旧链表中的节点一一对应,将其映射关系放入到
209 map<RandomListNode *, RandomListNode *> nodeMap中,然后复制随机指针域,先找到随机指针指向的随机节点,由于map中对应的有该随机节点对应的
210 新节点,所以也就找到了随机指针指向的结点对应的新节点,该新节点即为新链表前结点对应的随机指针指向的结点,然后新节点随机指针指向该节点,时间复杂度:O(N)
211 */
212 if (pHead = NULL) {
213 return NULL;
214 }
215 map<RandomListNode *, RandomListNode *> nodeMap;
216 RandomListNode *currNode = pHead;
217 RandomListNode *newHead = NULL, *preNode = NULL, *newNode = NULL;
218 //首先复制原链表的普通指针域,一次遍历即可完成
219 while (currNode != NULL) {
220 newNode = new RandomListNode(currNode->label);
221 nodeMap[currNode] = newNode;
222 if (preNode == NULL) {
223 newHead = newNode;
224 }
225 else
226 {
227 preNode->next = newNode;
228 }
229 preNode = newNode;
230 }
231 // 接着复制随机指针域, 需要两次遍历
232 currNode = pHead;
233 newNode = newHead;
234 while (currNode != NULL&&newNode != NULL) {
235 RandomListNode *randNode = currNode->random;
236 RandomListNode *newRandNode = nodeMap[randNode];
237 newNode->random = newRandNode;//这里找到原链表对应的随机指针指向的结点后,再从map中找到对应的新节点,然后将新链表随机指针指向该新节点
238 currNode = currNode->next;
239 newNode = newNode->next;
240 }
241 return newHead;
242 }
243 RandomListNode* CloneTogether(RandomListNode *pHead) {
244 /*
245 我们需要的就只是能够建立新节点与原节点之前的对应关系就可以了, 链表中的顺序非随机访问方式,能够很简单的通过接单的nex指针t域查找下一个节点
246 ,那么我们将新节点直接插入到原结点的后面,这样可以很方便的通过原来节点找到新节点,
247 1.遍历一遍原始链表,复制结点N对应的N’,将其插入到结点N的后面
248 2.确定每个随机指针的指向,只需遍历一遍链表即可确定每个结点的随机指针的指向
249 次遍历一遍,将原始链表和复制链表分开,奇数为原始链表,偶数为复制链表
250 */
251 if (pHead = NULL) {
252 return NULL;
253 }
254 RandomListNode *currNode = pHead;
255 RandomListNode *newHead = NULL, *preNode = NULL, *newNode = NULL;
256 while (currNode != NULL) {
257 if ((newNode = new RandomListNode(currNode->label)) == NULL) {
258 perror("new error:");
259 exit(-1);
260 }
261 // 将新的节点newNode连接在currNode的后面
262 newNode->next = currNode->next;
263 currNode->next = newNode;
264 // 指向指向下一个节点
265 currNode = newNode->next;
266 }
267 // 接着复制随机指针域,原来节点的下一个位置就是其对应的新节点
268 currNode = pHead;
269 newNode = currNode->next;
270 while (currNode != NULL) {
271 RandomListNode *randNode = currNode->random;// 随机指针域randNode
272 RandomListNode *newNode = currNode->next;
273 if (randNode != NULL) {
274 newNode->random = randNode->next;//新节点的随机指针指向的节点即为旧节点的随机指针指向的节点指向的下一个节点
275 }
276 else
277 {
278 newNode->random = NULL;
279 }
280 currNode = newNode->next;// 链表同步移动
281 }
282 // 将链接在一起的新旧两个链表拆分开,脱链,更新各链表的next指针
283 currNode = pHead;
284 newNode = newHead = pHead->next;
285 while (currNode != NULL) {
286 currNode->next = newNode->next;
287 if (newNode->next != NULL) {
288 newNode->next = newNode->next->next;
289 }
290 else {
291 newNode->next = NULL;
292 }
293 currNode = currNode->next;
294 newNode = newNode->next;
295 }
296 return newHead;
297 }
298 void printReverse() {//用于用户交互来转置链表
299 int num;
300 //ListNode *listnode;//要创建的链表
301 int listnodes[N];
302 cout << "请输入链表大小:" << endl;
303 cin >> num;
304 cout << "请依次输入链表每个节点数值:" << endl;
305 for (int i = 0; i<num; i++) {
306 cin >> listnodes[i];
307 }
308 Solution solution;
309 ListNode *listnode = solution.CreateListNode(num, listnodes);
310 solution.PrintListNode(listnode);
311 ListNode *result = solution.ReverseList(listnode);
312 solution.PrintReverseListNode(result);
313 }
314 void printMerge() {//用于用户交互有序链表合并过程
315 Solution solution;
316 int num1, num2;
317 ListNode *listnode1, *listnode2;
318 int listnodes1[N], listnodes2[N];
319 ListNode *result2;
320 cout << "请输入第一个链表大小:" << endl;
321 cin >> num1;
322 cout << "请按照数值递增顺序依次输入第一个链表每个节点数值:" << endl;
323 for (int i = 0; i<num1; i++) {
324 cin >> listnodes1[i];
325 }
326 //Solution solution;
327 listnode1 = solution.CreateListNode(num1, listnodes1);
328 solution.PrintListNode(listnode1);
329 cout << "请输入第二个链表大小:" << endl;
330 cin >> num2;
331 cout << "请按照数值递增顺序依次输入第二个链表每个节点数值:" << endl;
332 for (int i = 0; i<num2; i++) {
333 cin >> listnodes2[i];
334 }
335 listnode2 = solution.CreateListNode(num2, listnodes2);
336 solution.PrintListNode(listnode2);
337 cout << "合并两个有序链表" << endl;
338 //如果使用递归调用的话要把链表移到头结点的额下一个结点,不然会把头结点的空值也合并进去了
339 listnode1 = listnode1->next;
340 listnode2 = listnode2->next;
341 result2 = solution.MergeWithRecursion(listnode1, listnode2);
342 solution.PrintReverseListNode(result2);
343 }
344 void printprintListFromTailToHead() {//用户交互从尾到头打印链表过程
345 int num;
346 //ListNode *listnode;//要创建的链表
347 int listnodes[N];
348 cout << "请输入链表大小:" << endl;
349 cin >> num;
350 cout << "请依次输入链表每个节点数值:" << endl;
351 for (int i = 0; i<num; i++) {
352 cin >> listnodes[i];
353 }
354 Solution solution;
355 ListNode *listnode = solution.CreateListNode(num, listnodes);
356 solution.PrintListNode(listnode);
357 vector<int> result;
358 result = solution.printListFromTailToHead(listnode);
359 cout << endl << "逆序输出该链表" << endl;
360 for (int i = 0; i < num; i++) {
361 cout << result[i];
362 }
363 cout << endl;
364 }
365 void printFindKthToTail() {//用户交互打印倒数第K个值
366 int num;
367 //ListNode *listnode;//要创建的链表
368 int listnodes[N];
369 cout << "请输入链表大小:" << endl;
370 cin >> num;
371 cout << "请依次输入链表每个节点数值:" << endl;
372 for (int i = 0; i<num; i++) {
373 cin >> listnodes[i];
374 }
375 Solution solution;
376 ListNode *listnode = solution.CreateListNode(num, listnodes);
377 solution.PrintListNode(listnode);
378 int k;
379 cout << "请输入K值" << endl;
380 cin >> k;
381 ListNode *result = solution.FindKthToTail(listnode, k);
382 cout << result->val;
383 }
384 };
385 int main() {
386 /*int num;
387 //ListNode *listnode;//要创建的链表
388 int listnodes[N];
389 cout << "请输入链表大小:" << endl;
390 cin >> num;
391 cout << "请依次输入链表每个节点数值:" << endl;
392 for (int i = 0; i<num; i++) {
393 cin >> listnodes[i];
394 }
395 Solution solution;
396 ListNode *listnode=solution.CreateListNode(num, listnodes);
397 solution.PrintListNode(listnode);*/
398 Solution solution;
399 solution.printReverse();
400 }