每天三道冲刺工作--判断俩个链表是否相交。

转载自点击打开链接

题目:

给出俩个单向链表的头指针,比如h1,h2,判断这俩个链表是否相交。
为了简化问题,我们假设俩个链表均不带环。
问题扩展:
1.如果链表可能有环列?
2.如果需要求出俩个链表相交的第一个节点列?


解决方法:


设第一个链表的起始指针为a(结点数为n),第二个链表的起始指针为b(结点为m)

一、对于简化了的问题:

(1)最直观的方法,就是将a中的每个结构与b中的每个结点进行比较操作,看是否相等(注意不是比较的元素大小,而是比较的结点地址,这才叫相交),这样程序最直观,最简单,但时间复杂度为n*m;

(2)第二种方法,根据单链表的改天换地,即单链表只能指向其向后一个元素,可知,如果a与b有交点,那么交点以及交点之后的所有结点均作为两个单链表的最后的公有部分。因此,只需先遍历第一个链表,遍历到最后一个元素时,再遍历第二个链表,看该元素是否也是第二个链表中的最后一个结点,如果是,则相交,否则不相交

bool YesOrNo1(node *First,node *Second)//第一种方法,将第一个链表中元素挨个与第二个链表比较。时间复杂度为n1*n2;
{
	if(NULL == First->next || NULL == Second->next)
		return false ;
	while(NULL != First)
	{
		while(NULL != Second)
		{
			if(First == Second)
			{
				cout<<Second->a<<"Yes";
				return true;
			}
			else
			{
				Second = Second->next;
			}


		}
		First = First->next;
	}
	return false;

}

bool YesOrNo2(node *First,node *Second)//第二种方法,先将第一个链表遍历到底,,设最后一个元素为a,然后测试a是否在第二个链表中,如果在,则有交。
{
	if(NULL == First->next || NULL == Second->next)//链表为空
		return false;
	while(NULL != First->next)
		First = First->next;
	while(NULL != Second)
	{
		if(First == Second)
		{
			cout<<First->a;
			cout<<"Yes";
			return true;
		}
		else
		{
			Second = Second->next;
		}
	}
	cout<<"No";
	return false;
}



二、可能有环的情况

(1)首先要操作的是,判断链表是否有环。判断一个链表是否有环的方法是,对一个链表,设置两个指针c和d,分别指向第一个结点和第二个结点,那么将c每次加1,d每次加2 ,,直到两个指针到链表尾,,比较两个指针,如果相等,则存在环,否则不存在 环,,就好象绕操场跑步,,如果是直线跑,慢的永远追不上快的,直到终点,,而如果操场是环,则,快的肯定会追上慢的。。

(2)如果链表没有环,则按(一)进行操作。。有环时,如果有交点,,那么要么a=b,,要么a是b的一部分,或b是a的一部分。。则进行判断两个环是否有交点的过程,,同判断是否有环的过程类似,,即指针c指向a起始位置,指针d指针b起始位置,将c每次+1,将d每次+2;。。比较c和d如果相等,则有交点,否则没有交点。。但这种情况,,当两个都是环,且没有交点时,会造成无限循环,,(这点没有考虑到,,看别人的想到的。)这样的解决方法是,,判断既然两个链表都有环,,那么肯定一个链表是另一个的一部分,不妨先对a进行操作,按照判断链表是否存在环的过程,当相遇时,判断相遇结点是否在b中,如果在,则有公共结点,,否则就没有。

bool HaveRing(node *First)//判断链表是否有环,一个a一次走一步,一个b一次走两步,如果有a == b则有环,否则 没环
{
	if(NULL == First->next)
		return false;
	node *s1 = First;
	node *s2 = First->next;
	while(NULL != s1 && NULL != s2->next)
	{
		if(s1 == s2)
			return true;
		else
		{
			s1 = s1->next;
			s2 = s2->next->next;
		}
	}
	return false;
}

三、找出第一个交点

(1)对于 当没有环的情况下,在判断两个链表是否相交之前,先进行遍历,记录下两个链表的结点个数。如果相交,,则用结果多的减去结点少的,设结果为x,则从多的那个第x个结点开始判断,挨个与结果少的那个比较,如果相同,则为第一个相交的结点。直到链表尾。。

(2)对于有环的情况,,没有想到应该怎么办,,

有没有大神指点有环的情况应该怎么办???????


node* FirstNode(node *First,node *Second)
{
	int FirstLen = 0;
	int SecondLen = 0;
	node *a = First;
	node *b = Second;
	while(NULL !=a)
	{
		FirstLen++;
		a = a->next;
	}
	while(NULL != b)
	{
		SecondLen ++;
		b = b->next;
	}
	if(YesOrNo2(First,Second))
	{
		int x = FirstLen - SecondLen;
		if(x>0)
		{
			for(int i = 0;i<x;i++)
			{
				First = First->next;
			}
			while (First != Second)
			{
				First = First->next;
				Second = Second->next;
			}
			return First;
		}
		else
		{
			for(int i = 0;i<(-x);i++)
			{
				Second = Second->next;
			}
			while(Second != First)
			{
				First = First->next;
				Second = Second->next;
			}
			return Second;
		}
	}
	else
		return NULL;
}


测试部分:   均为自定代码,,有什么错误,,求大神指点与交流。。

int main()
{
	node *start1 = new node;
	node *begin1,*begin2;
	start1->a = 6;
	start1->next = NULL;
	begin1 = start1;

	for(int i = 0;i<5;i++)
	{
		//start->a = i;

		node *next = new node;
		start1->next = next;
		next->a = i;
		next->next = NULL;
		start1 = next;
	}//第一个链表,头指针为begin1,元素为6,0,1,2,3,4;
	node *start2 = new node;
	start2->a = 10;
	begin2 = start2;
	for(int i = 5;i<10;i++)
	{
		node *next = new node;
		start2->next = next;
		next->a = i;
		next->next = NULL;
		start2 = next;
	}
	start2->next = begin1;//第二个链表,头指针为begin2,元素为10,5,6,7,8,9,6,0,1,2,3,4;
	//YesOrNo1(begin1,begin2);
	//YesOrNo2(begin1,begin2);
	//node *a = new node;
	//start1->next = begin1;//第二个链表形成环,,元素为6,0,1,2,3,4,6,0,1,2,3,4,6,。。。。。。同时第二个链表中也就包含了这个环
	//cout<<HaveRing(begin2);
	//start2->next = begin1;
	//cout<<YesOrNo3(begin1,begin2);//如果将上边的start2->next = begin1;语句去掉,即将第二个链表变为没有环的情况,则输出为0;
	//cout<<FirstNode(begin1,begin2)->a;

	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值