一、建立双向链表
struct Node
{
int a;
struct Node* pNext;//后续指针
struct Node* pPre;//前驱指针
};
int main(void)
{
struct Node head = { 0 };
head.pNext = &head;
head.pPre = &head;
head.a = -1;
system("pause>0");
return 0;
}
a:节点的数据字段,存储整型值。pNext:指向下一个节点的指针。pPre:指向前一个节点的指针。- 初始化头节点
head,所有字段初始化为0。 head.pNext和head.pPre均指向自身,形成一个空的双向循环链表。head.a被赋值为-1,作为头节点的标记值。
尾添加
void AddToEnd(struct Node* head, int iData)//尾添加
{
//参数合法性检测
if (NULL == head)
return;
//申请节点
struct Node* pTemp = (struct Node*)malloc(sizeof(struct Node));
if (NULL == pTemp)
return;
pTemp->a = iData;
pTemp->pNext = NULL;
pTemp->pPre = NULL;
//链接
//先连
pTemp->pNext = head;
pTemp->pPre = head->pPre;
//后断
head->pPre->pNext = pTemp;
head->pPre = pTemp;
}
参数合法性检测
检查传入的头节点指针 head 是否为 NULL。如果是,函数直接返回,避免后续操作引发错误。
申请新节点
动态分配内存创建一个新节点 pTemp。如果内存分配失败(pTemp 为 NULL),函数直接返回。否则,初始化新节点的数据域 a 为 iData,并将前后指针 pNext 和 pPre 初始化为 NULL。
链接新节点
-
将新节点
pTemp的pPre指向头节点的前驱节点(即链表的尾节点)。 -
将新节点
pTemp的pNext指向头节点head。 -
将原尾节点的
pNext指向新节点pTemp。 -
将头节点的
pPre指向新节点pTemp,完成尾添加操作。
二、检测链表是否有环
bool QuiKSlow(struct Node* head)//检测链表是否有环
{
//参数合法性检测
if (NULL == head )
return false;
//快慢指针
struct Node* quik = head->pNext;//快指针
struct Node* slow = head->pNext;//慢指针
while (NULL != quik && NULL != quik->pNext)
{
slow = slow->pNext;
quik = quik->pNext->pNext;
if (slow == quik)
return true;
}
//链表无环
return false;
}
检测单向链表是否存在环。快指针每次移动两步,慢指针每次移动一步,若存在环,两者最终会相遇。
布尔(bool)
布尔(bool)是编程中的基本数据类型,表示逻辑值,仅有两种可能:true(真)或 false(假),头文件是<stdbool.h>。
执行逻辑
参数合法性检测
检查传入的头节点指针 head 是否为 NULL。如果是,函数返回false(假),避免后续操作引发错误。
循环遍历阶段
快指针每次移动两步quik = quik->pNext->pNext,慢指针每次移动一步slow = slow->pNext。每次移动后检查快慢指针是否相遇if (slow == quik),若相遇则存在环并返回true(真)。
终止条件
循环终止条件为快指针或其下一节点为NULL,表明链表已遍历完毕且未发现环,最终返回false。
检测:
让链表变成环,让尾节点的后续指针指向第二个节点,形成一个环。
head.pPre->pNext = head.pNext->pNext;
bool res = QuiKSlow(&head);

形成了一个环,检测函数返回了true表示有环状。