循环链表没有头结点 只有头指针,由头指针指向循环链表中的任意一个结点(指向谁 谁就是头节点)
多用于双向循环链表:
头结点的前驱指针指向最后一个结点
尾结点的后继指针指向头节点
一般都会把头结点写上
main.cpp
#include "pch.h"
#include <iostream>
#include"CirList.h"
int main()
{
CirList list;
Init_List(&list);
Insert_ListHead(&list, 10);
Insert_ListHead(&list, 20);
Show(list);
Insert_ListTail(&list, 30);
Show(list);
}
CirList.cpp
// Cirlist.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pch.h"
#include <iostream>
#include"CirList.h"
#include<assert.h>
bool IsEmpty(CirList list)//不修改这个指针所以不用传二级指针--?????
{
return list == NULL;//
}
static int Length(CirList list)
{
if (list==NULL) return 0;
CirList p = list;
int count = 0;
while (p->next != list)
{
count++;
p = p->next;
}
return count + 1;
}
bool Init_List(CirList *list)//要修改这个指针的话就传二级指针
{//因为定义的是CirList list 指针对象 所以要修改的话要传* 如果定义的Node对象 则传引用
assert(list != NULL);
if (list == NULL)
{
return false;
}
*list = NULL;//将main函数的list指向空
return true;
}
static CirList ApplyNode(ElemType val, CirList next)
{//申请节点的函数不光传进来节点内存的值 还有要插入的节点的位置
CirList s = (CirList)malloc(sizeof(CNode));//先申请一个节点的空间
assert(NULL != s);
s->data = val;
if (next)
{
s->next = next;
}
else
s->next = s;//如果传入的是NULL 说明链表为空 那这个时候循环链表内只有一个节点 自然是自己指向自己
return s;
}
bool Insert_ListPos(CirList *list, ElemType val, int pos)
{
if (pos == 0)
{
return Insert_ListHead(list, val);
}
if (pos % Length(*list) == 0)
{
return Insert_ListTail(list, val);
}
pos %= Length(*list);
CirList p = *list;
while (pos > 1)
{
p = p->next;
pos--;
}
p->next = ApplyNode(val, p->next);
return true;
}
bool Insert_ListHead(CirList *list, ElemType val)
{
Insert_ListTail(list, val);//先在尾部插入要插入的值
CirList p = *list;
while (p->next != *list)//一直循环到p到了头指针的前一个
{
p = p->next;
}
*list = p;//头指针指向p 也就是循环链表的最后一个(插入的那个)
//实现头插
return true;
}
bool Insert_ListTail(CirList *list, ElemType val)
{
if (IsEmpty(*list))
{
*list = ApplyNode(val, NULL);
return true;
}
CirList p = *list;
while (p->next != *list)//一直循环到p到了头指针的前一个
{
p = p->next;
}
p->next = ApplyNode(val, p->next);//要插入的值和位置都传进去
}
void Show(CirList list)
{
if (list == NULL)
{
return;
}
CirList p = list;//因为不想改变链表 所以不用传地址
while (p->next != list)
{
printf("%d", p->data);
p = p->next;
}
printf("%d ", p->data);//因为还有最后一个要输出
printf("\n");
}
bool Delete_ListHead(CirList *list)
{
if (IsEmpty(*list))
{
return false;
}
int len = Length(*list);
CirList p = *list;
while (p->next != *list)
{
printf("%d", p->data);
p = p->next;
}
CirList q = *list;//q现在指向头指针
*list = q->next;//头指针现在往下移动了一为
p->next = *list;//最后一位绕过q直接到了头指针 达到删除
free(q);
if (len == 1)
*list = NULL;
return true;
}
bool Delete_ListPos(CirList *list, int pos)
{
if (pos == 0 || pos % Length(*list) == 0)
{
return Delete_ListHead(list);
}
int len = Length(*list);
CirList p = *list;
while (pos > 1)
{
p = p->next;
pos--;
}
CirList q = p->next;
p->next = q->next;
free(q);
if (len == 1)
*list = NULL;
return true;
}
bool Delete_ListTail(CirList *list)
{
return Delete_ListPos(list, Length(*list) - 1);
}
// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单
// 入门提示:
// 1. 使用解决方案资源管理器窗口添加/管理文件
// 2. 使用团队资源管理器窗口连接到源代码管理
// 3. 使用输出窗口查看生成输出和其他消息
// 4. 使用错误列表窗口查看错误
// 5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
// 6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件
CirList.h
#pragma once
typedef int ElemType;
typedef struct _Cir
{
ElemType data;
struct _Cir *next;
}CNode, *CirList;
///////////////////////////////
// 必须声明传递二级指针的函数: 初始化 插入 删除 清空 销毁
//////////////////////////////
bool Init_List(CirList *list);//初始化 这里的list是个二级指针
bool IsEmpty(CirList list);
bool Insert_ListHead(CirList *list, ElemType val);
bool Insert_ListTail(CirList *list, ElemType val);
bool Insert_ListPos(CirList *list, ElemType val,int pos);
void Show(CirList list);
bool Delete_ListHead(CirList *list);
bool Delete_ListTail(CirList *list);
bool Delete_ListPos(CirList *list, int pos);