双向循环链表(含空头)
双向循环链表呢,就是将尾结点指向头结点形成一个环形
本文主要是针对双向循环链表进行增、删、改、查操作
创建一个结构体当做节点
struct Node
{
int iData;
struct Node* pNext;
struct Node* pPre;
};
定义空头
//空头
struct Node stHead;
stHead.iData = 0;
stHead.pNext = &stHead;
stHead.pPre = &stHead;
int iCount = 0;
此处的pNext和pPre都指向空头,当然也可以置空,不过为了方便操作,就不置空了,iCount为计数器(记录节点的个数)
增加:1.尾添加
void AddToEnd(struct Node* stHead, int* iCount, int iData)
{
//参数合法性检测
if (NULL == stHead)
return;
//创建节点
struct Node* pTemp = (struct Node*)malloc(sizeof(struct Node));
//节点赋值
if (pTemp == NULL)
return;
pTemp->iData = iData;
pTemp->pNext = NULL;
pTemp->pPre = NULL;
//将节点连上去
//先连 将新节点连在指定位置
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 = CreateNode();
if (pTemp == NULL)
return;
pTemp->iData = iData;
//链接
//先连
pTemp->pPre = stHead;
pTemp->pNext = stHead->pNext;
//后断
stHead->pNext->pPre = pTemp;
stHead->pNext = pTemp;
//数量自加
(*iCount) += 1;
}
遍历链表
由于是双向循环链表,所以最后节点指向空头,遍历条件为 (pTemp != stHead)
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');
}
释放链表
void FreeList(struct Node* stHead, int* iCount)
{
//参数合法性检测
if (NULL == stHead || stHead->pNext == stHead)
return;
//循环遍历
struct Node* pTemp = NULL;
pTemp = stHead->pNext;
if (pTemp == NULL)
return;
while (pTemp != stHead)
{
//记录
struct Node* pT = NULL;
pT = pTemp;
if (pT == NULL)
return;
//向下走
pTemp = pTemp->pNext;
//释放记录
free(pT);
}
//数据清0
*iCount = 0;
stHead->pNext = stHead;
stHead->pPre = stHead;
}
释放链表记得指针要置空哈
并且计数器置零
查找:1.根据下标查询
由于每次都会用到创建节点代码,避免重复和浪费,咱们创建一个专门的函数
struct Node* CreateNode()
{
//创建节点
struct Node* pTemp = (struct Node*)malloc(sizeof(struct Node));
//节点赋值
if (pTemp == NULL)
return NULL;
pTemp->iData = 0;
pTemp->pNext = NULL;
pTemp->pPre = NULL;
return pTemp;
}
struct Node* GetNodeByIndex(struct Node* stHead, int iCount, int iIndex)
{
//参数合法性检测
if (NULL == stHead || iCount <= 0 || iIndex < 0 || iIndex >= iCount)
return NULL;
struct Node* pTemp = stHead->pNext;
if (pTemp == NULL)
return NULL;
for (int i = 0; i < iIndex; i++)
{
pTemp = pTemp->pNext;
}
return pTemp;
}
查找:2.根据数值查询
struct Node* GetNodeByData(struct Node* stHead, int iData)
{
//参数合法性检测
if (NULL == stHead || NULL == stHead->pNext)
return NULL;
struct Node* pTemp = stHead->pNext;
if (pTemp == NULL)
return NULL;
while (pTemp != stHead)
{
if (pTemp->iData == iData)
return pTemp;
pTemp = pTemp->pNext;
}
return NULL;
}
升级版添加:1.指定的下标位置添加
void InsertByIndex(struct Node* stHead, int* iCount, int iIndex, int iData)
{
//参数合法性检测
if (stHead == NULL || *iCount < 0 || iIndex < 0 || iIndex > *iCount)
return;
//1.尾添加
if (iIndex == *iCount)
AddToEnd(stHead, iCount, iData);
else
{
//找位置
struct Node* pTemp = GetNodeByIndex(stHead, *iCount, iIndex);
if (pTemp == NULL)
return;
//创建节点
struct Node* pT = (struct Node*)malloc(sizeof(struct Node));
if (pT == NULL)
return;
pT->iData = iData;
pT->pNext = NULL;
pT->pPre = NULL;
//链接
//先连
pT->pNext = pTemp;
pT->pPre = pTemp->pPre;
//后断
pTemp->pPre->pNext = pT;
pTemp->pPre = pT;
//数量自加
(*iCount) += 1;
}
}
升级版添加:2.指定数据位置添加节点
void InsertByData(struct Node* stHead, int* iCount, int iValue, int iData)
{
//参数合法性检测
if (stHead == NULL || *iCount <= 0)
return;
//循环找节点
struct Node* pTemp = GetNodeByData(stHead, iValue);
if (pTemp == NULL)
return;
//创建节点
struct Node* pT = (struct Node*)malloc(sizeof(struct Node));
if (pT == NULL)
return;
pT->iData = iData;
pT->pNext = NULL;
pT->pPre = NULL;
//链接
//先连
pT->pNext = pTemp;
pT->pPre = pTemp->pPre;
//后断
pTemp->pPre->pNext = pT;
pTemp->pPre = pT;
//数量自加
(*iCount) += 1;
}
升级版添加:3.在指定下标位置插入N个节点
void InsertSomeByIndex(struct Node* stHead, int* iCount, int iIndex, int iData, int iNodeCount)
{
//参数合法性检测
if (stHead == NULL || *iCount < 0 || iIndex < 0 || iIndex > *iCount)
return;
for (int i = 0; i < iNodeCount; i++)
{
InsertByIndex(stHead, iCount, iIndex, iData);
}
}
删除:1.根据下标删除指定节点
void DeleteByIndex(struct Node* stHead, int* iCount, int iIndex)
{
//参数合法性检测
if (stHead == NULL || *iCount <= 0 || iIndex < 0 || iIndex >= *iCount)
return;
//循环找节点
struct Node* pTemp = GetNodeByIndex(stHead, *iCount, iIndex);
if (pTemp == NULL)
return;
//删除
pTemp->pPre->pNext = pTemp->pNext;
pTemp->pNext->pPre = pTemp->pPre;
free(pTemp);
//数量--
(*iCount)--;
}
删除:2.根据下标删除一段节点
void DeleteSomeByIndex(struct Node* stHead, int* iCount, int iIndex1, int iIndex2)
{
//参数合法性检测
if (stHead == NULL || *iCount <= 0 || iIndex1 < 0 || iIndex2 >= *iCount)
return;
删除下标之间节点
//for (int i = iIndex1; i <= iIndex2; i++)
//{
// DeleteByIndex(stHead, iCount, iIndex1 + 1);
// iIndex2--;
//}
//删除下标之间节点(包括下标处节点)
for (int i = iIndex1; i <= iIndex2 + i - 1; i++)
{
DeleteByIndex(stHead, iCount, iIndex1);
iIndex2--;
}
}
删除:3.根据数据删除所有一样的数据
void DeleteByData(struct Node* stHead, int* iCount, int iData)
{
//参数合法性检测
if (stHead == NULL || *iCount <= 0)
return;
while (1)
{
//找节点
struct Node* pTemp = GetNodeByData(stHead, iData);
if (pTemp == NULL)
return;
//删除
pTemp->pPre->pNext = pTemp->pNext;
pTemp->pNext->pPre = pTemp->pPre;
free(pTemp);
//数量--
(*iCount)--;
}
}
有些简单的大家看前面那个双向链表操作基本上一样,欢迎大家指正错误~