思路:
1.首先要实现对单链表是否有环的判断,以及取得第一个入环节点。
步骤为,设定一个块指针,每次走两步,设定一个慢指针,每次走一步。
如果无环,则快指针能够很块遍历完链表,直接退出返回NULL
如果有环,则他们会在某个时刻相遇,此时让快指针指向头指针,并且,快指针和慢指针每次只走一步。最后相遇的位置即为第一个入环节点。
2.其次是判断,两个链表是否相交,分以下几种情况:
1)两者都不相交,直接NULL
2)两者都无环,但是相交,则只要对两个链表都遍历以下长度,然后长的链表先遍历完多出的那部分,然后两个链表再一起走,最后会有一个时刻相遇。
3)两者都有环, 则分别算出两个链表各自的第一个入环节点,则分别有以下三种情况:
a)图(3)左,所示,两者交叉,且第一个入环节点相等。则直接取出入环节点以上的部分,按照2)的计算方式计算
b)图(3)中,所示,两者直接在第一个入环节点交叉。同理 用 2)的计算方式计算
3)图(3)右,所示,两者交叉,但是第一个入环节点不相等。则从其中一个入环节点进行遍历即可,返回其中弄一个入环节点都算是第一个相交节点。
4)一个有环,一个无环,则两者不相交
代码:
#include<iostream>
#include<cstdlib>
using namespace std;
struct Node{
int val;
Node * next;
Node(int val){
this->val = val;
this->next = NULL;
}
};
void init(Node *& point1,Node *& point2){
// //两者都无环,但是有交叉
// point1 = new Node(6);
// Node * head1 = point1;
// head1->next = new Node(4); head1=head1->next;
// head1->next = new Node(2); head1=head1->next;
// head1->next = new Node(3); head1=head1->next;
// head1->next = new Node(1); head1=head1->next;
// head1->next = new Node(5); head1=head1->next;
//
// point2 = new Node(7); //6->4 ->2 ->3 ->1 ->5
// Node * head2 = point2; // 7->8->9-^
// head2->next = new Node(8); head2=head2->next;
// head2->next = new Node(9); head2=head2->next;
// head2->next = point1->next->next->next->next;
// //
// //两者都有环,且第一个入环节点相等
// point1 = new Node(6);
// Node * head1 = point1; // 6->4 ->2 ->3 ->1 ->5->4
// head1->next = new Node(4); head1=head1->next;
// head1->next = new Node(2); head1=head1->next;
// head1->next = new Node(3); head1=head1->next;
// head1->next = new Node(1); head1=head1->next;
// head1->next = new Node(5); head1=head1->next;
// head1->next = point1->next;
//
// point2 = new Node(7); // 7->8 ->9 ->4 ->2 ->3 ->1 ->5->4
// Node * head2 = point2;
// head2->next = new Node(8); head2=head2->next;
// head2->next = new Node(9); head2=head2->next;
// head2->next = point1->next;
// //
//两者都有环,且第一个入环节点不相等
point1 = new Node(6);
Node * head1 = point1; // 6->4 ->2 ->3 ->1 ->5->4
head1->next = new Node(4); head1=head1->next;
head1->next = new Node(2); head1=head1->next;
head1->next = new Node(3); head1=head1->next;
head1->next = new Node(1); head1=head1->next;
head1->next = new Node(5); head1=head1->next;
head1->next = point1->next;
point2 = new Node(7); // 7->8 ->9 ->2 ->3 ->1 ->5->4
Node * head2 = point2;
head2->next = new Node(8); head2=head2->next;
head2->next = new Node(9); head2=head2->next;
head2->next = point1->next->next;
//
}
//若有环,返回第一个入环节点
//若无环,则NULL
Node * checkloop(Node * p){
if (p== NULL||p->next ==NULL||p->next->next==NULL) return NULL;
Node* one_step = p->next;
Node* two_step = one_step->next;
while(one_step !=two_step){
if(two_step->next==NULL ||two_step->next->next==NULL ) return NULL;
two_step = two_step->next->next;
one_step = one_step->next;
}
two_step = p;
while(one_step !=two_step){
two_step = two_step->next;
one_step= one_step->next;
}
return one_step;
}
Node * no_loop(Node * p1,Node * p2){
int p1_len = 0;
Node * head1 = p1;
while(p1){
p1_len ++;
p1 = p1->next;
}
int p2_len = 0;
Node * head2 = p2;
while(p2){
p2_len ++;
p2 = p2->next;
}
if (p1!=p2) return NULL;
Node * cur1 = NULL;
Node * cur2 = NULL;
cur1 = p1_len>p2_len ?head1:head2;
cur2 = p1_len>p2_len ?head2:head1;
int num = abs(p1_len-p2_len);
while(num){
cur1= cur1->next;
num--;
}
while(cur1!=cur2){
cur1= cur1->next;
cur2= cur2->next;
}
return cur1;
}
Node * both_loop(Node * p1,Node * in1,Node * p2,Node * in2){
//有环,且第一个入环点相等
if (in1==in2){
//代码 类似 no_loop 区别是,这里指出了末端点
int p1_len = 0;
Node * head1 = p1;
while(p1!=in1){
p1_len ++;
p1 = p1->next;
}
int p2_len = 0;
Node * head2 = p2;
while(p2!=in2){
p2_len ++;
p2 = p2->next;
}
if (p1!=p2) return NULL;
Node * cur1 =NULL;
Node * cur2 =NULL;
cur1 = p1_len>p2_len ?head1:head2;
cur2 = p1_len>p2_len ?head2:head1;
int num = abs(p1_len-p2_len);
while(num){
cur1= cur1->next;
num--;
}
while(cur1!=cur2){
cur1= cur1->next;
cur2= cur2->next;
}
return cur1;
}else{//有环,且第一个入环点不相等
Node * cur1 = in1->next;
while(cur1!=in1){
if(cur1 == in2) return cur1;
cur1 = in1->next;
}
return NULL;
}
return NULL;
}
Node * cal(Node * point1,Node * point2){
Node * in1 = checkloop(point1);
Node * in2 = checkloop(point2);
//两者都无环,可能存在交叉节点
if(in1==NULL && in2==NULL){
return no_loop(point1,point2);
}
//两者都有环,可能第一个入环节点相等,也可能第一个入环节点不相等
if(in1 && in2){
return both_loop(point1,in1,point2,in2);
}
//一个有环,一个无环 ,一定不相交
return NULL;
}
int main(){
Node * point1 = NULL;
Node * point2 = NULL;
init(point1,point2);
Node * ans = cal(point1, point2);
if (ans == NULL) printf("NULL!\n");
else printf("num:%d\n",ans->val);
return 0;
}