寻找两个单链表的公共结点(C语言)

问题描述:

	两个单链表有公共结点,也就是两个链表从某一结点开始,它们的指针域都指向同一个结点。由于每个单链表结点只有一个next域,因此从第一个公共结点开始,之后所有的结点都是重合的,不可能再出现分叉,如图所示:

在这里插入图片描述

一、实现方法

方法一:

	在两个单链表中分别顺序遍历每个链表中的所有结点,如果有相同的结点则找到了公共的结点,但该算法的时间复杂度为O(len1*len2)。

方法二:

	如果两个链表有公共结点,则该公共结点之后的所有结点都是重合的,即它们的最后一个结点必然是重合的。因此,我们判断两个链表是不是有重合的部分,只要分别遍历两个链表到最后一个结点。如果两个尾结点是一样的,说明它们有公共结点,否则两个链表没有公共的结点。但在顺序遍历两个链表到尾结点的时,并不能保证在两个链表同时到达尾结点,因为两个链表的长度有可能是不一样。因此假设一个链表比另一个长n个结点,先在长的链表上遍历n个结点,之后再两个链表同步遍历,此时就能保证同时到达最后一个结点。由于两个链表从第一个公共结点开始到链表的尾结点,这一部分是重合的。因此,它们肯定也是同时到达第一公共结点的,于是在遍历中,第一个相同的结点就是第一个公共的结点。
	因此在这样的思路中,先要分别遍历两个链表得到它们的长度,并求出两个长度之差。在长的链表上先遍历长度之差个结点之后,再同步遍历两个链表,直到找到第一个相同的结点就结束。该方法的时间复杂度为O(len1+len2)。

二、代码实现

1.链表结构体

代码如下(示例):

typedef struct node
{
	int data;  
	struct node* next;  
}SingleList;

2.初始化链表

代码如下(示例):

//初始化A链表
SingleList* a_init_SingleList()
{
	SingleList* a_list = malloc(sizeof(SingleList));

	if (a_list == NULL)
		return NULL;
	
	a_list->data = 0;
	a_list->next = NULL;

	return a_list;
}

//初始化B链表
SingleList* b_init_SingleList()
{
	SingleList* b_list = malloc(sizeof(SingleList));
	if (b_list == NULL)
		return NULL;

	b_list->data = 0;
	b_list->next = NULL;

	return b_list;
}
//初始化C链表
SingleList* c_init_SingleList()
{
	SingleList* c_list = malloc(sizeof(SingleList));
	if (c_list == NULL)
		return NULL;

	c_list->data = 0;
	c_list->next = NULL;

	return c_list;
}

3.尾插法创建单链表

代码如下(示例):

//尾插法创建单链表
SingleList* create_SingleListByTail(SingleList* list)
{
	SingleList* pMove, * pCreate, * head;
	int length, data;
	head = (SingleList*)malloc(sizeof(SingleList));
	head = list;
	if (head == NULL)
	{
		return NULL;
	}
	else
	{
		head->next = NULL;
	}
	pMove = head;
	printf("请输入创建链表的长度:");
	scanf_s("%d", &length);
	for (int i = 0; i < length; i++)
	{
		scanf_s("%d", &data);
		pCreate = (SingleList*)malloc(sizeof(SingleList));
		if (pCreate == NULL)
		{
			return NULL;
		}
		pCreate->data = data;
		pCreate->next = NULL;

		//插入操作
		pMove->next = pCreate;
		pMove = pCreate;
	}
	return list;
}

4.连接两个单链表

代码如下(示例):

//连接两个链表
SingleList* link(SingleList* list1, SingleList* list2)
{
	SingleList* pmove, * qmove;
	pmove = list1;
	qmove = list2;
	while (pmove->next)
	{
		pmove = pmove->next;
	}
	pmove->next = qmove->next;  //更改list1的指针域,让其指向list2完成连接
	return list1;
}

5.求链表的长度

代码如下(示例):

//求链表的长度
int foreach_SingleList(SingleList* list)
{
	SingleList* pMove;
	int num = 0;
	pMove = list->next;
	while (pMove != NULL)
	{
		num++;
		pMove = pMove->next;
	}
	return num;
}

6.寻找两个链表中的公共结点

代码如下(示例):

//寻找两个链表中的公共结点
void searchCommonNodeFromSingleList(SingleList* list1, SingleList* list2)
{
	SingleList* pMove, * qMove;
	int len1, len2, dis;
	len1 = foreach_SingleList(list1);
	len2 = foreach_SingleList(list2);
	
	if (len1 > len2)  //链表1的长度大于链表2的长度 
	{
		pMove = list1->next;  //指向长表
		qMove = list2->next;  //指向短表

		dis = len1 - len2;    //两表长度差
	}
	else
	{
		pMove = list2->next;
		qMove = list1->next;

		dis = len2 - len1;
	}
	while (dis--)   //长表先遍历到第dis个结点后再和短表同步遍历
	{
		pMove = pMove->next;
	}
	while (pMove != NULL)      //寻找公共结点
	{
		if (pMove == qMove)   //找到第一个相同结点
		{
			break;
		}
		else
		{
			pMove = pMove->next;
			qMove = qMove->next;
		}
	}
	printf("两个链表的公共结点为:\n");
	while (pMove != NULL)
	{
		printf("%d ", pMove->data);
		pMove = pMove->next;
	}
	printf("\n");
}

7.输出链表中的内容

代码如下(示例):

//打印
void printf_SingleList(SingleList* list)
{
	SingleList* pMove;
	pMove = list->next;
	while (pMove != NULL)
	{
		printf("%d ", pMove->data);
		pMove = pMove->next;
	}
	printf("\n");
}

8.主函数

代码如下(示例):

int main(void)
{
	SingleList* a_list, * b_list, * a_myList, * b_myList, * c_list, * c_myList, * a_link_c, * b_link_c;
	a_list = a_init_SingleList();  //初始化A链表
	b_list = b_init_SingleList();  //初始化B链表
	c_list = c_init_SingleList();  //初始化C链表

	a_myList = create_SingleListByTail(a_list);  //尾插法创建A链表
	printf("链表A的内容为:\n");
	printf_SingleList(a_myList);

	b_myList = create_SingleListByTail(b_list);  //尾插法创建B链表
	printf("链表B的内容为:\n");
	printf_SingleList(b_myList);

	c_myList = create_SingleListByTail(c_list);  //尾插法创建C链表
	printf("链表C的内容为:\n");
	printf_SingleList(c_myList);

	a_link_c = link(a_myList, c_myList);
	printf("链表A和链表C连接后为:\n");
	printf_SingleList(a_link_c);

	b_link_c = link(b_myList, c_myList);
	printf("链表B和链表C连接后为:\n");
	printf_SingleList(b_link_c);

	searchCommonNodeFromSingleList(a_link_c, b_link_c);  //寻找两个链表中的相同结点

	system("pause");
	return EXIT_SUCCESS;
}

9.运行截图

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值