循环链表的结构设计
循环链表就是——链表的头和尾连在一起
即最后一个数据(尾巴结点)的next由单链表的NULL,变为现在循环链表的存储头结点plist的地址200,尾巴结点指向头结点
现在来建立循环链表clist
先写结构设计
现在看对于循环链表有哪些操作——可以将原来的单链表一一复制过来
因为线性表(到现在为止顺序表,单链表,循环链表)其对外的操作都是一样的。
#pragma once
//循环链表
//struct是结点的样子
typedef struct CNode
{
int data;
struct CNode* next;
}CNode,*CList;//CList是名字不是类型,所以是*CList而不是CList*
//而CNode是类型,所以CList==CNode*
//链表的基本实现操作(常用的),应用操作一般不放在这里面
//可以将链表的复制过来
//初始化
void InitCList(CList plsit);//Init:初始化。链表结构体指针数据类型+其定义 的变量,名字为plsit
//头插(插入在头结点后面的第一个有效数据的位置上)
bool Insert_head(CList plist, int val);
//尾插
bool Insert_tail(CList plist, int val);
//插入数据,在链表plsit的pos位置插入val数据元素
//插入操作有2种结果,插入成功或失败,所以其插入函数原型是bool类型,只返回2种结果
bool Insert(CList plsit, int pos, int val);//参数就是实现这个函数的使用需要外界提供给它的数据东西
//判空(判断链表是否为空)
bool IsEmpty(CList plsit);
//获取数据结点的个数
int Getlength(CList plsit);
//在链表plsit中 查找第一个key值,找到返回key值的结点地址,没有找到返回空NULL
//所以其查找的返回类型为Node*
CNode* Search(CList plsit, int key);
//删除链表plsit中pos位置的值,删除跟插入一样成功或失败2种结果
bool DelPos(CList plsit, int pos);
//删除第一个val的值
bool DelVal(CList plsit, int val);
//返回key的前驱地址,如果不存在(key无前驱,在表头)返回NULL
CNode* GetPrio(CList plsit, int key);
//返回key的后继下标,如果不存在(key无后继,在表尾)返回NULL
CNode* GetNext(CList plsit, int key);
//输出链表,不是对链表内部的操作,但为了展示我们对链表的操作是否正确,有时要输出看一下
void Show(CList plsit);
//清空链表中的数据
void Clear(CList plsit);
//销毁整个链表内存(交回)
void Destroy(CList plsit);
这里说一下清空和销毁
再销毁时,有时候会调用清空函数,有时候又不调用清空函数;清空时的调用同理。
那么什么时候需要调用它——在清空就能达到销毁整个动态内存的的要求时,就可以调用它。
在定长顺序表里面,就可以调用——是因为定长顺序表里面就没有动态内存
在可扩容顺序表里面,清空函数不能销毁malloc出来的东西,需要free,所以不能调用
在单链表里面,清空数据调用销毁函数能够达到清空的要求,那么直接调用就行
所有链式结构里面的销毁方法——总是删除free第一个结点(每个数据结点都会变成第一个结点)
而头结点是从外面(int main)传进来的,main函数结束后return 0,里面的东西就自动销毁了。
如上图,有的会在初始化这里malloc一个plist,那么此时的头结点就不是临时结点了,
在销毁时,它也就需要free了
————一个malloc对应一个free