循环链表:和单链表相比,尾结点的next域不在指向NULL,而是指向头结点
循环链表的结构体声明和单链表一样:
//循环链表结构体设计
typedef int ELEMTYPE;
typedef struct Clist
{
ELEMTYPE data; //数据域 存放数据
struct Clist* next;//指针域 存放下一个节点的地址(尾结点的next保存头结点的地址)
}Clist, * PClist;
同样实现链表的相应功能:
函数声明
//循环链表拥有的 可执行函数声明:
//初始化
void InitClist(struct Clist* plist);
//头插
bool Insert_head(PClist plist, ELEMTYPE val);
//尾插
bool Insert_tail(PClist plist, ELEMTYPE val);
//按位置插
bool Insert_pos(PClist plist, int pos, ELEMTYPE val);
//头删
bool Del_head(PClist plist);
//尾删
bool Del_tail(PClist plist);
//按位置删
bool Del_pos(PClist plist, int pos);
//按值删除
bool Del_val(PClist plist, ELEMTYPE val);
//查找(如果查找到,需要返回找到的这个节点的地址)
struct Clist* Search(struct Clist* plist, ELEMTYPE val);
//判空
bool IsEmpty(PClist plist);
//判满(循环链表不需要这个操作)
//获取长度
int Get_length(PClist plist);
//清空
void Clear(PClist plist);
//销毁1
void Destroy1(PClist plist);
//销毁2
void Destroy2(PClist plist);
//打印
void Show(struct Clist* plist);
1.初始化:(数据域不做处理,next域为头结点自身的地址)
//初始化
void InitClist(struct Clist* plist)
{
assert(plist != NULL);
if (plist == NULL)
{
return;
}
//plist->data; // 数据域不处理
plist->next = plist;
}
2.头插:
bool Insert_head(PClist plist, ELEMTYPE val)
{
//assert断言
assert(plist != NULL);
if (plist == NULL)
{
return false;
}
//购买新的节点
PClist list = (PClist)malloc(sizeof(Clist) * 1);
assert(list != NULL);
list->data = val;
//找到合适的位置插入,这里是头插
list->next = plist->next;
plist->next = list;
return true;
}
3.尾插:
bool Insert_tail(PClist plist, ELEMTYPE val)
{
assert(plist != NULL);
if(plist==NULL)
{
return false;
}
//建立一个指针p,指向最后一个节点
PClist p = plist;
for (p; p->next != plist; p = p->next);
//购买新节点
PClist list = (PClist)malloc(sizeof(Clist) * 1);
assert(list != NULL);
list->data = val;
//此时 for循环执行结束 p指向尾结点
//在最后一个节点插入
list->next = p->next;
p->next = list;
return true;
}
4.按位置插
bool Insert_pos(PClist plist, int pos, ELEMTYPE val)
{
assert(plist != NULL);
assert(pos >= 0 && pos <= Get_length(plist));
//购买新节点
PClist list = (PClist)malloc(sizeof(Clist) * 1);
assert(list != NULL);
list->data = val;
//建立一个指针通过for循环指向要插入的位置,第0个位置相当于头插
PClist p=plist;
for (int i = 0; i < pos; ++i)
{
p = p->next;
}
//插入
list->next = p->next;
p->next = list;
return true;
}
5.头删
bool Del_head(PClist plist)
{
assert(plist != NULL);
//删除得判断是否为空
if (IsEmpty(plist))//不空 则至少存在一个有效值
{
return false;
}
//1.指针p指向待删除节点
struct Clist* p = plist->next;
//2.指针q指向待删除节点的前一个节点
//q 就是 头结点 这里就不再额外处理
//3.跨越指向
plist->next = p->next;
free(p);
return true;
}
6.尾删
bool Del_tail(PClist plist)
{
assert(plist != NULL);
if (IsEmpty(plist))//不空 则至少存在一个有效值
{
return false;
}
//1.指针p指向待删除节点(尾删的话,这里指向尾结点)
PClist p = plist;
for (p; p->next != plist; p = p->next);
//此时 for指向结束 代表着p指向尾结点
//2.指针q指向倒数第二个节点
PClist q = plist;
for (q; q->next != p; q = q->next);
//此时 for指向结束 代表着q指向p的上一个节点
q->next = p->next;
free(p);
return true;
}
7.按位置删
bool Del_pos(PClist plist, int pos)
{
assert(plist != NULL);
assert(pos >= 0 && pos <= Get_length(plist));
if (IsEmpty(plist))
{
return false;
}
//1.指针p指向待删除节点
PClist p = plist;
for (int i = 0; i <= pos; ++i)
{
p = p->next;
}
//2.指针q指向待删除节点的上一个节点
PClist q = plist;
for (q; q->next != p; q = q->next);
//删除
q->next = p->next;
free(p);
return true;
}
8.按值删
bool Del_val(PClist plist, ELEMTYPE val)
{
assert(plist != NULL);
struct Clist* p = Search(plist, val);//p指向要删除的节点
if (p == NULL)
{
return false;
}
struct Clist* q = plist;//q指向上一个节点
for (q; q->next != p; q = q->next);
q->next = p->next;
free(p);
return true;
}
9.查找
//查找(如果查找到,需要返回找到的这个节点的地址)
struct Clist* Search(struct Clist* plist, ELEMTYPE val)
{
assert(plist != NULL);
PClist p = plist->next;
for (p; p != plist; p = p->next)
{
if (p->data == val)
{
return p;
}
}
return NULL;
}
10.判空,获取长度
//判空
bool IsEmpty(PClist plist)
{
assert(plist != NULL);
return plist->next==plist;
}
//判满(循环链表不需要这个操作)
//获取长度
/*指针p从头结点的下一个节点开始向后跑,如果p再次遇到了头结点,
证明p走了一圈回来了,这是有效节点肯定已经遍历结束*/
int Get_length(PClist plist)
{
int cout=0;
for (PClist p = plist->next; p != plist; p = p->next)
{
cout++;
}
return cout;
}
11.清空,销毁(两种方法),打印
//清空
void Clear(PClist plist)
{
//assert
Destroy1(plist);
}
//销毁1
void Destroy1(PClist plist)
{
assert(plist != NULL);
while (plist->next != plist)
{
struct Clist* p = plist->next;
plist->next = p->next;
free(p);
}
plist->next = plist;
}
//销毁2
void Destroy2(PClist plist)
{
//assert
struct Clist* p = plist->next;
struct Clist* q = NULL;
plist->next = plist;
while (p != plist)
{
q = p->next;
free(p);
p = q;
}
}
//打印
void Show(struct Clist* plist)
{
for (PClist p = plist->next; p != plist; p = p->next)
{
printf("%d ", p->data);
}
printf("\n");
}
看一下测试结果:
主函数:
int main()
{
struct Clist head;
InitClist(&head);
for (int i = 0; i < 20; i++)
{
Insert_pos(&head, i, i + 1);
}//1到20按位置插给链表赋值
Show(&head);//打印
Insert_head(&head, 100);//头插100
Insert_tail(&head, 200);//尾插200
Show(&head);//打印
printf("length = %d\n", Get_length(&head));//打印长度
Del_head(&head);//头删
Del_tail(&head);//尾删
Show(&head);//打印
Del_pos(&head, 4);//将第四个位置删除
Del_val(&head, 14);//将值为14的结点删除
Show(&head);
printf("length = %d\n", Get_length(&head));//打印长度
//Destroy(&head);
Destroy2(&head);//销毁
//printf("%d\n", sizeof(struct Node));
return 0;
}