链表相关算法小结(判断环、复制、逆序等)

单向链表

[cpp] 
view plain
 copy

  1. struct ListNode {// 单向链表  
  2.     int val;  
  3.     struct ListNode *next;  
  4.     ListNode(int x) : val(x), next(NULL) {}  
  5. };  

从尾到头打印链表

[cpp] 
view plain
 copy

  1. vector<int> TravelListFromTailToHead(struct ListNode* head) {// 【从尾到头打印链表】  
  2.     vector<int> result;  
  3.     if(NULL == head)  
  4.         return result;  
  5.     ListNode *p = head;  
  6.     stack<ListNode*> nodeStack;  
  7.     while(p != NULL) {  
  8.         nodeStack.push(p);  
  9.         p = p->next;  
  10.     }  
  11.     while(!nodeStack.empty()) {  
  12.         p = nodeStack.top();  
  13.         result.push_back(p->val);  
  14.         nodeStack.pop();  
  15.     }  
  16.     return result;  
  17. }  

链表中倒数第 k 个结点

[cpp] 
view plain
 copy

  1. ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {// 【链表中倒数第 k 个结点】  
  2.     if(NULL == pListHead || 0 == k) return NULL;  
  3.     ListNode *p1 = pListHead, *p2 = pListHead;// 使用快慢指针  
  4.     while(p2->next && k– > 1) {// k– > 1 一定要放在后面  
  5.         p2 = p2->next;  
  6.     }  
  7.     if(k > 1) return NULL;// 说明 k 值比节点数还大  
  8.     while(p2->next) {  
  9.         p2 = p2->next;  
  10.         p1 = p1->next;  
  11.     }  
  12.     return p1;  
  13. }  

反转链表

[cpp] 
view plain
 copy

  1. ListNode* ReverseList(ListNode* pHead) {// 【反转链表】  
  2.     if(NULL == pHead) return NULL;  
  3.     ListNode *p = pHead, *pNext = pHead->next, *pPre = NULL;// 需要定义三个指针  
  4.     while(pNext) {  
  5.         p->next = pPre;  
  6.         pPre = p;  
  7.         p = pNext;  
  8.         pNext = pNext->next;  
  9.     }  
  10.     p->next = pPre;  
  11.     return p;  
  12. }  

合并两个排序的链表

[cpp] 
view plain
 copy

  1. ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {// 【合并两个排序的链表】  
  2.     if(NULL == pHead1) return pHead2;  
  3.     if(NULL == pHead2) return pHead1;  
  4.     ListNode *pHead = NULL, *p;// pHead:保存新链表表头;p:用于新链表遍历生成  
  5.     if(pHead1->val <= pHead2->val) {  
  6.         pHead = pHead1;  
  7.         pHead1 = pHead1->next;  
  8.     } else {  
  9.         pHead = pHead2;  
  10.         pHead2 = pHead2->next;  
  11.     }  
  12.     p = pHead;  
  13.     while(pHead1 && pHead2) {  
  14.         if(pHead1->val <= pHead2->val) {  
  15.             p->next = pHead1;  
  16.             pHead1 = pHead1->next;  
  17.         } else {  
  18.             p->next = pHead2;  
  19.             pHead2 = pHead2->next;  
  20.         }  
  21.         p = p->next;  
  22.     }  
  23.     while(pHead1) {  
  24.         p->next = pHead1;  
  25.         p = p->next;  
  26.         pHead1 = pHead1->next;  
  27.     }  
  28.     while(pHead2) {  
  29.         p->next = pHead2;  
  30.         p = p->next;  
  31.         pHead2 = pHead2->next;  
  32.     }  
  33.     return pHead;  
  34. }  

两个链表的第一个公共结点

[cpp] 
view plain
 copy

  1. ListNode* FindFirstCommonNode( ListNode *pHead1, ListNode *pHead2) {// 【两个链表的第一个公共结点】  
  2.     ListNode *p = pHead1, *q = pHead2;  
  3.     // 先计算两个链表的长度  
  4.     unsigned int nLength1 = 0, nLength2 = 0;  
  5.     while(p != NULL && q != NULL) {  
  6.         nLength1++;  
  7.         nLength2++;  
  8.         p = p->next;  
  9.         q = q->next;  
  10.     }  
  11.     while(p != NULL) {  
  12.         nLength1++;  
  13.         p = p->next;  
  14.     }  
  15.     while(q != NULL) {  
  16.         nLength2++;  
  17.         q = q->next;  
  18.     }  
  19.     // 根据两链表的长度差,长的链表先走这个差值的步数  
  20.     int n = abs(nLength1 – nLength2);  
  21.     p = pHead1;  
  22.     q = pHead2;  
  23.     if(nLength1 < nLength2) {  
  24.         p = pHead2;  
  25.         q = pHead1;  
  26.     }  
  27.     while(n–)  
  28.         p = p->next;  
  29.     // 对齐后,一起走,直到遇到第一个公共节点  
  30.     while(p != NULL && q != NULL && p != q) {  
  31.         p = p->next;  
  32.         q = q->next;  
  33.     }  
  34.     return p;  
  35. }  

链表中环的入口结点

[cpp] 
view plain
 copy

  1. ListNode* getMeetNode(ListNode* pHead) {// 用快慢指针,必然相会于环内某个节点,返回这个节点,否则返回 NULL  
  2.     if(NULL == pHead) return NULL;  
  3.     ListNode* pSlow = pHead->next;  
  4.     if(NULL == pSlow) return NULL;  
  5.     ListNode* pFast = pSlow->next;  
  6.     while(pSlow != NULL && pFast != NULL) {  
  7.         if(pFast == pSlow)  
  8.             return pFast;  
  9.         pFast = pFast->next;  
  10.         pSlow = pSlow->next;  
  11.         if(pFast != pSlow)  
  12.             pFast = pFast->next;  
  13.     }  
  14.     return NULL;  
  15. }  
  16. ListNode* EntryNodeOfLoop(ListNode* pHead) {// 【链表中环的入口结点】  
  17.     ListNode* meetNode = getMeetNode(pHead);// 用快慢指针得到环内某个节点  
  18.     if(NULL == meetNode)  
  19.         return NULL;  
  20.     int n = 1;  
  21.     // 用这个环内节点计算得到环内节点数  
  22.     ListNode* p = meetNode->next;  
  23.     while(p != meetNode) {  
  24.         p = p->next;  
  25.         ++n;  
  26.     }  
  27.     // 用两个指针,一个指针先走环内节点个数的步数,另一个节点在链表头  
  28.     // 当两个节点相遇时,此时的节点即是环的入口节点  
  29.     p = pHead;  
  30.     while(n–)  
  31.         p = p->next;  
  32.     ListNode* p1 = pHead;  
  33.     while(p1 != p) {  
  34.         p = p->next;  
  35.         p1 = p1->next;  
  36.     }  
  37.     return p;  
  38. }  

判断链表是否是回文结构

[cpp] 
view plain
 copy

  1. bool IsPalindrome(ListNode* pHead) {// 【判断链表是否是回文结构】  
  2.     // 使用快慢指针,找到链表的中间  
  3.     ListNode* pFast = pHead;  
  4.     ListNode* pSlow = pHead;  
  5.     while(pFast != NULL && pSlow != NULL) {  
  6.         pFast = pFast->next;  
  7.         pSlow = pSlow->next;  
  8.         if(pFast != NULL)  
  9.             pFast = pFast->next;  
  10.     }  
  11.   
  12.     pSlow = ReverseList(pSlow);// 从中间节点开始将链表反转(链表被改变,即现场改变)  
  13.   
  14.     // 从两头开始往中间遍历,判断是否是回文结构  
  15.     bool flag = true;  
  16.     ListNode *p1 = pHead, *p2 = pSlow;  
  17.     while(p2 != NULL) {  
  18.         if(p1->val != p2->val) {  
  19.             flag = false;  
  20.         }  
  21.         p1 = p1->next;  
  22.         p2 = p2->next;  
  23.     }  
  24.   
  25.     ReverseList(pSlow);// 将链表恢复(恢复现场)  
  26.   
  27.     return flag;  
  28. }  

删除链表中的重复结点

删除链表中相邻的重复结点(保留一个)

[cpp] 
view plain
 copy

  1. void DeleteDuplication(ListNode* &pHead) {// 【删除链表中相邻的重复结点(保留一个)】  
  2.     if(NULL == pHead) return;  
  3.     ListNode *p1 = pHead, *p2 = p1->next;  
  4.     while(p2 != NULL) {  
  5.         if(p2->val == p1->val) {  
  6.             while(p2 != NULL && p2->val == p1->val) {  
  7.                 ListNode* p = p2;  
  8.                 p2 = p2->next;  
  9.                 delete p;  
  10.                 p = NULL;  
  11.             }  
  12.             p1->next = p2;  
  13.         }  
  14.         if(NULL != p2)  
  15.             p2 = p2->next;  
  16.         p1 = p1->next;  
  17.     }  
  18. }  

删除链表中重复结点(保留一个)

[cpp] 
view plain
 copy

  1. void DeleteDuplication2(ListNode* &pHead) {// 【删除链表中重复结点(保留一个)】  
  2.     if(NULL == pHead) return;  
  3.     set<int> s;  
  4.     s.insert(pHead->val);  
  5.     ListNode* p = pHead, *pNode = pHead->next;  
  6.     while(pNode != NULL) {  
  7.         if(s.find(pNode->val) == s.end()) {  
  8.             s.insert(pNode->val);  
  9.             p->next = pNode;  
  10.             p = p->next;  
  11.             pNode = pNode->next;  
  12.         } else {  
  13.             ListNode* q = pNode;  
  14.             pNode = q->next;  
  15.             delete q;  
  16.             q = NULL;  
  17.             p->next = NULL;  
  18.         }  
  19.     }  
  20. }  

删除链表中相邻重复结点

[cpp] 
view plain
 copy

  1. void DeleteDuplication3(ListNode* &pHead) {// 【删除链表中相邻重复结点】  
  2.     if(NULL == pHead) return;  
  3.     ListNode *pPre = NULL, *pNode = pHead;  
  4.     while(pNode != NULL) {  
  5.         ListNode* pNext = pNode->next;  
  6.         if(pNext != NULL && pNext->val == pNode->val) {  
  7.             const int val = pNode->val;  
  8.             ListNode* p = pNode;  
  9.             while(p != NULL && val == p->val) {  
  10.                 pNext = p->next;  
  11.                 delete p;  
  12.                 p = pNext;  
  13.             }  
  14.             if(NULL == pPre)  
  15.                 pHead = pNext;  
  16.             else  
  17.                 pPre->next = pNext;  
  18.             pNode = pNext;  
  19.         } else {  
  20.             pPre = pNode;  
  21.             pNode = pNode->next;  
  22.         }  
  23.     }  
  24. }  

复杂链表

[cpp] 
view plain
 copy

  1. struct RandomListNode {// 复杂链表  
  2.     int val;  
  3.     struct RandomListNode *next, *random;  
  4.     RandomListNode(int x) : val(x), next(NULL), random(NULL) {}  
  5. };  

复杂链表的复制

[cpp] 
view plain
 copy

  1. RandomListNode* Clone(RandomListNode* pHead) {// 【复杂链表的复制】  
  2.     if(NULL == pHead) return NULL;  
  3.     RandomListNode *p = pHead;  
  4.     while(p != NULL) {  
  5.         RandomListNode *pNode = new RandomListNode(p->val);  
  6.         pNode->next = p->next;  
  7.         p->next = pNode;  
  8.         p = pNode->next;  
  9.     }  
  10.   
  11.     p = pHead;  
  12.     RandomListNode *pClone;  
  13.     while(p != NULL) {  
  14.         pClone = p->next;  
  15.         if(p->random != NULL)  
  16.             pClone->random = p->random->next;  
  17.         p = pClone->next;  
  18.     }  
  19.   
  20.     p = pHead;  
  21.     RandomListNode *pCloneHead = pHead->next;  
  22. //    pClone = pHead->next;  
  23. //    p = pClone->next;  
  24. //    while(p != NULL) {  
  25. //        pClone->next = p->next;  
  26. //        pClone = pClone->next;  
  27. //        p->next = pClone->next;  
  28. //        p = p->next;  
  29. //    }  
  30.     RandomListNode *tmp;  
  31.     while(p->next) {  
  32.         tmp = p->next;  
  33.         p->next = tmp->next;  
  34.         p = tmp;  
  35.     }  
  36.   
  37.     return pCloneHead;  
  38. }  
点赞