单循环链表:
就一个点和单链表不同,尾结点的next域不再保存NULL,而是保存头结点的地址
即尾结点的地址是头结点的地址,这样就形成一个循环
可以从循环链表任何一个点出发,就可以遍历整个链表的所有节点
单循环链表的结构体和单链表的结构体设计基本无任何改变
结构体设计:
//带头结点单循环链表结构体设计:
typedef int ELEM_TYPE;
typedef struct CNode
{
ELEM_TYPE data;//数据域
struct CNode *next;//指针域
}CNode, *PCNode;
实现功能
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include "clist.h"
//可实现的操作:
//初始化
void Init_clist(struct CNode *pclist)
{
//0.安全性处理
assert(pclist != NULL);
//1.对pclist指向的头结点里面的成员进行赋值:
//头结点的数据域不使用,只需要对指针域赋值即可,赋值为自身地址
pclist->next = pclist;
}
//头插
bool Insert_head(PCNode pclist, ELEM_TYPE val)
{
assert(pclist != NULL);//保证pclist这个指针 指向的单循环链表的头结点 确确实实存在
struct CNode *pnewnode = (struct CNode *)malloc(1 * sizeof(struct CNode));
assert(pnewnode != NULL);
pnewnode->data = val; //-> ==(*).
//合适的插入位置不用找,因为头插就是在头结点后面插,所以使用pclist即可
pnewnode->next = pclist->next;
pclist->next = pnewnode;
return true;
}
//尾插
bool Insert_tail(PCNode pclist, ELEM_TYPE val)
{
//0.安全性处理
assert(pclist != NULL);
//1.购买新节点
struct CNode *pnewnode = (struct CNode *)malloc(1 * sizeof(struct CNode));
assert(pnewnode != NULL);
pnewnode->data = val;
//2.找到合适的插入位置(也就是说找到在哪一个节点后面插入)
//尾插,找尾结点,用指针p指向
//通过判断,确实使用需要前驱的for循环,也就是说,申请一个临时指针p,执行头结点
struct CNode *p = pclist;
for(; p->next!=pclist; p=p->next);
//此时,for循环,跑完,p指向尾结点
//3.插入即可
pnewnode->next = p->next;
p->next = pnewnode;
return true;
}
//按位置插
bool Insert_pos(PCNode pclist, int pos, ELEM_TYPE val)
{
//0.安全性处理
assert(pclist != NULL);
assert(pos>=0 && pos<=Get_length(pclist));
//1.购买新节点
struct CNode *pnewnode = (struct CNode *)malloc(1 * sizeof(struct CNode));
assert(pnewnode != NULL);
pnewnode->data = val;
//2.找到合适的插入位置
struct CNode * p = pclist; //判断这个是插入函数,需要使用带前驱的for循环
for(int i=0; i<pos; i++)
{
p=p->next;
}
//3.插入即可
pnewnode->next = p->next;
p->next = pnewnode;
return true;
}
//头删
bool Del_head(PCNode pclist)
{
//0:安全性处理
assert(pclist != NULL);
if(IsEmpty(pclist))
{
return false;
}//确保至少存在一个有效节点
//1.找到待删除节点,用指针p指向(头删的话,待删除节点就是第一个有效节点)
struct CNode *p = pclist->next;
//2.找到待删除节点的前驱,用指针q指向
//这里不用处理,因为这里pclist就可以代替q
//3.跨越指向+释放
pclist->next = p->next;
free(p);
return true;
}
//尾删
bool Del_tail(PCNode pclist)
{
assert(pclist != NULL);//保证pclist这个指针 指向的单循环链表的头结点 确确实实存在
if(IsEmpty(pclist))//保证pclist指向的这个头结点 后边存在有效节点
{
return false;
}
struct CNode *p = pclist;
for( ; p->next!=pclist; p=p->next);
struct CNode *q = pclist;
for(; q->next!=p; q=q->next);
q->next = p->next;
free(p);
return true;
}
//按位置删
bool Del_pos(PCNode pclist, int pos)
{
//0.assert pclist
assert(pos >=0 && pos<Get_length(pclist));
if(IsEmpty(pclist))//保证pclist指向的这个头结点 后边存在有效节点
{
return false;
}
//1.先找q 从头结点开始出发,向后走pos步
struct CNode *q = pclist;
for(int i=0; i<pos; ++i)
{
q = q->next;
}
//这时q就为
//2.再找p
struct CNode *p = q->next;
//3.跨越指向+释放
q->next = p->next;
free(p);
return true;
}
//按值删
bool Del_val(PCNode pclist, ELEM_TYPE val)
{
//0.安全性处理
//1.先需要判断val值,是否存在于单循环链表中
struct CNode*p = Search(pclist, val);
//2.若存在,则删除,若不存在,则return false
if(p == NULL)
{
return false;
}
//反之,找到val这个待删除节点了,且现在由指针p指针
//3.找带删除节点的上一个节点,用指针q指向
struct CNode *q = pclist;
for(; q->next!=p; q=q->next);
//4.跨越指向+释放
q->next = p->next;
free(p);
return true;
}
//查找 //查找到,返回的是查找到的这个节点的地址
struct CNode *Search(PCNode pclist, ELEM_TYPE val)
{
//assert pclist
//将单循环链表遍历一遍即可,对每一个有效节点都判断一次
struct CNode *p = pclist->next;
for(; p!=pclist; p=p->next)
{
if(p->data == val)
{
return p;
}
}
return NULL;
}
//获取有效值个数
int Get_length(PCNode pclist)
{
//assert pclist
//将单循环链表遍历一遍即可,对每一个有效节点都判断一次
int count = 0;//有效值个数
struct CNode *p = pclist->next;
for(; p!=pclist; p=p->next)
{
count++;
}
return count;;
}
//判空
bool IsEmpty(PCNode pclist)
{
return pclist->next == pclist;
}
//清空
void Clear(PCNode pclist)
{
return Destroy1(pclist);
}
//销毁1 无限头删
void Destroy1(PCNode pclist)
{
while(pclist->next != pclist)
{
struct CNode *p = pclist->next;
pclist->next = p->next;
free(p);
}
}
//销毁2 不借助头结点,有两个辅助指针
void Destroy2(PCNode pclist)
{
assert(pclist != NULL);
if(IsEmpty(pclist))
{
return;
}
struct CNode *p = pclist->next;
struct CNode *q = p->next;
pclist->next = pclist;
while(p!=pclist)
{
q = p->next;
free(p);
p = q;
}
}
//打印
void Show(PCNode pclist)
{
struct CNode *p = pclist->next;
for(; p!=pclist; p=p->next)
{
printf("%d ", p->data);
}
printf("\n");
}
如果有宝子不是看的不是很懂,小白请大家回看Day04单链表学习,因为循环链表和单链表差的不是很大,小白在上一节对单链表已经做了很详细的个人见解。 最后希望看过此篇的宝子能给小白一个小小的赞,更希望宝子能有所收获
博客介绍了单循环链表,其与单链表的不同在于尾结点的next域保存头结点地址,形成循环,可从任意点遍历所有节点。同时提到单循环链表的结构体和单链表设计基本无改变。
929

被折叠的 条评论
为什么被折叠?



