问题描述:
给定两个链表LinkList1, LinkList2, 判断两个链表是否相交?
解题思路:
这是一道常考题了,解题的思路主要如下:
1.首先要考虑到链表是否有环?
2. 如果链表没有环,则可以分别遍历链表,如果相交,最后两个指针一定会相遇
3. 如果有环且相交, 那么环上面的任意一个节点都一定会出现在另一个链表上。那么就变成了判断
环上的点是否链表上的问题。
关于判断链表是否有环的算法:
这个算法应该在网上出现了很多次了。用两个指针同时指向链表头,一个指针的步长为1,另一个指针的步长为2,如果最后相遇,则证明有环。
否则链表无环。
为什么另一个指针的步长是2,就能一定保证在链表有环的情况下两个指针最后一定会相遇呢?有没有可能最后两个指针不相遇呢?
分析一下:
假设链表是有环的,我们称步长为2的指针为快指针(p_fast), 步长为1的指针为慢指针(p_slow).
p_fast一定会先进入环,p_slow后进入环。假设当p_slow进入环时,p_fast到p_slow这间超出的节点个数为K. (p_fast有可能已经在环内转了几圈)
如果N步之后, p_fast经过了2*N个节点, p_slow经过了N个节点
要使它们能相遇:
2*N = N + K
N = K
K为整数,N可以满足。所以一定会相遇。
如果p_fast的步长为3呢?
3*N = N + K
2*N = K
N = K/2
此时如果K是奇数,那么p_fast和p_slow就永远没有相遇的一天了。
所以快指针的步长为2不是随意定的。
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct _node_t{
int val;
_node_t *next;
}node_t;
int check_loop(node_t *link_head, node_t **cross_node)
{
node_t *p_fast;
node_t *p_slow;
int has_loop;
p_fast = link_head;
p_slow = link_head;
has_loop = 0;
while (p_fast != NULL && p_slow != NULL)
{
p_slow = p_slow->next;
if (p_fast->next != NULL){
p_fast = p_fast->next->next;
}
else {
break;
}
if (p_slow == p_fast){
has_loop = 1;
*cross_node = p_slow;
break;
}
}
return has_loop;
}
int check_node_exist(node_t *link_head, node_t *node)
{
node_t *p = link_head;
int ret = 0;
while (p)
{
if (p == node){
ret = 1;
break;
}
p = p->next;
}
return ret;
}
int link_cross(node_t *link_head1, node_t *link_head2)
{
int flag1, flag2;
int ret;
node_t *node;
flag1 = check_loop(link_head1, &node);
flag2 = check_loop(link_head2, &node);
ret = 0;
/* Neigher of the two link_list has loop */
if (flag1 == 0 && flag2 == 0)
{
node_t *p1 = link_head1;
node_t *p2 = link_head2;
while (1)
{
if (p1 == p2){
/* crossed */
ret = 1;
break;
}
if (p1->next){
p1 = p1->next;
}
if (p2->next){
p2 = p2->next;
}
if (p1->next == NULL && p2->next == NULL){
/* both link_list come to the end */
ret = 0;
break;
}
}
}
else if (flag1 == 1){
/* find out one node in the loop and check its existence in the other link_list*/
ret = check_node_exist(link_head2, node);
}
else{
/* find out one node in the loop and check its existence in the other link_list*/
ret = check_node_exist(link_head1, node);
}
return ret;
}