两个链表相交的一系列问题_算法

思路:

1.首先要实现对单链表是否有环的判断,以及取得第一个入环节点。

步骤为,设定一个块指针,每次走两步,设定一个慢指针,每次走一步。

如果无环,则快指针能够很块遍历完链表,直接退出返回NULL

如果有环,则他们会在某个时刻相遇,此时让快指针指向头指针,并且,快指针和慢指针每次只走一步。最后相遇的位置即为第一个入环节点。

2.其次是判断,两个链表是否相交,分以下几种情况:

两个链表相交的一系列问题_链表_02

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;
}