单项循环链表
将单项非循环链表尾结点的指针域指向头结点即为单项循环链表。
一、单项循环链表结点数据类型
//数据节点
typedef struct Node
{
int dat;//结点值
struct Node *pNext;//下一个结点
}Node, *pNode;
//Node 等效于 struct Node
//*pNode 等效于 struct Node *
二、创建单项循环链表
1.为单项循环链表头结点申请内存。
2.将头结点指针域指向头结点本身,即创建成功单项循环链表。
3.头结点数据域为零,表示单项循环链表有效节点个数。
注意:单项循环链表头结点存在的目的是方便操作链表,亦可不使用头结点。
如下图所示:
//创建单项循环链表
Node * pCreat_sCircleLink(void)
{
Node * pHeadNode = NULL;//头结点指针
pHeadNode = (Node *)malloc(sizeof(Node));//为头结点申请内存
if (pHeadNode == NULL)
{
printf("头结点申请内存失败,程序终止......\r\n");
while (1);
}
pHeadNode->pNext = pHeadNode;//指向自身
pHeadNode->dat = 0;//节点数为0
printf("创建单项循环链表成功......");
printf("头结点:0x%08X 指针域:0x%08X 节点数:%d\r\n", pHeadNode, pHeadNode->pNext, pHeadNode->dat);
return pHeadNode;
}
三、判断单项循环链表是否为空’
当单项循环链表头结点的数据域为零,且指针域指向头结点本身,则表示链表为空。
如下图所示:
//判断单项循环链表是否为空
bool IsEmpty_sCircleLink(Node * pHeadLink)
{
//节点数为零且指针域为自身
if ((!pHeadLink->dat) && (pHeadLink->pNext == pHeadLink))
return true;
else
return false;
}
四、寻找单项循环链表尾结点
结点指针域指向头结点的结点为尾结点。
1.获取头结点指针。
2.其指针域不等于链表头结点继续寻找。
3.移动指针,指向下一个结点。
//寻找单项循环链表尾结点
Node * SearchRearNode_sCircleLink(Node * pHeadLink)
{
Node * pNode = NULL;//尾结点指针
pNode = pHeadLink;//头结点指针
while (pNode->pNext != pHeadLink)
pNode = pNode->pNext;//下个结点
return pNode;
}
五、向单项循环链表追加数据
在单项循环链表尾结点后添加新的结点。
1.获取链表尾结点指针。
2.为新加入的结点申请内存。
3.尾结点指针域指向新加入的结点。
4.新加入的结点指针域指向头结点。
5.新结点数据为追加的数据值。
如下图所示:
//向单项循环链表追加数据
void Append_sCircleLink(Node * pHeadLink, int value)
{
Node * pRearNode = NULL;//尾结点指针
Node * pNewNode = NULL;//新结点指针
pNewNode = (Node *)malloc(sizeof(Node));//为新结点申请内存
if (pNewNode == NULL)
{
printf("新结点内存失败......\r\n");
return;
}
pRearNode = SearchRearNode_sCircleLink(pHeadLink);//寻找单项循环链表尾结点
if (pRearNode == NULL)
{
printf("无效尾结点......\r\n");
return;
}
pRearNode->pNext = pNewNode;//尾结点指向新结点
pNewNode->pNext = pHeadLink;//新结点指向头结点,即为尾结点
pNewNode->dat = value;//追加值
pHeadLink->dat++;//链表结点数量自加
printf("追加数据成功......");
printf("上结点:0x%08X\t本结点:0x%08X\t指针域:0x%08X\t节点数:%d\t追加值:%d\r\n", pRearNode, pNewNode, pNewNode->pNext, pHeadLink->dat, value);
}
六、向单项循环链表头结点追加数据
向单项循环链表头结点后添加新的结点。
1.为新加入的结点申请内存。
2.新结点指针域为头结点指针域。
3.头结点指针指向新加入的结点。
4.新结点数据域为追加的数据值。
如下图所示:
//向单项循环链表头结点追加数据
void AppendHeadNode_sCircleLink(Node * pHeadLink, int value)
{
Node * pNewNode = NULL;//新结点指针
pNewNode = (Node *)malloc(sizeof(Node));//为新结点申请内存
if (pNewNode == NULL)
{
printf("新结点内存失败......\r\n");
return;
}
pNewNode->pNext = pHeadLink->pNext;//新节点为第一个有效结点
pHeadLink->pNext = pNewNode;//头结点指向新节点
pNewNode->dat = value;//追加值
pHeadLink->dat++;//链表结点数量自加
printf("头结点追加数据成功......");
printf("头指域:0x%08X\t本结点:0x%08X\t指针域:0x%08X\t节点数:%d\t追加值:%d\r\n", pHeadLink->pNext, pNewNode, pNewNode->pNext, pHeadLink->dat, value);
}
七、向单项循环链表某处插入数据
1.寻找插入位置之前的结点指针(尾结点指针)。
2.为新加入的结点申请内存。
3.新结点指针域指针尾结点指针域。
4.尾结点指针域指向新结点。
5.新节点数据域为插入的数据。
6.链表结点数加一。
注意:
1. 向单项循环链表某处插入新结点,头结点后为开始位置,默认为1。
如下图所示:
//向单项循环链表某处插入数据
void Insert_sCircleLink(Node * pHeadLink, int pos, int value)
{
Node * pNewNode = NULL;//新结点指针
Node * pRearNode = NULL;//尾结点指针
int i = 0;
//判断插入位置的合法性
if ((pHeadLink == NULL) || (pos < 1) || (pos > (pHeadLink->dat + 1)))
{
printf("插入位置无效......\r\n");
return;
}
//寻找插入点之前的有效位置(尾结点)
pRearNode = pHeadLink;//头结点指针
while ((pRearNode->pNext != pHeadLink) && (i < (pos - 1)))
{
pRearNode = pRearNode->pNext;
i++;
}
pNewNode = (Node *)malloc(sizeof(Node));//为新结点申请内存
if (pNewNode == NULL)
{
printf("新结点内存失败......\r\n");
return;
}
pNewNode->pNext = pRearNode->pNext;//新节点指向尾结点后个结点
pRearNode->pNext = pNewNode;//新结点插入尾结点之后
pNewNode->dat = value;//插入值
pHeadLink->dat++;//链表结点数量自加
printf("插入数据成功......");
printf("上结点:0x%08X\t本结点:0x%08X\t指针域:0x%08X\t节点数:%d\t位置:%d\t 插入值:%d\r\n", pRearNode, pNewNode, pNewNode->pNext, pHeadLink->dat, pos, value);
}
八、删除单项循环链表某处结点
1.判断删除位置为有效位置。
2.寻找删除位置之前的结点,称为尾结点,删除尾结点之后的结点即可。
4.保存将要删除的结点指针。
5.尾结点指针指向下一个结点的下一个结点。
6.保存删除结点的数据。
7.释放删除结点内存。
8.链表结点数减一。
注意:
1. 删除单项循环链表某处结点,头结点后为开始位置,默认为1。
如下图所示:
//删除单项循环链表某处数据
int Delete_sCircleLink(Node * pHeadLink, int pos)
{
Node * pRearNode = NULL;//尾结点指针
Node * pNode = NULL;//结点指针
int value = 0;
int i = 0;
//判断删除位置的合法性
if ((pHeadLink == NULL) || (pos < 1) || (pos > pHeadLink->dat))
{
printf("删除位置无效......\r\n");
return value;
}
//寻找删除点之前的有效位置(尾结点)
pRearNode = pHeadLink;//头结点指针
while ((pRearNode->pNext != pHeadLink) && (i < (pos - 1)))
{
pRearNode = pRearNode->pNext;
i++;
}
pNode = pRearNode->pNext;//将删除的结点
pRearNode->pNext = pNode->pNext;//指向将删除结点的下个结点
value = pNode->dat;//将删除的结点值
free(pNode);//释放删除结点内存
pHeadLink->dat--;//链表结点数量自减
printf("删除数据成功......");
printf("上结点:0x%08X\t指针域:0x%08X\t本结点:0x%08X\t节点数:%d\t删除值:%d\r\n", pRearNode, pRearNode->pNext, pNode, pHeadLink->dat, value);
return value;
}
九、删除单项循环链表尾部数据
1.链表非空时才可删除尾部结点。
2.获取第一个有效结点指针。
3.寻找尾结点之前的第一个有效结点,另称为尾结点。
4.保存要删除的结点指针。
5.尾结点指针指向下一个结点的指针域。
6.获取将要删除的结点数据。
7.释放将要删除的结点内存。
8 链表结点数减一。
如下图所示:
//删除单项循环链表尾部数据
int DeleteEnd_sCircleLink(Node * pHeadLink)
{
Node * pRearNode = NULL;//尾结点指针
Node * pNode = NULL;//结点指针
int value = 0;
int i = 0;
if (IsEmpty_sCircleLink(pHeadLink))//判断单项循环链表是否为空
{
printf("空链表......\r\n");
return value;
}
//寻找删除点之前的有效位置(尾结点)
pRearNode = pHeadLink;//头结点指针
while ((pRearNode->pNext != pHeadLink) && (i < (pHeadLink->dat - 1)))
{
pRearNode = pRearNode->pNext;
i++;
}
pNode = pRearNode->pNext;//将删除的结点
pRearNode->pNext = pNode->pNext;//尾结点指向删除后的结点
value = pNode->dat;//将删除的结点值
free(pNode);//释放删除结点内存
pHeadLink->dat--;//链表结点数量自减
printf("删除数据成功......");
printf("上结点:0x%08X\t指针域:0x%08X\t本结点:0x%08X\t节点数:%d\t删除值:%d\r\n", pRearNode, pRearNode->pNext, pNode, pHeadLink->dat, value);
return value;
}
十、清空单项循环链
1.获取第一个有效结点。
2.获取去有效结点指针域,即指向下下个结点。
3.释放结点内存。
4.链表结点数加一。
5.直到为头结点为此,或者链表为空为此。
如下图所示:
//清空单项循环链
void Clear_sCircleLink(Node * pHeadLink)
{
Node * delNode = NULL;//删除结点指针
int i = 0;
for (i = 0; i < pHeadLink->dat; )
{
delNode = pHeadLink->pNext;//第一个有效结点
pHeadLink->pNext = delNode->pNext;//头结点指针域指向下个有效结点
pHeadLink->dat--;//结点数自减
free(delNode);//释放结点内存
}
printf("清空链表成功......");
printf("头结点:0x%08X\t指针域:0x%08X\t节点数:%d\r\n", pHeadLink, pHeadLink->pNext, pHeadLink->dat);
}
十一、显示单项循环链表结点数据
//显示单项循环链表结点数据
void Show_sCircleLink(Node * pHeadLink)
{
Node * pNode = NULL;//结点指针
if (IsEmpty_sCircleLink(pHeadLink) == true)
{
printf("单项循环链表为空......\r\n");
return;
}
printf("循环链表结点数据:");
pNode = pHeadLink->pNext;//第一个有效结点
while(pNode != pHeadLink)//不为头结点
{
printf("%d ", pNode->dat);//结点数据
pNode = pNode->pNext;//下一个结点
}
printf("\r\n");
}
十二、获取单项循环链表的结点数
//获取单项循环链表的结点数
int GetCount_sCircleLink(Node * pHeadLink)
{
return pHeadLink->dat;
}
十三、代码验证演示
void main(void)
{
Node * pHeadLink = NULL;//头结点指针
pHeadLink = pCreat_sCircleLink();//创建单项循环链表
printf("\r\n");
Append_sCircleLink(pHeadLink, 100);//向单项循环链表追加数据
Append_sCircleLink(pHeadLink, 200);
Append_sCircleLink(pHeadLink, 300);
Append_sCircleLink(pHeadLink, 400);
Append_sCircleLink(pHeadLink, 500);
Append_sCircleLink(pHeadLink, 600);
Show_sCircleLink(pHeadLink);//显示单项循环链表结点数据
printf("\r\n");
AppendHeadNode_sCircleLink(pHeadLink, 10);//向单项循环链表头结点追加数据
AppendHeadNode_sCircleLink(pHeadLink, 20);
AppendHeadNode_sCircleLink(pHeadLink, 30);
AppendHeadNode_sCircleLink(pHeadLink, 40);
AppendHeadNode_sCircleLink(pHeadLink, 50);
AppendHeadNode_sCircleLink(pHeadLink, 60);
Show_sCircleLink(pHeadLink);//显示单项循环链表结点数据
printf("\r\n");
Insert_sCircleLink(pHeadLink, 1, 11);//向单项循环链表某处插入数据
Insert_sCircleLink(pHeadLink, 2, 22);
Insert_sCircleLink(pHeadLink, 3, 33);
Insert_sCircleLink(pHeadLink, 4, 44);
Insert_sCircleLink(pHeadLink, 5, 55);
Insert_sCircleLink(pHeadLink, 6, 66);
Show_sCircleLink(pHeadLink);//显示单项循环链表结点数据
printf("\r\n");
Delete_sCircleLink(pHeadLink, 1);//删除单项循环链表某处数据
Delete_sCircleLink(pHeadLink, 2);
Delete_sCircleLink(pHeadLink, 3);
Show_sCircleLink(pHeadLink);//显示单项循环链表结点数据
printf("\r\n");
DeleteEnd_sCircleLink(pHeadLink);//删除单项循环链表尾部数据
DeleteEnd_sCircleLink(pHeadLink);
DeleteEnd_sCircleLink(pHeadLink);
Show_sCircleLink(pHeadLink);//显示单项循环链表结点数据
printf("\r\n");
Clear_sCircleLink(pHeadLink);//清空单项循环链
Show_sCircleLink(pHeadLink);//显示单项循环链表结点数据
printf("\r\n");
while (1);
}
十四、运行结果
创建单项循环链表成功......头结点:0x01359248 指针域:0x01359248 节点数:0
追加数据成功......上结点:0x01359248 本结点:0x01359750 指针域:0x01359248 节点数:1 追加值:100
追加数据成功......上结点:0x01359750 本结点:0x01359798 指针域:0x01359248 节点数:2 追加值:200
追加数据成功......上结点:0x01359798 本结点:0x013597E0 指针域:0x01359248 节点数:3 追加值:300
追加数据成功......上结点:0x013597E0 本结点:0x01359828 指针域:0x01359248 节点数:4 追加值:400
追加数据成功......上结点:0x01359828 本结点:0x01359870 指针域:0x01359248 节点数:5 追加值:500
追加数据成功......上结点:0x01359870 本结点:0x013598B8 指针域:0x01359248 节点数:6 追加值:600
循环链表结点数据:100 200 300 400 500 600
头结点追加数据成功......头指域:0x01359900 本结点:0x01359900 指针域:0x01359750 节点数:7 追加值:10
头结点追加数据成功......头指域:0x01359948 本结点:0x01359948 指针域:0x01359900 节点数:8 追加值:20
头结点追加数据成功......头指域:0x01359990 本结点:0x01359990 指针域:0x01359948 节点数:9 追加值:30
头结点追加数据成功......头指域:0x013599D8 本结点:0x013599D8 指针域:0x01359990 节点数:10 追加值:40
头结点追加数据成功......头指域:0x01359A20 本结点:0x01359A20 指针域:0x013599D8 节点数:11 追加值:50
头结点追加数据成功......头指域:0x01359A68 本结点:0x01359A68 指针域:0x01359A20 节点数:12 追加值:60
循环链表结点数据:60 50 40 30 20 10 100 200 300 400 500 600
插入数据成功......上结点:0x01359248 本结点:0x01359AB0 指针域:0x01359A68 节点数:13 位置:1 插入值:11
插入数据成功......上结点:0x01359AB0 本结点:0x01359AF8 指针域:0x01359A68 节点数:14 位置:2 插入值:22
插入数据成功......上结点:0x01359AF8 本结点:0x01359B40 指针域:0x01359A68 节点数:15 位置:3 插入值:33
插入数据成功......上结点:0x01359B40 本结点:0x01359B88 指针域:0x01359A68 节点数:16 位置:4 插入值:44
插入数据成功......上结点:0x01359B88 本结点:0x01359BD0 指针域:0x01359A68 节点数:17 位置:5 插入值:55
插入数据成功......上结点:0x01359BD0 本结点:0x01359C18 指针域:0x01359A68 节点数:18 位置:6 插入值:66
循环链表结点数据:11 22 33 44 55 66 60 50 40 30 20 10 100 200 300 400 500 600
删除数据成功......上结点:0x01359248 指针域:0x01359AF8 本结点:0x01359AB0 节点数:17 删除值:11
删除数据成功......上结点:0x01359AF8 指针域:0x01359B88 本结点:0x01359B40 节点数:16 删除值:33
删除数据成功......上结点:0x01359B88 指针域:0x01359C18 本结点:0x01359BD0 节点数:15 删除值:55
循环链表结点数据:22 44 66 60 50 40 30 20 10 100 200 300 400 500 600
删除数据成功......上结点:0x01359870 指针域:0x01359248 本结点:0x013598B8 节点数:14 删除值:600
删除数据成功......上结点:0x01359828 指针域:0x01359248 本结点:0x01359870 节点数:13 删除值:500
删除数据成功......上结点:0x013597E0 指针域:0x01359248 本结点:0x01359828 节点数:12 删除值:400
循环链表结点数据:22 44 66 60 50 40 30 20 10 100 200 300
清空链表成功......头结点:0x01359248 指针域:0x01359248 节点数:0
单项循环链表为空......