剑指offer-23:链表中环的入口结点

本文介绍了一种在链表中检测环并找到环入口的方法。通过快慢指针判断链表是否存在环,再利用双指针技巧定位环的入口结点。文章提供了详细的算法步骤和C语言实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如果一个离岸边表中包含环,如何找出环的入口结点?
本文有关链表结点结构体定义以及其它方法接口定义如下:

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef   int DataType;

typedef struct ListNode{
	DataType data;
	struct  ListNode *next;
} ListNode;



void  ListInit(ListNode **ppfirst)
{
	assert(ppfirst != NULL);
	*ppfirst = NULL;
}

void ListDestory(ListNode **ppfirst)
{
	*ppfirst = NULL;
}
static ListNode *CreateNode(DataType  data)
{
	ListNode *newNode = (ListNode*)malloc(sizeof(ListNode));
	assert(newNode);
	newNode->data = data;
	newNode->next = NULL;
	return newNode;
}

首先确定链表中是否包含环。定义两个指针pFast和pSlow,pSlow一次走一步,pFast指针一次走两步。如果走pFast指针追上了走得慢的指针pSlow,那么链表中就包含环。若pFast指针走到链表末尾都未能追到走pSlow,则链表中不包含环。

如果链表中有环,接下来需要确定环的入口。指定两个指pNode1和pNode2都指向链表的头结点。假设链表中有n个结点,先让pNode1向后移动n步,然后两个指针一块移动。当pNode1==pNode2时,此时两个个指针都指向环入口结点。

代码如下:

//判断链表中是否有环
ListNode * MeetNode(ListNode* pHead)
{
	if (pHead == NULL)
	{
		return NULL;
	}
	ListNode * pSlow = pHead->next;
	ListNode *pFast = pSlow->next;
	while (pFast != NULL&&pSlow != NULL)
	{
		if (pFast == pSlow)
		{
			return pFast;
		}
		pSlow = pSlow->next;
		pFast = pFast->next;
		if (pFast != NULL)
		{
			pFast = pFast->next;
		}
	}
	return NULL;

}
ListNode *EntryNode(ListNode * pHead)
{
	ListNode * meetingNode = MeetNode(pHead);
	//如果链表中五环则返回NULL
	if (meetingNode == NULL)
		return NULL;
	//确定环中结点数目
	int nodeLoop = 1;
	ListNode* pNode1 = meetingNode;
	while (pNode1->next != meetingNode)
	{
		pNode1 = pNode1->next;
		nodeLoop++;
	}
	//先移动pNode1
	pNode1 = pHead;
	for (int i = 0; i < nodeLoop; ++ i)
	{
		pNode1 = pNode1->next;
	}
	//同时移动pNode1和pNode2
	ListNode* pNode2 = pHead;
	while (pNode1 != pNode2)
	{
		pNode1 = pNode1->next;
		pNode2 = pNode2->next;
	}
	return pNode1;
}

测试代码如下:

//尾插法
void    ListPushBack(ListNode **ppfirst, DataType data)
{
	ListNode *newNode = CreateNode(data);
	if (*ppfirst == NULL)
	{
		*ppfirst = newNode;
		return;
	}
	ListNode *cur = *ppfirst;
	while (cur->next != NULL)
	{
		cur = cur->next;
	}
	cur->next = newNode;
}
//查找结点
ListNode   *ListFind(ListNode *first, DataType data)
{
	for (ListNode *cur = first; cur != NULL; cur = cur->next)
	{
		if (data == cur->data)
			return cur;
	}
	return NULL;
}
//构造有环的链表
void CreateLoop(ListNode **pfirst)
{
	ListNode *str = ListFind(*pfirst, 3);
	ListNode *cur = *pfirst;
	//ListNode *str = cur->next->next;
	while (cur->next != NULL)
	{
		cur = cur->next;
	}
	cur->next = str;
}
int main()
{
	ListNode *list1;
	ListInit(&list1);
	ListPushBack(&list1, 1);
	ListPushBack(&list1, 2);
	ListPushBack(&list1, 3);
	ListPushBack(&list1, 4);
	ListPushBack(&list1, 5);
	CreateLoop(&list1);
	ListNode *m = EntryNode(list1);
	system("pause");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值