就是简单写写笔记,都是基础的知识
单向循环链表
单向循环链表相比较单链表,唯一的区别,
就是让最后一个节点的next域不再指向nullptr,而是指向头结点。
图解
在初始化头节点时,next域不用再初始化为空,而是指向自己。
最后一个结点的next域指向头结点。
其实和单链表的主要差异就在循环的判断条件上,单链表是判断plist->next是否为空,而循环链表是判断plist->next是否等于头结点。
代码
clist.h
#pragma once
//clist == circle list
//循环链表的结构体定义
typedef int ElemType;
typedef struct CNode
{
ElemType data;
struct CNode *next;
}CNode, *PClist;
//循环链表可执行的操作:(增删改查)
//初始化
void Init_clist(PClist pl);
//头插
bool Insert_head(PClist pl, ElemType val);
//尾插
bool Insert_tail(PClist pl, ElemType val);
//按位置插入
bool Insert_pos(PClist pl, int pos, ElemType val);
//头删
bool Del_head(PClist pl);
//尾删
bool Del_tail(PClist pl);
//按位置删除
bool Del_pos(PClist pl, int pos);
//按值删除,删除遇到的第一个值为val的节点 如果值为val的节点不存在,则返回false
bool Del_val(PClist pl, ElemType val);
//查找 查找值为val的第一个节点,找到则返回其节点地址,否则返回nullptr
struct CNode* Search(PClist pl, ElemType val);
//判空
bool IsEmpty(PClist pl);
//获取循环链表有效元素个数
int Get_length(PClist pl);
//打印
void Show(PClist pl);
//清空
void Clear(PClist pl);
//销毁1 一直头删的方式释放内存
void Destroy(PClist pl);
//销毁2
void Destroy2(PClist pl);
//寻找值为val的节点的前驱
PClist Get_prior(PClist pl, ElemType val);
//寻找值为val的节点的后继
PClist Get_next(PClist pl, ElemType val);
clist.cpp
注:编写步骤和想法和代码写在一起,个人感觉很好理解
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include<stdbool.h>
#include "clist.h"
//初始化
void Init_clist(PClist pl)
{
assert(pl != nullptr);
if(pl == nullptr)
return;
//pl->data; 头结点的数据域不使用
pl->next = pl;
}
//头插
bool Insert_head(PClist pl, ElemType val)
{
assert(pl != nullptr);
//1.申请新节点
CNode* pnewnode = (CNode*)malloc(sizeof(CNode) * 1);
assert(pnewnode != nullptr);
pnewnode->data = val;
//2.找到合适的插入位置
//因为是头插函数 所以不需要找它的插入位置
//3.插入
pnewnode->next = pl->next;
pl->next = pnewnode;
return true;
}
//尾插
bool Insert_tail(PClist pl, ElemType val)
{
assert(pl != nullptr);
//1.申请新节点
CNode* pnewnode = (CNode*)malloc(sizeof(CNode) * 1);
assert(pnewnode != nullptr);
pnewnode->data = val;
//2.找到合适的插入位置
CNode* p = pl;
for(p; p->next != pl; p = p->next);//for循环执行完毕后 p就指向了最后一个节点
//3.插入
pnewnode->next = p->next;//pnewnode->next = pl;
p->next = pnewnode;
return true;
}
//按位置插入
bool Insert_pos(PClist pl, int pos, ElemType val)
{
assert(pl != nullptr && pos >= 0 && pos <= Get_length(pl));
if(pos < 0 || pos > Get_length(pl))
return false;
//1.申请新节点
CNode* pnewnode = (CNode*)malloc(sizeof(CNode) * 1);
assert(pnewnode != nullptr);
pnewnode->data = val;
//2.找到合适的插入位置
CNode* p = pl;
for (int i = 0; i < pos; i++)
{
p = p->next;
}
//3.插入
pnewnode->next = p->next;
p->next = pnewnode;
return true;
}
//头删
bool Del_head(PClist pl)
{
assert(pl != nullptr);
//1.找到删除节点的前驱
if(pl->next == pl)
return false;
//2.删除节点(2.1改变节点指向 2.2释放内存)
CNode* p = pl->next;
pl->next = p->next;
free(p);
p = nullptr;
return true;
}
//尾删
bool Del_tail(PClist pl)
{
assert(pl != nullptr && pl->next != pl);//断言不能光头结点存在
if (pl == nullptr || pl->next == pl)
{
return false;
}
//1.找到删除节点的前驱 走一步看两步
CNode* p = pl;
for (p; p->next != pl; p = p->next)//走一步
{
if (p->next->next == pl)//看两步
{
break;
}
}
//2.删除节点
CNode* q = p->next;
p->next = q->next;//p->next = pl;
free(q);
q = nullptr;
return true;
}
//按位置删除
bool Del_pos(PClist pl, int pos)
{
assert(pl != nullptr & pos >= 0 && pos <= Get_length(pl));
if (pl == nullptr || pos < 0 || pos >= Get_length(pl))
return false;
//1.找到删除节点的前驱
CNode* p = pl;
for (int i = 0; i < pos; i++)
{
p = p->next;
}
//2.删除
CNode* q = p->next;
p->next = q->next;
free(q);
q = nullptr;
return true;
}
//按值删除,删除遇到的第一个值为val的节点 如果值为val的节点不存在,则返回false
bool Del_val(PClist pl, ElemType val)
{
assert(pl != nullptr && pl->next != pl);
//1.通过调用Get_prior函数来获取删除节点的前驱
CNode* p = Get_prior(pl, val);
if(p == nullptr)
{
return false;
}
//2.删除
CNode* q = p->next;
p->next = q->next;
free(q);
q = nullptr;
return true;
}
//查找 查找值为val的第一个节点,找到则返回其节点地址,否则返回nullptr
struct CNode* Search(PClist pl, ElemType val)
{
assert(pl != nullptr);
CNode* p = pl->next;
for(p; p != pl; p = p->next)
{
if(p->data == val)
{
return p;
}
}
return nullptr;
}
//判空
bool IsEmpty(PClist pl)
{
//return pl->next == NULL; 单链表的判空
return pl->next == pl;//循环链表的判空
}
//获取循环链表有效元素个数
int Get_length(PClist pl)
{
assert(pl != nullptr);
int count = 0;
CNode* p = pl->next;
for(p; p != pl; p = p->next)
{
count++;
}
return count;
}
//打印
void Show(PClist pl)
{
assert(pl != nullptr);
CNode* p = pl->next;
for(p; p!=pl; p=p->next)
{
printf("%d ", p->data);
}
printf("\n");
}
//清空
void Clear(PClist pl)
{
Destroy(pl);
}
//销毁1 一直头删的方式释放内存
void Destroy(PClist pl)
{
assert(pl != nullptr);
while(pl->next != pl)
{
CNode* p = pl->next;
pl->next = p->next;
free(p);
}
}
//销毁2
void Destroy2(PClist pl)
{
assert(pl != nullptr && pl->next != pl);
CNode* p = pl->next;
CNode* q = nullptr;
while(p != pl)
{
q = p->next;
free(p);
p = q;
}
pl->next = pl;
}
//寻找值为val的节点的前驱
PClist Get_prior(PClist pl, ElemType val)
{
assert(pl != nullptr);
CNode* p = pl;
for(p; p->next != pl; p = p->next)
{
if(p->next->data == val)
{
return p;
}
}
return nullptr;
}
//寻找值为val的节点的后继
PClist Get_next(PClist pl, ElemType val)
{
assert(pl != nullptr);
CNode *p = Search(pl, val);
if(p == nullptr)
return nullptr;
return p->next;
//return p==NULL ? NULL : p->next;
}
main.cpp运行示例
#include<stdio.h>
#include"clist.h"
int main(void)
{
CNode cn;
Init_clist(&cn);
//按位置插入
for (int i = 0; i < 10; ++i)
{
Insert_pos(&cn, i, i + 1);
}
Show(&cn);
//其他两个插入
Insert_head(&cn, 100);
Insert_tail(&cn, 200);
Show(&cn);
printf("lenth = %d\n", Get_length(&cn));
//头删,尾删
Del_head(&cn);
Del_tail(&cn);
Show(&cn);
printf("lenth = %d\n", Get_length(&cn));
//按位置和按值删除
Del_pos(&cn, 3);
Del_val(&cn, 7);
Show(&cn);
printf("lenth = %d\n", Get_length(&cn));
Destroy(&cn);
Show(&cn);
printf("lenth = %d\n", Get_length(&cn));
return 0;
}
运行结果