寻找两个单链表的公共结点(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
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 可以使用双指针法来实现。首先,创建一个新的头节点,然后让两个指针分别指向两个单链表的头节点,比较两个指针指向的节点的值,如果第一个指针指向的节点的值大于第二个指针指向的节点的值,则将第一个指针指向的节点插入新的头节点之后,第一个指针指向该节点的下一个节点;如果第二个指针指向的节点的值大于第一个指针指向的节点的值,则将第二个指针指向的节点插入新的头节点之后,第二个指针指向该节点的下一个节点。最后,将新的头节点指向合并后的单链表,即可完成合并操作。 ### 回答2: 实现这个功能可以按照以下步骤进行: 首先,创建一个新的单链表,用于存放合并后的结果。 然后,比较两个原始单链表的头结点的值,将值较大的头结点作为新链表的头结点,并移动到下一个结点。 接下来,循环执行以下步骤,直到其中一个链表遍历完: 1. 比较两个链表的头结点的值,将值较大的头结点移动到新链表的下一个结点,并移动到下一个结点。 2. 若其中一个链表遍历完,则将另一个未遍历完的链表的剩余部分连接到新链表的末尾。 最后,将新链表的头结点指向的下一个结点设为NULL,即将新链表的结束标识置为空。 具体的C语言代码实现如下: ```c #include <stdio.h> #include <stdlib.h> struct ListNode { int val; struct ListNode* next; }; struct ListNode* merge(struct ListNode* l1, struct ListNode* l2) { struct ListNode* dummy = (struct ListNode*)malloc(sizeof(struct ListNode)); struct ListNode* cur = dummy; while (l1 && l2) { if (l1->val <= l2->val) { cur->next = l1; l1 = l1->next; } else { cur->next = l2; l2 = l2->next; } cur = cur->next; } if (l1) { cur->next = l1; } else if (l2) { cur->next = l2; } struct ListNode* prev = NULL; cur = dummy->next; while (cur) { struct ListNode* next = cur->next; cur->next = prev; prev = cur; cur = next; } dummy->next = prev; free(dummy); return prev; } int main() { struct ListNode* l1 = (struct ListNode*)malloc(sizeof(struct ListNode)); struct ListNode* l2 = (struct ListNode*)malloc(sizeof(struct ListNode)); struct ListNode* node1 = (struct ListNode*)malloc(sizeof(struct ListNode)); node1->val = 1; struct ListNode* node2 = (struct ListNode*)malloc(sizeof(struct ListNode)); node2->val = 3; struct ListNode* node3 = (struct ListNode*)malloc(sizeof(struct ListNode)); node3->val = 5; l1->next = node1; node1->next = node2; node2->next = node3; node3->next = NULL; struct ListNode* node4 = (struct ListNode*)malloc(sizeof(struct ListNode)); node4->val = 2; struct ListNode* node5 = (struct ListNode*)malloc(sizeof(struct ListNode)); node5->val = 4; struct ListNode* node6 = (struct ListNode*)malloc(sizeof(struct ListNode)); node6->val = 6; l2->next = node4; node4->next = node5; node5->next = node6; node6->next = NULL; struct ListNode* merged = merge(l1->next, l2->next); while (merged) { printf("%d ", merged->val); merged = merged->next; } free(node6); free(node5); free(node4); free(node3); free(node2); free(node1); free(l2); free(l1); return 0; } ``` 以上就是将两个按元素值递增次序排列的单链表合并为一个按元素值递减次序排列的单链表的实现。 ### 回答3: 题目要求将两个按元素值递增次序排列的单链表合并为一个按元素值递减次序排列的单链表,并要求利用原来两个单链表结点存放合并后的单链表。下面是用C语言实现的思路: ```c #include <stdio.h> #include <stdlib.h> // 定义链表结点结构体 typedef struct Node { int data; struct Node* next; } Node; // 定义函数将两个链表合并并按递减次序排序,返回合并后的头结点 Node* mergeLists(Node* list1, Node* list2) { // 如果其中一个链表为空,返回另一个链表 if (list1 == NULL) return list2; if (list2 == NULL) return list1; // 定义合并后链表的头结点和当前结点 Node* head = NULL; Node* cur = NULL; // 选取较大的元素作为头结点 if (list1->data < list2->data) { head = list1; list1 = list1->next; } else { head = list2; list2 = list2->next; } cur = head; // 循环比较链表中的元素,选取较大的元素插入到合并链表的下一个结点 while (list1 != NULL && list2 != NULL) { if (list1->data < list2->data) { cur->next = list1; list1 = list1->next; } else { cur->next = list2; list2 = list2->next; } cur = cur->next; } // 将链表中剩余元素插入到合并链表的下一个结点 if (list1 != NULL) cur->next = list1; if (list2 != NULL) cur->next = list2; // 将合并后链表结点逆序 Node* prev = NULL; cur = head; while (cur != NULL) { Node* next = cur->next; cur->next = prev; prev = cur; cur = next; } head = prev; return head; } // 输出链表 void printList(Node* head) { Node* cur = head; while (cur != NULL) { printf("%d ", cur->data); cur = cur->next; } printf("\n"); } int main() { // 初始化链表1 Node* list1 = (Node*)malloc(sizeof(Node)); list1->data = 1; list1->next = (Node*)malloc(sizeof(Node)); list1->next->data = 3; list1->next->next = (Node*)malloc(sizeof(Node)); list1->next->next->data = 5; list1->next->next->next = NULL; // 初始化链表2 Node* list2 = (Node*)malloc(sizeof(Node)); list2->data = 2; list2->next = (Node*)malloc(sizeof(Node)); list2->next->data = 4; list2->next->next = (Node*)malloc(sizeof(Node)); list2->next->next->data = 6; list2->next->next->next = NULL; printf("合并前链表1:"); printList(list1); printf("合并前链表2:"); printList(list2); Node* mergedList = mergeLists(list1, list2); printf("合并后链表:"); printList(mergedList); return 0; } ``` 运行结果: ``` 合并前链表1:1 3 5 合并前链表2:2 4 6 合并后链表:6 5 4 3 2 1 ``` 以上代码实现了将两个按元素值递增次序排列的单链表合并为一个按元素值递减次序排列的单链表,利用了原始链表结点
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值