判断链表是否含有环,若有则找出环的入口节点

可以简单的通过一个“快指针”和一个“慢指针”来实现:

#include <stdio.h>
#include <stdlib.h>

#define bool int
#define false 0
#define true 1

struct lis
{
	int MyData;
	struct lis * MyNext;
};

//判断链表是否含有环
bool HasLoopOrNot(struct lis * ls)
{
	bool bResult = false;
	struct lis *fast = ls;
	struct lis *slow = ls;

	while ((fast != NULL)  && (fast->MyNext != NULL) && (fast->MyNext->MyNext != NULL))
	{
		fast = fast->MyNext->MyNext;
		slow = slow->MyNext;

		if (fast==slow)
		{
			return true;
		}
	}

	return false;
}

//如果存在环,则返回环的入口节点
struct lis * EnterNode(struct lis *ls)
{
	struct lis *fast = ls;
	struct lis *slow = ls;
	while ((fast!=NULL)&&(fast->MyNext!=NULL)&&(fast->MyNext->MyNext))
	{
		fast = fast->MyNext->MyNext;
		slow = slow->MyNext;

		if (fast==slow)//相遇,存在环
		{
			break;
		}
	}

	//算法思想:
	/******************
	当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)循环内环 + 相遇点到环入口点,
	于是我们从链表头、与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点。
	******************/


	//fast停在第一个相遇点
	slow = ls;//slow重新指向链表的第一个节点
	while (slow!=fast)
	{
		fast = fast->MyNext;
		slow = slow->MyNext;
	}
	return slow;//或者return fast;
}


int main()
{
	struct  lis *node1 = calloc(sizeof(struct lis), 1);
	struct  lis *node2 = calloc(sizeof(struct lis), 1);
	struct  lis *node3 = calloc(sizeof(struct lis), 1);
	struct  lis *node4 = calloc(sizeof(struct lis), 1);
	struct  lis *node5 = calloc(sizeof(struct lis), 1);
	struct  lis *node6 = calloc(sizeof(struct lis), 1);
	struct  lis *node7 = calloc(sizeof(struct lis), 1);
	struct  lis *node8 = calloc(sizeof(struct lis), 1);
	struct  lis *node9 = calloc(sizeof(struct lis), 1);

	node1->MyNext = node2;
	node2->MyNext = node3;
	node3->MyNext = node4;
	node4->MyNext = node5;
	node5->MyNext = node6;
	node6->MyNext = node7;
	node7->MyNext = node8;
	node8->MyNext = node9;
	
	node9->MyNext = node4;//含有环
	//node9->MyNext = NULL;//不含环

	node1->MyData = 2001;
	node2->MyData = 2002;
	node3->MyData = 2003;
	node4->MyData = 2004;
	node5->MyData = 2005;
	node6->MyData = 2006;
	node7->MyData = 2007;
	node8->MyData = 2008;
	node9->MyData = 2009;

	bool br = HasLoopOrNot(node1);
	if (br)
	{
		printf("含有环\n");
	}
	else
		printf("not含有环\n");

	printf("---------------------------------------\n");

	struct lis * enter = EnterNode(node1);
	
	printf("入口节点的值是:%d\n", enter->MyData);

	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值