--常用链表操作总结--(转)
1. 求单链表中结点的个数
2. 将单链表反转
3. 查找单链表中的倒数第K个结点(k >
0)
4. 查找单链表的中间结点
5. 从尾到头打印单链表
6. 已知两个单链表pHead1
和pHead2 各自有序,把它们合并成一个链表依然有序
7. 判断一个单链表中是否有环
8.
判断两个单链表是否相交
9. 求两个单链表相交的第一个节点
10. 已知一个单链表中存在环,求进入环中的第一个节点
11.
给出一单链表头指针pHead和一节点指针pToBeDeleted,O(1)时间复杂度删除节点pToBeDeleted
1 /**************************************** 2 * File Name: l1.cpp 3 * Author: sky0917 4 * Created Time: 2014年01月11日 21:50:22 5 ****************************************/ 6 #include <map> 7 #include <cmath> 8 #include <queue> 9 #include <stack> 10 #include <cstdio> 11 #include <cstring> 12 #include <algorithm> 13 using namespace std; 14 15 struct Node{ 16 int key; 17 Node *next; 18 Node(){ 19 key = 0; 20 next = NULL; 21 } 22 }; 23 24 // 1. 求单链表中节点的个数 25 int getListLength(Node *head){ 26 27 if (head->next == NULL) 28 return 0; 29 int ListLength = 0; 30 Node *p = head->next; 31 while (p != NULL){ 32 ListLength++; 33 p = p->next; 34 } 35 36 return ListLength; 37 } 38 39 // 2. 将单链表反转 40 void reverseList(Node *head){ 41 42 if (head->next == NULL) 43 return; 44 45 Node *p1, *p2, *p3; 46 47 p2 = head->next; 48 if (p2->next == NULL)//只有一个元素,直接返回 49 return; 50 51 p1 = p2->next; 52 p2->next = NULL; 53 54 while (p1 != NULL){ 55 p3 = p1->next; 56 p1->next = p2; 57 p2 = p1; 58 p1 = p3; 59 } 60 head->next = p2; 61 } 62 63 // 3. 查找单链表中的倒数第K个结点(k > 0) 64 int GetRkthNode(Node *head, int k){ 65 66 Node *pf = head; 67 if (NULL == pf->next) 68 return -1; 69 if (k <= 0) 70 return -1; 71 72 int tot = 0; 73 while (pf->next != NULL){ 74 tot++; 75 pf = pf->next; 76 if (tot == k) break; 77 } 78 if (tot < k) return -1; 79 80 Node *pr = head->next; 81 while (pf->next != NULL){ 82 pf = pf->next; 83 pr = pr->next; 84 } 85 return pr->key; 86 } 87 88 // 4. 查找单链表的中间结点 89 Node* getMidNode(Node *head){ 90 91 Node *pf = head->next; 92 if (pf == NULL) 93 return head; 94 95 if (pf->next == NULL) 96 return pf; 97 98 Node *pr = head->next; 99 while (pf->next != NULL){ 100 pf = pf->next; 101 pr = pr->next; 102 if (pf->next != NULL){ 103 pf = pf->next; 104 } 105 } 106 return pr; 107 } 108 109 // 5. 从尾到头打印单链表 110 void rPrintList(Node *head){ 111 112 stack<Node *> s; 113 Node *p = head; 114 115 if (p->next == NULL) 116 return; 117 118 while (p->next != NULL){ 119 s.push(p->next); 120 p = p->next; 121 } 122 123 while (!s.empty()){ 124 p = s.top(); 125 printf("%d->",p->key); 126 s.pop(); 127 } 128 puts(""); 129 } 130 131 // 5. 从尾到头打印单链表(2) 132 void dfsPrint(Node *p){ 133 134 if (p == NULL) 135 return; 136 137 dfsPrint(p->next); 138 printf("%d->",p->key); 139 140 } 141 void rPrintList2(Node *head){ 142 143 Node *p = head; 144 145 if (p->next == NULL) 146 return; 147 148 dfsPrint(p->next); 149 puts(""); 150 } 151 152 // 6. 已知两个单链表pHead1 和pHead2 各自有序,把它们合并成一个链表依然有序 153 Node *mergeSortedList(Node *head, Node *head2){ 154 155 Node *p1 = head->next; 156 Node *p2 = head2->next; 157 158 if (p1 == NULL) 159 return head2; 160 if (p2 == NULL) 161 return head; 162 163 Node *mHead = NULL; 164 if (p1->key < p2->key){ 165 mHead = head; 166 mHead->next = NULL; 167 } 168 else{ 169 mHead = head2; 170 mHead->next = NULL; 171 } 172 173 Node *pm = mHead; 174 while (p1 != NULL && p2 != NULL){ 175 if (p1->key < p2->key){ 176 pm->next = p1; 177 p1 = p1->next; 178 pm = pm->next; 179 pm->next = NULL; 180 } 181 else{ 182 pm->next = p2; 183 p2 = p2->next; 184 pm = pm->next; 185 pm->next == NULL; 186 } 187 } 188 189 while (p1 != NULL){ 190 pm->next = p1; 191 p1 = p1->next; 192 pm = pm->next; 193 pm->next = NULL; 194 } 195 while (p2 != NULL){ 196 pm->next = p2; 197 p2 = p2->next; 198 pm = pm->next; 199 pm->next = NULL; 200 } 201 return mHead; 202 } 203 204 // 7. 判断一个单链表中是否有环 205 bool hasCircle(Node *head){ 206 207 if (head == NULL) 208 return false; 209 210 Node *pFast = head->next; 211 Node *pSlow = head->next; 212 213 while (pFast != NULL && pFast->next != NULL){ 214 pFast = pFast->next->next; 215 pSlow = pSlow->next; 216 if (pSlow == pFast) 217 return true; 218 } 219 return false; 220 } 221 222 // 8. 判断两个单链表是否相交 223 bool isIntersect(Node *head1, Node *head2){ 224 225 if (head1 == NULL || head2 == NULL) 226 return false; 227 228 Node *p1 = head1; 229 while (p1->next != NULL){ 230 p1 = p1->next; 231 } 232 233 Node *p2 = head2; 234 while (p2->next != NULL){ 235 p2 = p2->next; 236 } 237 238 return p1 == p2; 239 } 240 241 // 9. 求两个单链表相交的第一个节点 242 Node *getFirstCommonNode(Node *head1, Node *head2){ 243 244 if (head1 == NULL || head2 == NULL) 245 return NULL; 246 247 int len1 = 0; 248 Node *p1 = head1; 249 while (p1->next != NULL){ 250 p1 = p1->next; 251 len1++; 252 } 253 254 int len2 = 0; 255 Node *p2 = head2; 256 while (p2->next != NULL){ 257 p2 = p2->next; 258 len2++; 259 } 260 261 if (p1 != p2) 262 return NULL; 263 264 p1 = head1; 265 p2 = head2; 266 267 if (len1 > len2){ 268 int k = len1 - len2; 269 while (k--){ 270 p1 = p1->next; 271 } 272 } 273 else{ 274 int k = len2 - len1; 275 while (k--){ 276 p2 = p2->next; 277 } 278 } 279 while (p1 != p2){ 280 p1 = p1->next; 281 p2 = p2->next; 282 } 283 return p1; 284 } 285 286 // 10. 已知一个单链表中存在环,求进入环中的第一个节点 287 Node *getFirstNodeInCircle(Node *head){ 288 289 if (head == NULL || head->next == NULL) 290 return NULL; 291 292 Node *pFast = head; 293 Node *pSlow = head; 294 while (pFast != NULL && pFast->next != NULL){ 295 pFast = pFast->next->next; 296 pSlow = pSlow->next; 297 if (pFast == pSlow) 298 break; 299 } 300 if (pFast == NULL || pFast->next == NULL) 301 return NULL; 302 303 Node *ptmp = pSlow; 304 Node *ph1 = head->next; 305 Node *ph2 = ptmp->next; 306 307 int len1 = 0; 308 Node *p1 = ph1; 309 while (p1 != ptmp){ 310 p1 = p1->next; 311 len1++; 312 } 313 314 int len2 = 0; 315 Node *p2 = ph2; 316 while (p2 != ptmp){ 317 p2 = p2->next; 318 len2++; 319 } 320 321 p1 = ph1; 322 p2 = ph2; 323 324 if (len1 > len2){ 325 int k = len1 - len2; 326 while (k--){ 327 p1 = p1->next; 328 } 329 } 330 else{ 331 int k = len2 - len1; 332 while (k--){ 333 p2 = p2->next; 334 } 335 } 336 while (p1 != p2){ 337 p1 = p1->next; 338 p2 = p2->next; 339 } 340 return p1; 341 } 342 343 // 11. 给出一单链表头指针pHead和一节点指针pToBeDeleted,O(1)时间复杂度删除节点pToBeDeleted 344 void deleteNode(Node *head, Node *pd){ 345 346 if (head == NULL || pd == NULL) 347 return; 348 349 if (pd->next != NULL){ 350 pd->key = pd->next->key; 351 Node *ptmp = pd->next; 352 pd->next = pd->next->next; 353 delete ptmp; 354 } 355 else{ 356 Node *p = head; 357 while (p->next != pd){ 358 p = p->next; 359 } 360 p->next = NULL; 361 delete pd; 362 } 363 } 364 365 int main(){ 366 367 void init(Node *head); 368 void print(Node *head); 369 Node *head = new Node(); 370 371 init(head); 372 print(head); 373 374 /* 375 * @求单链表中节点的个数 376 */ 377 int len = getListLength(head); 378 printf("len = %d\n",len); 379 380 /* 381 * @将单链表反转 382 */ 383 reverseList(head); 384 print(head); 385 386 /* 387 * @将单链表反转 388 */ 389 reverseList(head); 390 print(head); 391 392 /* 393 *@ 返回链表的倒数第 k 个元素的值 394 * 用两个指针,让第一个指针先走k个元素,然后第二个指针和第一个指针一起走, 395 * 但第一个指针走到尾部的时候,第二个就走到了倒数第k个元素的位置 396 */ 397 int kth = GetRkthNode(head, 5); 398 printf("kth = %d\n",kth); 399 400 /* 401 * @查找单链表的中间结点 402 * 设置两个指针,两个指针同时向前走,前面的指针每次走两步,后面的指针每次走一步, 403 * 前面的指针走到最后一个结点时,后面的指针所指结点就是中间结点,即第(n/2+1)个 404 * 结点 405 * 时间复杂度 O(n) 406 */ 407 Node *midNode = getMidNode(head); 408 printf("midNode.val = %d\n",midNode->key); 409 410 /* 411 * @从尾到头打印单链表 412 * 两种方式:一个是自己模拟栈,另一种是调用系统栈 413 * 时间复杂度 O(n) 414 */ 415 rPrintList(head); 416 rPrintList2(head); 417 418 /* 419 *@已知两个单链表pHead1 和pHead2 各自有序,把它们合并成一个链表依然有序 420 * 类似归并排序。 421 * 注意两个链表都为空,和其中一个为空时的情况。 422 * O(1)的空间,时间复杂度为O(max(len1, len2))。 423 */ 424 Node *head2 = new Node(); 425 init(head2); 426 Node *mhead = mergeSortedList(head, head2); 427 print(mhead); 428 429 /* 430 * @判断一个单链表中是否有环 431 * 用两个指针,一个指针一次走两步,一个指针一次走一步,如果有环,两个指针肯定会在环中相遇。 432 * 时间复杂度为O(n) 433 */ 434 // mhead->next->next->next = mhead->next; 435 if (hasCircle(mhead)) 436 printf("有环\n"); 437 else printf("无环\n"); 438 439 /* 440 * @判断两个单链表是否相交鱼某一点 441 * 如果两个链表相交鱼某一点,那么在这个相交节点之后的所有节点都是两个链表所共有的。 442 * 所以如果相交那么最后一个节点一定是共有的。 443 * 可以先遍历第一个链表记住最后一个节点,然后遍历第二个链表,到最后一个节点时和第一 444 * 个链表的最后一个节点比较,如果相同,则相交,否则不相交。 445 * 时间复杂度O(len1+len2) 空间复杂度为O(1) 446 */ 447 448 if (isIntersect(head, mhead)) 449 printf("相交\n"); 450 else printf("不相交\n"); 451 452 /* 453 * @求两个单链表相交的第一个节点 454 * 先遍历第一个单链表,计算其长度len1, 同时保存最后一个节点的地址 455 * 再遍历第二个单链表,计算其长度len2, 同时查看最后一个节点是否和第一个链表的最后 456 * 一个节点相同,如果不相同,说明不想交,直接返回。 457 * 再次从头遍历两个链表,如果len1 > len2,那么第一个链表先遍历Len1-len2个节点,这个 458 * 时候两个链表当前节点距离第一个相交节点的距离相同,只要一起遍历,直到两个节点的 459 * 地址相同即可。 460 * 时间复杂度O(len1+len2) 461 */ 462 Node *pt = getFirstCommonNode(head, mhead); 463 if (pt != NULL) 464 printf("FirstCommonNode‘s value is %d\n",pt->key); 465 else printf("No intersect\n"); 466 467 /* 468 * @已知一个单链表有环,求进入环中的第一个节点 469 * 首先判断是否存在环,如果没有环直接返回。 470 * 在环中的一个节点处断开(函数结束之后需要恢复原来的链表结构) 471 * 然后就转化成了求两个单链表第一个相交节点的问题。 472 * 473 */ 474 //mhead->next->next->next->next->next = mhead->next->next->next; 475 Node *pF = getFirstNodeInCircle(mhead); 476 if (pF != NULL) 477 printf("The first Node in circle‘s value = %d\n",pF->key); 478 else printf("No circle\n"); 479 480 /* 481 * @给出一个单链表头指针head,和一个节点指针pToBeDeleted 482 * 要求用O(1)的时间爱你复杂度删除节点pToBeDeleted 483 * 可以把要删除的节点的下一个节点的数据复制到该节点,然后删除 484 * 下一个节点即可。 485 * 注意最后后一个节点的情况。这个时候只能用普通的方法来找到前一个节点。 486 */ 487 488 Node *pd = mhead->next->next->next; 489 deleteNode(mhead, pd); 490 print(mhead); 491 return 0; 492 } 493 494 void init(Node *head){ 495 Node *p = head; 496 497 for (int i=0; i<5; i++){ 498 p->next = new Node(); 499 p->next->key = i+1; 500 p = p->next; 501 } 502 } 503 504 void print(Node *head){ 505 if (head->next == NULL) 506 return; 507 Node *p = head->next; 508 while (p != NULL){ 509 printf("%d --> ",p->key); 510 p = p->next; 511 } 512 513 puts(""); 514 }