怎样判断链表是否相交

         关于数据结构的知识经常是互联网公司面试的重点内容,而对于链表的考察更是重中之重。经常会问到单链表中关于是否相交是否存在环的问题,笔者不才,自己想出一种方法。看到其他博客所写的规律,很难理解,并且缺乏证明。让我们一起来看看这个高频率的考点。

1、判断链表是否相交,并且返回一个相交的节点。

链表是否相交,并不是你想的两条线相交的样子,一般考察的是链表只有一个next域的单链表。那就简单了许多。你可以想象两个人从两条路出发,最终走到一条路的情景。最形象的例子就是你衣服上的拉链了。因为只有一个next域,所以只要链表相交,从相交的那个节点开始,从该节点以后的所有的节点都是公共节点。请注意:data域相等并不是链表相交的判断条件,所以将链表的data和链表A交B所结合的思路都是错的。审题清楚了,怎样判断呢!

      突破口就在这里:从相交的那个节点开始,从该节点以后的所有的节点都是公共节点。那我们是不是可以只看每个链表最后那个节点是不是公共节点呢!如果不是公共节点,那链表不想交,如果是,那就是链表相交。

怎样返回第一个节点呢!要想找到第一个节点,用蛮力法,那就是一个链表做模板,另一个链表每次都遍历一次,时间复杂度太高,不能让面试官满意。相交最好的情况就是链表是对称的。两个指针同时走,p = q 时候那就是第一个节点了。可惜事实并非完美。但是我们可以构造一个逻辑上接近完美的最好情况。如果我们想象把长的链表多余的部分去掉就好办了,那必须要知道链表的长度。接着上步,判断链表是否相交,找各自指向链表的两个指针一定得滑到最后一个节点,我们定义两个计数的变量来记录两个链表的长度。然后再次让指针从各自链表的开头开始走。只不过不是同时走。我们已经知道了链表的长度,找到比较长的链表,先用for循环让指向头结点的指针向前滑动m-n个节点。然后再同时滑动。就是构造了最好的情况。只需要两次遍历链表,不但可以知道是否相交,而且可以返回第一个相交的节点。如下图所示:

函数实现

Node *Fisrt_Node (List plist, List qlist) //返回相交的一个节点,如果返回为NULL,则没有交点
{                                        
	 if(qlist == NULL || plist == NULL) //如果有一个链表为空,则两条链表不相交,                  
	 {
		 return NULL;
	 }
	List p = plist->next;                       
	List q = qlist->next;//定义两个指向链表的指针

	int n = 0;
	int m = 0;//定义两个计数器,分别计数两个链表的长度。
	while (p->next != NULL)
	{
		n++;
		p = p->next;
	}

	while (q->next != NULL)
	{
		m++;
		q = q->next;
	}

	if ( p != q)//判断是否有公共节点,不能用数据域data判断。
	{
		return NULL;//没有相交,返回为NULL
	}
	if (m == n)//最好的情况,m = n;两个指向链表的指针p,q同时滑动,当P = q时;此节点为相交的第一个节点;返回即可
	{
		q = qlist;
		p = plist;
		while ( p != q)//p 和 q同时走
		{
			p = p->next;
			q = q->next;
		}

		return p;
	}
	else if (m>n)//两条链表不一样长,
	{
		int i=0;
		for (q = qlist; i<m-n; i++)//指向长的链表的指针先走m-n个节点,然后就构造了理想的最好情况,剩下的两条链表一样长了
		{
			q = q->next;
		}
		p = plist;
		while ( p != q)
		{
			p = p->next;
			q = q->next;
		}
		return p;
	}

	else 
	{
		int i=0;
		for (q = qlist; i<n-m; i++)
		{
			q = q->next;
		}
		q = qlist;
		while ( p != q)
		{
			p = p->next;
			q = q->next;
		}
		return p;
	}
}
至于判断是否有交点的函数,请读者自己写,只要明白返回节点的函数,很简单就能判断是否相交。饮水思源。点个赞吧!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值