判断两个链表是否相交,若相交,求交点。(假设链表不带环)

int SListIsCrossNode(SListNode* list1, SListNode* list2)

{

SListNode *L1 = list1;

SListNode *L2 = list2;

DataType n1 = 0;

DataType n2 = 0;

DataType n = 0;

while (L1)

{

n1++;

L1 = L1->_next;

};

while (L2)

{

n2++;

L2 = L2->_next;

}

if (n1 >= n2)

{

n = n1 - n2;

L1 = list1;

while (n)

{

n--;

L1 = L1->_next;

}

}

else

{

n = n2 - n1;

L2 = list2;

while (n--)

{

L2 = L2->_next;

}

}

L1 = list1;

while (L1 != L2)

{

if ((L1 == NULL) || (L2 == NULL))

{

 

printf("两链表不相交\n");

return -1;

}

else

{

 

L1 = L1->_next;

L2 = L2->_next;

 

}

}

printf("两个链表相交\n");

return L1->_data;

}

昨天写了判断链表是否带环以及带环之后的一些求解方法,是否带环说的是一个链表的特殊状态,今天要写的是两个链表之间的特殊状态也就是两个链表相交的基础版本,两个链表都不带环来判断一下两个链表是否相交,先用一个图来说明一下什么是链表相交。

 

这是两个链表L1L2L2在数据3之后的指针指向了L1的部分空间,也就是如果cur指向的是L1中数据4的空间的话,那么L23数据处的next指针指向的就是cur所指向的数据4的空间。

遍历L2的时候走到数据3之后再往下走就是L1中的数据4的空间,这就是两个链表相交的情况。

今天我们来写一下如何判断两个链表是否相交,交点怎么求。

 

先说一下思想,如果判断两个链表相交的话,想到的就是如果两个链表中有的数据相同那可能就是相交的,但是这并不可靠,毕竟可能出现两个链表中的数据一模一样的情况,所以比较指针是可靠的,假如一个指针指向了L1,并且这个指针也指向了L2,那么就可以说这两个链表是相交的,但是到底比哪个指针呢?倒数第三个?万一倒数第二个数据开始两个链表合并了呢?都是会有极端情况,有的人提到了说比最后一个如果最后一个一样的话那么两个链表是相交的,这个方法并不是说不可靠,但是今天我给大家说的是一种更清楚更细致的方法。

while (L1)

{

n1++;

L1 = L1->_next;

};

while (L2)

{

n2++;

L2 = L2->_next;

}

 

首先,遍历两个链表,将两个链表的长度求出来。如果两个链表相交了,那么两个链表相交部分的长度一定是一样的,所以两个链表长度不同的部分只能是前边不想交的部分。

if (n1 >= n2)

{

n = n1 - n2;

L1 = list1;

while (n)

{

n--;

L1 = L1->_next;

}

}

else

{

n = n2 - n1;

L2 = list2;

while (n--)

{

L2 = L2->_next;

}

}

将两个链表的长度求出来之后,找到链表长的那个链表的长度,减去短链表的长度就是两个链表长度的差,然后让长的那个链表先走相差的长度。

 

L1 = list1;

这时候一定要注意这些小细节,当你遍历完两个链表的时候,两个指针L1,L2都是指向两个链表的最后的。

while (L1 != L2)

{

if ((L1 == NULL) || (L2 == NULL))

{

 

printf("两链表不相交\n");

return -1;

}

else

{

 

L1 = L1->_next;

L2 = L2->_next;

 

}

}

然后让两个指针不断的向后走,如果两个指针相等就退出while循环,就说明这两个链表中出现了一个指向相同位置的指针,也就是两个链表相交了,如果说出现了其中有一个链表出现了NULL。就是遍历完了其中一个链表,仍然没有出现指向同一个位置的指针,那就说明两个链表不会相交了。

printf("两个链表相交\n");

return L1->_data;

 

因为一相等就跳出来了,所以当前两个指针指向的都是第一块相等的空间,也就是交点,这时候随便返回两个指针中的一个数据就是两个链表的交点了。

 

同样这里还要说一下怎么让两个链表相交起来。

while (cur1->_next->_next->_next)

{

cur1 = cur1->_next;

};

这里将cur指向L1中的一个位置,这里我找的是倒数第二个位置。

while (cur2->_next)

{

cur2 = cur2->_next;

}

 

然后找到L2中的最后一个元素将他的next指针指向cur位置,这时候两个链表就合并了。

int main()

{

SListNode* SList1;

SListNode* SList2;

SListNode *cur1 = NULL;

SListNode *cur2 = NULL;

DataType ret = 0;

SList1 = BuySListNode(1);

SListPushBack(&SList1, 2);

SListPushBack(&SList1, 3);

SListPushBack(&SList1, 4);

SListPushBack(&SList1, 5);

SList2 = BuySListNode(1);

SListPushBack(&SList2, 2);

SListPushBack(&SList2, 3);

cur1 = SList1;

while (cur1->_next->_next->_next)

{

cur1 = cur1->_next;

};

cur2 = SList2;

while (cur2->_next)

{

cur2 = cur2->_next;

}

cur2->_next = cur1;

ret=SListIsCrossNode(SList1, SList2);

printf("%d", ret);

printf("\n");

system("pause");

return 0;

}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值