前言
双向循环链表是链表的一种特殊形式,每个节点包含两个指针域:pPre指向直接前驱节点,pNext指向直接后继节点。链表的头节点的pPre指向尾节点,尾节点的pNext指向头节点,形成一个闭环。
一、建立链表
代码:
struct Node
{
int iData;
struct Node* pNext;
struct Node* pPre;
};
iData:存储节点的整型数据。pNext:指向下一个节点的指针。pPre:指向前一个节点的指针。
int main(void)
{
struct Node stHead = {0};
stHead.iData = 0;
stHead.pNext = &stHead;
stHead.pPre = &stHead;
int iCount = 0;
system("pause > 0");
return 0;
}
- 初始化头节点
stHead,数据域iData设为 0。 pNext和pPre均指向自身,形成一个环状结构。
二、添加节点
1、尾添加
代码:
void AddToEnd(struct Node* stHead, int* iCount, int iData)//尾添加
{
//参数合法性检测
if (NULL == stHead)
return;
//创建节点
struct Node* pTemp = (struct Node*)malloc(sizeof(struct Node));
if (NULL == pTemp)
return;
//节点赋值
pTemp->iData = iData;
pTemp->pNext = NULL;
pTemp->pPre = NULL;
//将节点连上去
//先连,将新节点接在指定位置上
pTemp->pNext = stHead;
pTemp->pPre = stHead->pPre;
//后断
stHead->pPre->pNext = pTemp;
stHead->pPre = pTemp;
//数量++
*iCount += 1;
}
实现双向循环链表的尾部节点添加操作。参数包括链表头节点指针stHead、节点计数器指针iCount和待插入数据iData。
步骤:
参数合法性检测
检查链表头节点是否为空指针,若为空直接返回,避免非法访问。
新节点创建与初始化
动态分配新节点内存并检查分配结果,若分配失败直接返回,初始化新节点的数据和指针域。
链表连接逻辑
将新节点插入到尾节点位置:
先将新节点接在指定位置,然后断开原尾节点和头节点的连接。
必须先断开原尾节点指向头节点,再断开头节点指向原尾节点。
-
新节点前驱指向尾节点:
pTemp->pPre = stHead->pPre -
新节点后继指向头节点:
pTemp->pNext = stHead -
原尾节点后继指向新节点:
stHead->pPre->pNext = pTemp -
头节点前驱指向新节点:
stHead->pPre = pTemp
节点计数更新
通过指针修改外部计数器 *iCount += 1。
2、头添加
代码:
void AddToHead(struct Node* stHead, int* iCount, int iData)//头添加
{
//参数合法性检测
if (NULL == stHead)
return;
//创建节点
struct Node* pTemp = (struct Node*)malloc(sizeof(struct Node));
if (NULL == pTemp)
return;
//节点赋值
pTemp->iData = iData;
pTemp->pNext = NULL;
pTemp->pPre = NULL;
//链接
//先连
pTemp->pPre = stHead;
pTemp->pNext = stHead->pNext;
//后断
stHead->pNext->pPre = pTemp;
stHead->pNext = pTemp;
//数量++
*iCount += 1;
}
实现双向链表的头部插入操作,参数包括链表头节点指针stHead、节点计数器指针iCount以及待插入数据iData。
步骤:
参数合法性检测
检查链表头节点是否为空指针,若为空直接返回,避免非法访问。
新节点创建与初始化
动态分配新节点内存并检查分配结果,若分配失败直接返回,初始化新节点的数据和指针域。
链表插入操作
先将新节点接在指定位置,然后断开头节点和原第一个节点的连接。
必须先断开原第一个节点指向头节点,再断开头节点指向原第一个节点。
-
新节点前驱指向头节点:
pTemp->pPre = stHead -
新节点前驱指向原第一个节点:
pTemp->pNext = stHead->pNext -
原第一个节点后继指向新节点:
stHead->pPre->pNext = pTemp -
头节点后继指向新节点:
stHead->pPre = pTemp
节点计数更新
通过指针修改外部计数器 *iCount += 1。
三、遍历链表
代码:
void Look(struct Node* stHead, int iCount)//遍历
{
//参数合法性检测
if (NULL == stHead || stHead->pNext == stHead)
return;
//循环遍历
printf("节点个数共有%d个: ", iCount);
struct Node* pTemp = stHead->pNext;
while (pTemp != stHead)
{
printf("%d ", pTemp->iData);
pTemp = pTemp->pNext;
}
putchar('\n');
}
实现了一个循环链表的遍历功能,输出链表中所有节点的数据值及节点个数。
步骤:
参数合法性检查
确认头节点不为空且链表非空(头节点的下一个节点不是自己)
循环遍历
遍历过程从第一个有效节点开始(stHead->pNext),通过while循环依次访问每个节点,每个节点的数据通过printf输出,直到再次遇到头节点为止,最后用putchar输出换行符
调用:
先尾添加,后头添加。
AddToEnd(&stHead, &iCount, 4);
AddToEnd(&stHead, &iCount, 5);
AddToEnd(&stHead, &iCount, 6);
Look(&stHead, iCount);
AddToHead(&stHead, &iCount, 1);
AddToHead(&stHead, &iCount, 2);
AddToHead(&stHead, &iCount, 3);
Look(&stHead, iCount);
