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

来源:互联网 发布:好玩的桌面软件 编辑:程序博客网 时间:2024/05/21 06:29
/************************************************************* * 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;elsewhile(diff_len-- > 0 && tmp2->next)tmp2 = tmp2->next;while(tmp1 && tmp2){if(tmp1 == phead2)return phead1;tmp1 = tmp1->next;tmp2 = tmp2->next;}}elsereturn 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;elsewhile(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;}elsereturn NULL;//两个环不相交}return NULL; }   

0 0
原创粉丝点击