/*************************************************************
* 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;
}
求两个单链表的第一个交点(人搜)
最新推荐文章于 2021-03-29 22:40:16 发布