求两个单链表的第一个交点(人搜)

/*************************************************************
 * file:find_common_node_of_two_lists.c
 * brief:找个两个单链表的第一个交点
 * yejing@2015.1.20    1.0      creat
 *************************************************************/
 #include <stdio.h>
 #include <stdlib.h>
 
 typedef struct __node_t{
	struct __node_t* next;
	int              value;
 }node_t
 
 //获取从头开始的两个不同速指针第一次交汇的节点,没有返回NULL
 node_t* get_cross_node(node_t* phead){
	if(!phead)
		return NULL;
	node_t *one_step, *two_step;
	one_step = two_step = phead;
	while(two_step && one_step->next){
		one_step = one_step->next;
		two_step = two_step->next->next;
		if(one_step == two_step)
			return one_step;
	}
	
	return NULL;
 }
 
 //通过判断尾节点是否相等判断两个链表是否交叉,如果交叉返回长度差并标示那个比较长
 int check_no_circle_lists_crossed(node_t* phead_1, node_t* phead_2, int* diff_len, int* bigger_one, node_t* mark){
	if(!phead_1 || !phead_2 || is_crossed)
		return;
	node_t *tmp1, *tmp2;
	int count1 = 1, count2 = 1;
	tmp1 = phead1;
	tmp2 = phead2;
	while(tmp1->next != mark){
		++count1; tmp1 = tmp1->next;
	}
	while(tmp2->next != mark){
		++count2; tmp2 = tmp2->next;
	}
	
	if(tmp2 == tmp1){
		if(count2 <= count1){
			*diff_len = count1 - count2;
			*bigger_one = 1;
		}
		else{
			*diff_len = count2 - count1;
			*bigger_one = 2;
		}
		return 1;
	}
	
	return 0;
	
 }
 
 /*
 返回NULL表示没有交点的情况
 */
 node_t* process(node_t* phead_1, node_t* phead_2){
	if(!phead_1 || !phead_2)
		return NULL;
		
	int diff_len = 0, bigger_one = 0;
	node_t *meet_node1, *meet_node2;
	node_t *tmp1, tmp2;
	meet_node1 = get_cross_node(phead_1);
	meet_node2 = get_cross_node(phead_2);
		
	//因为是单链表,所以不可能出现一个有环一个无环还相交的情况
	if((meet_node1 && !meet_node2)||(!meet_node1 && meet_node2))
	   return NULL;
	//两个都无环
	else if(!meet_node1 && !meet_node2){
		//两个无环单链表如果相交,最后一个节点一定相等。
		//另外一个办法是将一个头接到另外一个尾上看是不是有环,判断方法与上面类似
		if(check_no_circle_lists_crossed(phead_1, phead_2, &diff_len, &bigger_one, NULL)){
			//消除两个链表的长度差
			tmp1 = phead_1; tmp2 = phead_2;
			if(1 == bigger_one)
				while(diff_len-- > 0 && tmp1->next)
					tmp1 = tmp1->next;
			else
				while(diff_len-- > 0 && tmp2->next)
					tmp2 = tmp2->next;
			
			while(tmp1 && tmp2){
					if(tmp1 == phead2)
						return phead1;
					tmp1 = tmp1->next;
					tmp2 = tmp2->next;
				}
		}
		else
			return NULL;
	}
	//两个链表都有环,如果交叉,则环必定是公共环,入口也必定是一个
	else{
		/*先求入环口,而需要先明确的是:
		1,重合的时候two_step的路程一定是one_step的两倍。
		2,一旦one_step进入环内,无论如何two_step一定能在一圈之内追上它。
		假设从起始点到入环口路程为x,截止相遇时在环内走过y,一圈为m,two在圈中走了n次
		则2(x+y) = x + y + m.n,即 x + y = m.n,即x+y一定是圈的整数倍。
		所以从x开始再走y的路程,就是入口,同时也是起点到入口的距离。
		如果同时走,当二者相等时就是入口
		*/
		node_t* circle_enter1 = phead_1;
		node_t* circle_enter2 = phead_2;
		while(meet_node1 && circle_enter1)
		{
			if(meet_node1 == circle_enter1)
				break;
			meet_node1 = meet_node1->next;
			circle_enter1 = circle_enter1->next;
		}
		while(meet_node2 && circle_enter2)
		{
			if(meet_node2 == circle_enter2)
				break;
			meet_node2 = meet_node2->next;
			circle_enter2 = circle_enter2->next;
		}
		
		if(circle_enter2 == circle_enter1){
			//两种情况,1,环入口是第一个的公共点,2,在入环之前就已经重合了
			//这里可以先用上满没有环的判断办法计算交点
			if(check_no_circle_lists_crossed(phead_1, phead_2, &diff_len, &bigger_one, circle_enter2)){
				//消除两个链表的长度差
				tmp1 = phead_1; tmp2 = phead_2;
				if(1 == bigger_one)
					while(diff_len-- > 0 && tmp1->next)
						tmp1 = tmp1->next;
				else
					while(diff_len-- > 0 && tmp2->next)
						tmp2 = tmp2->next;
				
				while(tmp1 && tmp2){
						if(tmp1 == phead2)
							return phead1;
						tmp1 = tmp1->next;
						tmp2 = tmp2->next;
				}
			}
			else//在环入口之前没有交点,返回环入口点
				return circle_enter1;
			
		}
		else
			return NULL;//两个环不相交
		
	}
	return NULL;
 }
 
 
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值