判断两个单链表有相交节点/判断一个链表是否有环

本文讨论了如何检测两个单向链表是否有相交节点,并提供了多种解决方案,包括一般解法、hash计数、转化为环问题以及从尾节点开始判断的方法。还介绍了如何在链表相交的情况下找到第一个相交节点。
部署运行你感兴趣的模型镜像

1、题目:给定两个单向链表的头指针,如h1和h2,判断这两个链表是否有相交节点。

假设两个链表都不带环,其相交如下图所示:


一、分析与解法

两个链表相交的情况在一个大的系统中可能会出现,如果出现两个链表相交的情况,一旦程序释放了其中一个链表的所有节点,那样就会造成信息的丢失,并且另一个与之相交的链表也会受到影响。在特殊情况下,的确需要出现相交的两个链表,我们希望在释放一个链表之前知道是否有其他链表跟当前这个链表相交。


解法一、一般解法

双重遍历两个链表,直接查找是否有相同的节点地址,其时间复杂度为O(len(h1)*len(h2)),空间复杂度为O(1)。这种方法很耗时间。


解法二、hash计数

如果两个链表相交,那么这两个链表中就会有共同的节点。而节点地址又是节点的唯一标识。所以,如果我们能够判断两个链表中是否存在地址一致的节点,就可以知道这两个链表是否相交。一个简单的做法就是对第一个链表的节点地址进行hash排序,建立hash表,然后针对第二个链表的每个节点的地址查询hash表,如果它在hash表中出现,那么说明第二个链表和第一个链表有共同的节点。这个方法的时间复杂度为O(len(h1)+len(h2)),空间复杂度为O(len(h1))。它是典型地以增加存储空间为代价,减少了时间复杂度。


解法三、转化为一个链表是否有环问题

由于两个链表都没有环,那我们可以把第二个链表接在第一个链表的后面,如果得到的链表有环,则说明这两个链表不相交。这样就把问题转化为判断一个链表是否有环的问题了。


判断一个链表是否有环,也不是简单的问题。其时间复杂度为O(len(h1)+len(h2)),空间复杂度为O(1)。


解法四、尾节点开始

如果两个没有环的链表相较于某一个节点,那么在这个节点之后的所有节点都是两个链表所共有的。根据这个特点,我们通过找到链表最后一个节点进行判断比较。先遍历第一个链表,记住最后一个节点。然后遍历第二个链表,到最后一个节点时和第一个链表的最后一个节点做比较,如果相同,则相交,否则,不相交。这样我们就得到了 一个复杂度为O(len(h1)+len(h2)),且只用了一个额外的指针来存储最后一个节点。

代码实现:

/*
	判断两个不含环的单链表相交
	相交指的是结点的地址相同,而不是结点的值相同
*/
#include <iostream>

using namespace std;

struct LinkList{
	int value;
	LinkList *next;
};

//建立一个链表
void InsertList(LinkList *&list)
{
	LinkList *head;
	LinkList *newNode;
	int data;
	head=list;
	while(head->next)
		head=head->next;
	cout<<"输入数据:";
	while(1)
	{
		cin>>data;
		if(data == 0) break;
		newNode=new LinkList();
		newNode->value = data;
		newNode->next = NULL;
		head->next = newNode;
		head=newNode;
		head->next=NULL;
	}
}

//输出链表
void Traverse(LinkList *list)
{
	LinkList *p;
	p=list->next;
	while(p)
	{
		cout<<" "<<p->value<<" address="<<p<<endl;
		p=p->next;
	}
}

int main()
{
	LinkList *first,*second;
	LinkList *fhead,*shead,*h1,*h2,*p,*q;
	int flen=0,slen=0;

	first=new LinkList();
	first->next=NULL;
	second=new LinkList();
	second->next=NULL;

	InsertList(first);
	InsertList(second);
	//将第一个链表中从第四个结点起链接到第二个链表后,构成两个相交的链表
	p=second;
	while(p->next)
		p=p->next;

	q=first;
	for(int i=0;i<4;i++)
		q=q->next;
	p->next=q;

	Traverse(first);
	cout<<endl;
	Traverse(second);
	cout<<endl;

	//对链表1进行遍历到尾部
	fhead=first;
	while(fhead->next)
	{
		fhead=fhead->next;
		flen++;
	}

	//对链表2进行遍历到尾部
	shead=second;
	while(shead->next)
	{
		shead=shead->next;
		slen++;
	}

	if(fhead == shead)
	{
		cout<<"两个链表相交!"<<endl;
	}
	else
		cout<<"两个链表不相交!"<<endl;
	system("pause");
	return 0;
}


二、拓展问题

2.1、求出两个链表相交的第一个节点?

解法:计算相差的长度

分别遍历两个链表,记录长度(若已知则不需此步),短链表从头结点开始,长链表从第| len(h1) - len(h2) | 个节点开始,依次遍历并比较,相等的第一个节点则为相交的第一个节点。也可以使用hash法。

代码实现:

//求两个链表相交的第一个节点
	if(flen>=slen)//其两个链表的长度差值
	{
		len=flen-slen;
		while(len--)
			h1=h1->next;
	}
	else
	{
		len=slen-flen;
		while(len--)
			h2=h2->next;
	}
	while(1)
	{
		if(h1 == h2)
		{
			cout<<"两个链表第一个相交的节点是"<<h1->value<<",地址是:"<<h1<<endl;
			break;
		}
		else if((h1->next)&&(h2->next))
		{
			h1=h1->next;
			h2=h2->next;
		}
		else
			cout<<"两个链表不相交!"<<endl;
	}


您可能感兴趣的与本文相关的镜像

LobeChat

LobeChat

AI应用

LobeChat 是一个开源、高性能的聊天机器人框架。支持语音合成、多模态和可扩展插件系统。支持一键式免费部署私人ChatGPT/LLM 网络应用程序。

在C语言中,我们可以使用双指针法来编写一个程序判断两个单链表是否相交。这里是一个简单的示例: ```c #include <stdio.h> #include <stdlib.h> // 定义链表节点结构体 typedef struct ListNode { int val; struct ListNode* next; } ListNode; // 创建新节点 ListNode* createNode(int val) { ListNode* newNode = (ListNode*)malloc(sizeof(ListNode)); if (!newNode) { printf("Memory allocation failed.\n"); return NULL; } newNode->val = val; newNode->next = NULL; return newNode; } // 判断两个链表是否有交叉点 int isListIntersect(ListNode* listA, ListNode* listB) { ListNode* p1 = listA; // 指针p1遍历listA ListNode* p2 = listB; // 指针p2遍历listB // 遍历列表直到有一个到达末尾 while (p1 != NULL && p2 != NULL) { if (p1 == p2) { // 如果找到相同的节点,则有交点 return 1; } p1 = p1->next ? p1->next : listB; // 如果p1到了末尾,从头开始遍历listB p2 = p2->next ? p2->next : listA; // 同理,如果p2到了末尾,从头开始遍历listA } return 0; // 没有找到交点,返回0 } // 测试函数 void testIntersection() { ListNode* listA = createNode(1); listA->next = createNode(2); listA->next->next = createNode(4); listB = createNode(3); listB->next = createNode(4); // 两链表在这里相交 int result = isListIntersect(listA, listB); if (result) printf("The two lists intersect.\n"); else printf("The two lists do not intersect.\n"); } int main() { testIntersection(); return 0; } ``` 这个程序首先创建两个单链表,然后使用`isListIntersect`函数检查它们是否有交点。如果有交点,该函数会返回1,否则返回0。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值