一、问题描述
- 现在有两条单向链表,如何判断它们是否相交,以及相交时的第一个公共节点在哪?
二、解决方案
- 先判断它们是否相交:如果它们是相交的,那么必然尾节点相同。因此,可以遍历两个单链表,一直遍历到尾节点,然后判断它们的尾节点指针是否相同,如果相同则可以确定它们相交
- 如果相交,再找出两个单链表的第一个公共节点:
- 获取两个单链表的长度,设为LA和LB
- 如果LA>LB,则单链表A从距头结点距离为LA-LB的那个节点开始遍历,LB直接从头结点开始遍历,当遍历到两个节点的指针都相同时,那么这两个单链表相交
- 如果LB>LA,则单链表B从距头结点距离为LB-LA的那个节点开始遍历,LA直接从头结点开始遍历,当遍历到两个节点的指针都相同时,那么这两个单链表相交
三、编码实现
/**
* @description: 判断list1和list2是否相交, 如果相交返回一个公共节点的指针
* @param :
list1: 链表1
list2: 链表2
* @return:
不想交, 没有公共节点: NULL
相交: 返回第一个公共节点的指针
* @author: Dongshao
*/
Node* firstCommonNode(Node *list1, Node *list2)
{
Node *temp1 = list1;
Node *temp2 = list2;
size_t list1Size = 0;
size_t list2Size = 0;
// 先判断两个链表是否相交:
// 判断两个链表的尾节点是否相同即可
// 再遍历的时候同时记录两个链表的长度
for(temp1; temp1->_pnext != NULL; temp1 = temp1->_pnext)
++list1Size;
++list1Size;
for(temp2; temp2->_pnext != NULL; temp2 = temp2->_pnext)
++list2Size;
++list2Size;
// 如果尾节点不相同, 那么两个单链表不相交, 返回NULL
if(temp1 != temp2)
return NULL;
// 根据哪个链表长, 设定遍历起点
// 如果list1 > list2, 则temp1指向距头结点长度为(list1-list2)的节点, temp2直接指向头结点
if(list1Size > list2Size)
{
temp1 = list1;
for(int i = 0; i < (list1Size - list2Size); ++i)
temp1 = temp1->_pnext;
temp2 = list2;
}
// 如果list1 < list2
else if(list1Size < list2Size)
{
temp2 = list2;
for(int i = 0; i < (list2Size - list1Size); ++i)
temp2 = temp2->_pnext;
temp1 = list1;
}
else
{
temp1 = list1;
temp2 = list2;
}
// 然后开始遍历, 如果遍历到一个指针相同的节点, 那么这个就是第一个相交的节点, 直接返回即可
while(temp1 != temp2)
{
temp1 = temp1->_pnext;
temp2 = temp2->_pnext;
}
return temp1;
}
四、测试代码
#include <iostream>
using namespace std;
typedef struct node
{
struct node *_pnext;
int data;
} Node;
/**
* @description: 判断list1和list2是否相交, 如果相交返回一个公共节点的指针
* @param :
list1: 链表1
list2: 链表2
* @return:
不想交, 没有公共节点: NULL
相交: 返回第一个公共节点的指针
* @author: Dongshao
*/
Node* firstCommonNode(Node *list1, Node *list2)
{
Node *temp1 = list1;
Node *temp2 = list2;
size_t list1Size = 0;
size_t list2Size = 0;
// 先判断两个链表是否相交:
// 判断两个链表的尾节点是否相同即可
// 再遍历的时候同时记录两个链表的长度
for(temp1; temp1->_pnext != NULL; temp1 = temp1->_pnext)
++list1Size;
++list1Size;
for(temp2; temp2->_pnext != NULL; temp2 = temp2->_pnext)
++list2Size;
++list2Size;
// 如果尾节点不相同, 那么两个单链表不相交, 返回NULL
if(temp1 != temp2)
return NULL;
// 根据哪个链表长, 设定遍历起点
// 如果list1 > list2, 则temp1指向距头结点长度为(list1-list2)的节点, temp2直接指向头结点
if(list1Size > list2Size)
{
temp1 = list1;
for(int i = 0; i < (list1Size - list2Size); ++i)
temp1 = temp1->_pnext;
temp2 = list2;
}
// 如果list1 < list2
else if(list1Size < list2Size)
{
temp2 = list2;
for(int i = 0; i < (list2Size - list1Size); ++i)
temp2 = temp2->_pnext;
temp1 = list1;
}
else
{
temp1 = list1;
temp2 = list2;
}
// 然后开始遍历, 如果遍历到一个指针相同的节点, 那么这个就是第一个相交的节点, 直接返回即可
while(temp1 != temp2)
{
temp1 = temp1->_pnext;
temp2 = temp2->_pnext;
}
return temp1;
}
int main()
{
// 构建LA的前半部分
Node *anode1 = (Node*)malloc(sizeof(Node));
Node *anode2 = (Node*)malloc(sizeof(Node));
Node *anode3 = (Node*)malloc(sizeof(Node));
anode1->data = 1;
anode2->data = 7;
anode3->data = 4;
anode1->_pnext = anode2;
anode2->_pnext = anode3;
// 构建LB的前半部分
Node *bnode1 = (Node*)malloc(sizeof(Node));
Node *bnode2 = (Node*)malloc(sizeof(Node));
bnode1->data = 1;
bnode2->data = 7;
bnode1->_pnext = bnode2;
// 构建两个公共节点
Node *commonNode1 = (Node*)malloc(sizeof(Node));
Node *commonNode2 = (Node*)malloc(sizeof(Node));
commonNode1->data = 8;
commonNode2->data = 10;
commonNode2->_pnext = NULL;
commonNode1->_pnext = commonNode2;
// 将公共节点拼接到LA和LB的后面
anode3->_pnext = commonNode1;
bnode2->_pnext = commonNode1;
// 寻找公共节点, 并打印值
Node *commonNode = firstCommonNode(anode1, bnode1);
std::cout << "firstCommonNode data: " << commonNode->data << std::endl;
return 0;
}