链表带环问题1

给出一个链表;

1.判断其是否带环?

2.如果带环求环的长度?

3.求环的入口节点?

解题思路:

用两个指针,快指针一次走两步,慢指针一次走一步,如果两指针相遇,那么链表带环,若两指针不相遇,则链表不带环。

带环的几种情况:


Node* List::find_meet_node(Node* Head)
	{
		if(Head==NULL)
			return NULL;
		if(Head->_next ==Head)
			return Head;
		Node* entry=NULL;
		Node* fast=Head;
		Node* slow=Head;
		while(fast)
		{
			fast=fast->_next ->_next ;
			slow=slow->_next ;
			if(fast==slow)
				return fast;
		}
		return NULL;
	}
void List::IsHasRing(Node* Head)
{
	Node* ret=find_meet_node(Head);
	if(ret==NULL)
		cout<<"no ring"<<endl;
	else
		cout<<"have a ring"<<endl;
}



扫描二维码关注公众号,回复: 2239944 查看本文章

2.求环的长度:

解题思路:

面试题1已经判断过链表带环,且返回两指针相遇节点,求环长度时我们可以让一个指针从相遇节点处开始遍历,当再次回到相遇节点时,它走过的步数就是环的长度。

int List::ring_len(Node* meet)
	{
		if(meet==NULL)
			return 0;
		Node* cur=meet->_next ;
		int len=1;
		while(cur!=meet)
		{
			cur=cur->_next;
		    len++;
		}
		return len;
	}


3.求环的入口节点:

方法一:假设上图是一个单链表,两指针走到相遇节点时,慢指针走了L+X步,快指针走了L+X+nC步,(l为环的长度),由于快指针速度是慢指针速度的一倍,那么就有以下的等式:
(L+X)*2=L+X+nC;化解可得:L=nC-X;

那解题时我们可以用两个指针,一个指针从链表的开始位置走,另一个指针从相遇的节点处开始走,也就是y,两个指针相遇的节点就是入口点。


Node* List::find_entry(Node* Head,Node* meet)
{
	if(meet==NULL)
		return NULL;
	Node* prev=Head;
	Node* post=meet;
	while(prev!=post)
	{
		prev=prev->_next ;
		post=post->_next ;
	}
	return prev;
}

方法二:将相遇的节点处断开,转化为两条链表相交求交点问题,两个指针meet和Entry分别遍历到链表尾,记录两链表的长度len_l1和len_l2,然后让较长的链表先走len=|len_l1 - len_l2|步,然后两指针一起走,直到两指针相遇,相遇的节点就是链表的交点,即环的入口点。


Node* List::find_entry(Node* Head,Node* meet)
{
 pLinkNode Entry = head;
 pLinkNode meet = MeetNode->next;
 int len_head = 0;
 int len_meet = 0;
 int len = 0;
 while (Entry != MeetNode) //求链表长度
 {
  len_head++;
  Entry = Entry->next;
 }
 while (meet != MeetNode)//求链表长度
 {
  len_meet++;
  meet = meet->next;
 }
  Entry = head;
  meet = MeetNode->next;
 if (len_head > len_meet)  
 {
  len = len_head - len_meet;
  while (len--)
  {
   Entry = Entry->next;
  }//较长链表先走len=|len_l1 - len_l2|步
 }
 else
 {
  len = len_meet - len_head;
  while (len--)
  {
   meet = meet->next;
  }//较长链表先走len=|len_l1 - len_l2|步
 }
 while (meet != Entry)
 {
  Entry = Entry->next;
  meet = meet->next;
 } //两指针同时走,相遇节点就是环入口点
 return Entry;
}



测试运行结果:

测试用例:

void test3()//测试是否带环
{
	List l;

	Node* node1=new Node(0);
	Node* node2=new Node(1);
	Node* node3=new Node(2);
	Node* node4=new Node(3);
	Node* node5=new Node(4);
	Node* node6=new Node(5);
	Node* node7=new Node(6);

	node1->_next =node2;
	node2->_next =node3;
	node3->_next =node4;
   	node4->_next =node5;
	node5->_next =node6;
	node6->_next =node5;
    l.IsHasRing(node1);
	Node* meet=l.find_meet_node(node1);
	cout<<"meet:"<<meet->_data <<endl;
	int len=l.ring_len(meet);
	cout<<"length:"<<len<<endl;
	Node* entry=l.find_entry(node1,meet);
	cout<<"entry:"<<entry->_data <<endl;
	
	
}

运行结果:


到此结束!









猜你喜欢

转载自blog.csdn.net/wodeqingtian1234/article/details/75175244