【说明】:
本文是左程云老师所著的《程序员面试代码指南》第二章中“两个单链表相交的一系列问题”这一题目的C++复现。
本文只包含问题描述、C++代码的实现以及简单的思路,不包含解析说明,具体的问题解析请参考原书。
感谢左程云老师的支持。
【题目】:
在本题中,单链表可能有环也可能无环。给定两个单链表的头节点 head1 和 head2,这两个单链表可能相交也可能不相交。请实现一个函数,如果两个链表相交,请返回相交的第一个节点;如果不相交,返回 NULL。
【思路】:
将本问题拆分成3个子问题:
1、判断一个链表是否有环
2、判断两个无环链表相交的问题
3、判断两个有环链表相交的问题
4、一个有环一个无环则肯定不相交
【编译环境】:
CentOS6.7(x86_64)
gcc 4.4.7
【实现】:
实现及测试代码:
1 /* 2 *文件名:list_intersect.cpp 3 *作者: 4 *摘要:链表相交的一系列问题 5 */ 6 7 #include <iostream> 8 #include<stdlib.h> 9 10 using namespace std; 11 12 class Node 13 { 14 public: 15 Node(int data) 16 { 17 value = data; 18 next = NULL; 19 } 20 public: 21 int value; 22 Node *next; 23 }; 24 25 //找到入环节点 26 Node* getLoopNode(Node *head) 27 { 28 if(NULL == head || NULL == head->next || NULL == head->next->next) 29 return NULL; 30 Node *n1 = head->next; 31 Node *n2 = head->next->next; 32 while(n1 != n2) 33 { 34 if(NULL == n2->next || NULL == n2->next->next) 35 return NULL; 36 n2 = n2->next->next; 37 n1 = n1->next; 38 } 39 n2 = head; 40 while(n1 != n2) 41 { 42 n1 = n1->next; 43 n2 = n2->next; 44 } 45 return n1; 46 } 47 48 //不带环的链表的相交节点 49 Node* noLoop(Node *head1,Node *head2) 50 { 51 if(NULL == head1 || NULL == head2) 52 return NULL; 53 Node *cur1 = head1; 54 Node *cur2 = head2; 55 int n = 0; 56 57 while(NULL != cur1->next) 58 { 59 n++; 60 cur1 = cur1->next; 61 } 62 while(NULL != cur2->next) 63 { 64 n--; 65 cur2 = cur2->next; 66 } 67 68 if(cur1 != cur2) //若最后一个节点不想等,则俩链表不相交 69 return NULL; 70 71 cur1 = n > 0 ? head1 : head2; 72 cur2 = cur1 == head1 ? head2 : head1; 73 n = abs(n); 74 while(0 != n) //以较短的那个链表为准 75 { 76 n--; 77 cur1 = cur1->next; 78 } 79 while(cur1 != cur2) 80 { 81 cur1 = cur1->next; 82 cur2 = cur2->next; 83 } 84 return cur1; 85 } 86 87 //带环链表的相交节点的判断 88 Node* bothLoop(Node *head1,Node *loop1,Node *head2,Node *loop2) 89 { 90 Node *cur1(NULL),*cur2(NULL); 91 92 if(loop1 == loop2) //与不带环的相交节点的判断一样的 93 { 94 cur1 = head1; 95 cur2 = head2; 96 int n = 0; 97 while(cur1 != loop1) 98 { 99 n++; 100 cur1 = cur1->next; 101 } 102 103 while(cur2 != loop2) 104 { 105 n--; 106 cur2 = cur2->next; 107 } 108 cur1 = n > 0 ? head1 : head2; 109 cur2 = cur1 == head1 ? head2 : head1; 110 n = abs(n); 111 while(0 != n) 112 { 113 n--; 114 cur1 = cur1->next; 115 } 116 while(cur1 != cur2) 117 { 118 cur1 = cur1->next; 119 cur2 = cur2->next; 120 } 121 return cur1; 122 } 123 else 124 { 125 cur1 = loop1->next; 126 while(cur1 != loop1) 127 { 128 if(cur1 == loop2) 129 return loop2; 130 cur1 = cur1->next; 131 } 132 return NULL; 133 } 134 } 135 136 Node* getIntersectNode(Node *head1,Node *head2) 137 { 138 if(NULL == head1 || NULL == head2) 139 return NULL; 140 Node *loop1 = getLoopNode(head1); 141 Node *loop2 = getLoopNode(head2); 142 if(NULL == loop1 && NULL == loop2) 143 return noLoop(head1,head2); 144 if(NULL != loop1 && NULL != loop2) 145 return bothLoop(head1,loop1,head2,loop2); 146 return NULL; 147 } 148 149 150 int main() 151 { 152 Node *head1 = NULL; 153 Node *head2 = NULL; 154 Node *ptr1 = NULL; 155 Node *ptr2 = NULL; 156 Node *head3 = NULL; 157 Node *ptr3 = NULL; 158 for(int i =0;i<4;i++)//构造链表 159 { 160 if(NULL == head1 || NULL == head2) 161 { 162 head1 = new Node(i); 163 head1->next = NULL; 164 ptr1 = head1; 165 head2 = new Node(i); 166 head2->next = NULL; 167 ptr2 = head2; 168 head3 = new Node(10-i); 169 head3->next = NULL; 170 ptr3 = head3; 171 continue; 172 } 173 ptr1->next = new Node(i); 174 ptr1 = ptr1->next; 175 ptr1->next = NULL; 176 ptr2->next = new Node(i); 177 ptr2 = ptr2->next; 178 ptr2->next = NULL; 179 ptr3->next = new Node(10-i); 180 ptr3 = ptr3->next; 181 ptr3->next = NULL; 182 } 183 //第一:无环不相交 184 if(NULL == getIntersectNode(head1,head2)) 185 cout << "Two lists are not intersecting!" << endl; 186 //第二:有环不相交 187 ptr1->next = head1->next; 188 ptr2->next = head2->next; 189 if(NULL == getIntersectNode(head1,head2)) 190 cout << "Two lists are not intersecting!" << endl; 191 //第三:无环相交 192 ptr1->next = head3; 193 ptr2->next = head3; 194 if(NULL != getIntersectNode(head1,head2)) 195 cout << "Two lists are intersecting!" << getIntersectNode(head1,head2)->value << endl; 196 //第四有环相交 197 ptr3->next = head3; 198 if(NULL != getIntersectNode(head1,head2)) 199 cout << "Two lists are intersecting!" << getIntersectNode(head1,head2)->value << endl; 200 return 0; 201 }
注:
转载请注明出处;
转载请注明源思路来自于左程云老师的《程序员代码面试指南》。