题目:①判断一个单向链表是否有环,如果有环则找到环的入口节点。 ②判断两个单向链表是否相交,如果相交则找到交点节点。

  淘宝的技术笔试题量不大,但是时间也很短(一个小时),基础题的难度还可以,后面的算法编程题就有点难度了,除非是之前做过类似的题目,否则在考场上用极其有限的时间很难做出来。下面和大家分享一道淘宝的编程题。

 

题目:①判断一个单向链表是否有环,如果有环则找到环的入口节点。

          ②判断两个单向链表是否相交,如果相交则找到交点节点。

算法思想:①用两个指针p1,p2同时指向链表的头部,p1一次移动一步,p2一次移动两步,如果最终p1和p2重合则说明链表有环,如果p2走到空指针(链表的结尾)则说明链表无环。如果最终p1和p2重合,使p2重新指向链表的头结点,然后p1和p2同时一次移动一步,当p1和p2再次重合时该节点指针就是环的入口节点指针。

                ②有了第一问的算法基础,应该不难理解第二问。首先将其中一个链表list1首尾相接,变成一个有环链表,如果另一个链表list2和list1相交的话,list2也将成为一个有环链表,并且环的入口节点就是两个链表的交叉节点。如果两个链表不相交,则list2依然是一个无环链表。

      下面是我用C++实现的程序代码,已经在visual C++6.0上运行通过了,程序中有详细的代码注释,这两个小问题在一个main函数中实现。程序代码中的不足之处还请大家多提宝贵意见。



#include <iostream>
using namespace std;

/*节点的类定义*/
class Node
{
public:
	int data;
	Node * next;
	Node(int data)
	{
		this->data=data;
	}
};

/*链表的类定义*/
class List
{
public:
	Node * head;//头结点指针
	Node * tail;//尾结点指针

	/*用一个整形数组作为参数的构造函数*/
	List(int array[],int length)
	{
		head=new Node(array[0]);
		Node * temp=head;
		int i;
		for(i=1;i<length;i++)
		{
			temp->next=new Node(array[i]);
			temp=temp->next;
		}
		temp->next=NULL;
		tail=temp;
	}

	/*查找指定位置的节点,并返回指向该节点的指针*/
	Node * FindNode(int index)
	{
		Node * temp=head;
		while(--index)
			temp=temp->next;
		return temp;
	}
};

/*判断链表是否有环,如果有环则返回环的首结点指针,否则返回NULL值*/
Node * FindCircle(List list)
{
	Node * p1,* p2;
	p1=list.head;
	p2=list.head;

	/*判断链表是否有环,当p1=p2时说明链表有环,程序跳出循环。如果p2一直走到链表尽头则说明没有环。*/
	do
	{
		if(p2->next!=NULL&&p2->next->next!=NULL)
		{
			p2=p2->next->next;
			p1=p1->next;
		}
		else
			return NULL;
	}
	while(p1!=p2);

	/*求出环的起点节点,并将其返回*/
	p2=list.head;
	while(p1!=p2)
	{
		p2=p2->next;
		p1=p1->next;
	}
	return p1;
}

/*判断两个链表是否交叉,如果交叉返回交叉节点,否则返回NULL。*/
Node * FindCross(List list1,List list2)
{
	list1.tail->next=list1.head;//将list1变成有环链表

	Node * p1,* p2;
	p1=list2.head;
	p2=list2.head;

	/*判断链表是否有环,当p1=p2时说明链表有环,程序跳出循环。如果p2一直走到链表尽头则说明没有环。*/
	do
	{
		if(p2->next!=NULL&&p2->next->next!=NULL)
		{
			p2=p2->next->next;
			p1=p1->next;
		}
		else
			return NULL;
	}
	while(p1!=p2);

	/*求出环的起点节点,并将其返回*/
	p2=list2.head;
	while(p1!=p2)
	{
		p2=p2->next;
		p1=p1->next;
	}
	return p1;
}

int main()
{
	/*构造一个有环链表,并查找环的起始节点*/
	int array[8]={1,2,3,4,5,6,7,8};
	List list(array,sizeof(array1)/sizeof(int));//构造一个链表
	list.tail->next=list.FindNode(5);//将该链表构造成一个有环链表
	Node * temp=FindCircle(list);//查找环的起始节点
	if(temp==NULL)
		cout<<"No cirle exists in the list."<<endl;
	else
		cout<<"There is a circle in the list , and the value of the join_point is "<<temp->data<<endl;

	/*构造两个链表,然后使这两个链表交叉。最后查找交叉节点。*/
	int array1[8]={1,2,3,4,5,6,7,8};
	int array2[5]={9,10,11,12,13};
	List list1(array1,sizeof(array1)/sizeof(int));//构造链表list1
	List list2(array2,sizeof(array2)/sizeof(int));//构造链表list2
	list2.tail->next=list.FindNode(3);//使这两个链表交叉
	temp=FindCross(list,list2);//查找这两个链表的交叉节点
	if(temp==NULL)
		cout<<"These two lists dose not cross."<<endl;
	else
		cout<<"These two lists cross with each other , and the value of the corss_point is "<<temp->data<<endl;
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值