如果一个离岸边表中包含环,如何找出环的入口结点?
本文有关链表结点结构体定义以及其它方法接口定义如下:
#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;
}