两个链表的相交和含有环的单链表

本文参考了http://www.cppblog.com/humanchao/archive/2008/04/17/47357.aspx

问题1:如何判断单链表有环

2:如果有环,在哪里有环的开始点

3 判断两个链表是否相交

问题一:

设置两个指针(fast, slow),初始值都指向头,slow每次前进一步,fast每次前进二步,如果链表存在环,则fast必定先进入环,而slow后进入环,两个指针必定相遇。(当然,fast先行头到尾部为NULL,则为无环链表)程序如下:LOOP_2

问题二:

二、找到环的入口点
当fast若与slow相遇时,slow肯定没有走遍历完链表,而fast已经在环内循环了n圈(1<=n)。假设slow走了s步,则fast走了2s步(fast步数还等于s 加上在环上多转的n圈),设环长为r,则:


2s = s + nr
s= nr


设整个链表长L,入口环与相遇点距离为x,起点到环入口点的距离为a。
a + x = nr
a + x = (n – 1)r +r = (n-1)r + L - a
a = (n-1)r + (L – a – x)


(L – a – x)为相遇点到环入口点的距离,由此可知,从链表头到环入口点等于(n-1)循环内环+相遇点到环入口点,于是我们从链表头、与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点。在函数的 LOOP_2

问题三:如果2个链表相交,可以判断最后元素相交否,如相交一定,相等;否则不等。程序如loop()。还可以把链head_1的尾和head_2的头相连,通过判断是否有环,来判断是否相交,找到环的入口点,找到2个链的交点  代码如 LOOP2

// 最短摘要的生成.cpp : 定义控制台应用程序的入口点。
//
/*author:songzhengchao
time:2013/11/6*/
#include "stdafx.h"
#include <iostream>
#include <vector>
using namespace std;
/*define the data struct for link */
typedef struct node
{
	struct node *next;
	int value;
}NODE;
/*construct the link head_1 1-->2-->6-->7-->8
head_2  3-->4-->6-->7-->8
*/
void make(NODE * &head_1,NODE * &head_2)
{
	int i;
	NODE *pre_1=head_1;
	NODE *p;
	for(i=1;i<=2;i++)
	{
		
		p=new NODE;
		p->next=NULL;
		p->value=i;
		pre_1->next=p;
		pre_1=p;
	}


	NODE *pre_2=head_2;
	NODE *q;
	for(i=3;i<=4;i++)
	{
		q=new NODE;
		pre_2->next=q;
		q->value=i;
		q->next=NULL;
		pre_2=q;
		
	}
	NODE *pre=new NODE ;
	for(i=6;i<=8;i++)
	{
		NODE *r=new NODE;
		r->next=NULL;
		r->value=i;
		if(i==6)
		{
			q->next=p->next=r;
			
			pre=r;
		}else
		{
			pre->next=r;
			pre=r;
		}
	}
}
/*打印元素*/
void print(NODE *head)
{
	 NODE *p=head->next;
	while(p!=NULL)
	{
		cout<<p->value<<" ";
		p=p->next;
	}
	cout<<"---end---"<<endl;
}
/*方法一 :如有相交,最后一个元素一定相等*/
bool loop(NODE *head_1,NODE *head_2)
{
	NODE *p=head_1;
	NODE *q=head_2;
	while(p->next)
	{
		p=p->next;
	}
	while(q->next)
	{
		q=q->next;
	}
	if(q==p){
		cout<<"exist the loop"<<endl;
		return true;
	}else
	{
		cout<<"can't exist loop"<<endl;
		return false;
	}
	
}
/*方法二:将一个串 head_1的尾部接入到head_2的头部**/
bool LOOP_2(NODE *head_1,NODE *head_2)
{
	NODE *p=head_1;
	while(p->next)
	{
		p=p->next;
	}
	NODE *q=head_2;
	p->next=q;
	int flag=0;//判断是否有环的标志
	NODE *fast,*slow;
	fast=slow=head_1;
	while(fast->next)
	{
		slow=slow->next;
		fast=fast->next->next;
		if(slow==fast)
		{
			flag=1;
			break;
			
		}
	}
	/*下面求交点,即环的开始点*/
	if(flag)
	{
	slow=head_1;
	while(slow!=fast)
	{
		slow=slow->next;
		fast=fast->next;
	}
	cout<<"相遇的节点为---->"<<slow->value<<endl;
	cout<<"exist loop "<<endl;
	return true;
	}
	else{
	cout<<"isn't exist loop"<<endl;
	return false;}

}

int _tmain(int argc, _TCHAR* argv[])
{
	NODE *head_1=new NODE;
	NODE *head_2=new NODE;
	head_1->next=NULL;
	head_2->next=NULL;
	make(head_1,head_2);
	print(head_2);

	loop(head_1,head_2);
	LOOP_2(head_1,head_2);
	return 0;
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值