1. 单向循环链表基本概念
循环链表是一个首尾相接的链表。将单链表最后一个结点的指针域由NULL改为指向表头结点,就得到了单链形式的循环链表,并称为循环单链表。
单链表的存储结构及基本运算:https://blog.csdn.net/weixin_51450101/article/details/121754357
在循环单链表中,表中所有结点都被链在一个环上,为使某些操作实现方便,在循环单链表中也可以设置一个头结点。这样,空循环链表仅由一个自成循环的头结点表示,如图所示。
带头结点的单向循环链表的各种操作的实现算法与带头结点的单链表的实现算法类似,差别仅在于算法中判别当前结点p是否为表尾结点的条件不同。单链表中判别条件为p!=NULL或p->next!=NULL,而单循环链表的判别条件则是p!=CL或p->next!=CL。
单向循环链表的基本运算包括单向循环链表的初始化,尾插法建表,输出,求表长,结点查找(按序号/按值),插入和删除。
2. 完整代码+注释
/*
单向循环链表的存储结构及基本运算
包括单向循环链表的初始化,尾插法建表,输出,求表长,结点查找(按序号/按值),插入和删除
*/
# include<stdio.h>
# include<malloc.h>
# define OK 1
# define ERROR 0
typedef int ElemType;
/*单向循环链表的存储结构*/
typedef struct Node { //结点类型定义
ElemType data;
struct Node* next;
}Node, * CLinkList;
CLinkList CL;
/*单向循环链表的初始化(带头结点和头指针的单向循环链表)*/
InitCLinkList(CLinkList* CL) {
*CL = (CLinkList)malloc(sizeof(Node)); //建立头结点
(*CL)->next = *CL; //建立空的循环单链表CL
}
/*尾插法创建单向循环链表*/
/*CL是已经初始化完毕、带头结点的空单向循环链表的头指针,通过键盘输入元素值*/
void CreateCLinkList(CLinkList CL) {
Node* rear, * s;
int c, flag = 1;
rear = CL; //rear指针动态指向当前表尾,其初值指向头结点
while (flag) {
scanf("%d", &c);
if (c != 0) {
s = (Node*)malloc(sizeof(Node));//建立新结点
s->data = c; //新结点s的数据域值为c
rear->next = s; //将新结点s插入表尾
rear = s; //rear指针指向当前表尾
}
else { //输入为0表示输入结束
flag = 0;
rear->next = CL; //最后一个结点的next链域指向头结点
}
}
}
/*输出单向循环链表*/
void OutputCLinkList(CLinkList CL) {
if (CL->next == CL) {
printf("空表!");
}
else {
Node* p;
p = CL->next; //p初值指向首元结点
while (p != CL) {
printf("%d ", p->data);
p = p->next; //p指向下一个结点
}
}
}
/*求表长*/
int CLinkListLength(CLinkList CL) {
int i = 0;
Node* p;
p = CL->next; //p初值指向首元结点
while (p != CL) {
i++;
p = p->next; //p指向下一个结点
}
return i;
}
/*按序号查找*/
/*在带头结点的单向循环链表CL中查找第n个结点,若找到则返回该结点的元素值;否则返回NULL*/
int Get(CLinkList CL, int n) {
int i = 0; //i用于计数
Node* p;
if (n <= 0)
return NULL;
p = CL; //p初值指向头结点
while (p->next != CL && i < n) {
p = p->next;
i++;
}
if (i == n) //i=n说明查找该结点,则返回结点值
return (p->data);
else //说明输入序号大于链表长度,则返回NULL
return NULL;
}
/*按值查找*/
/*在带头结点的单向循环链表CL中查找其结点值等于e的第一个结点,若找到则返回该结点的位置p,否则返回NULL*/
int Locate(CLinkList CL, int e) {
int i = 0; //i用于计数
Node* p;
p = CL->next; //p初值指向首元结点
while (p != CL) {
if (p->data != e) {
p = p->next; //当前结点值不为e则指向下一个结点
i++;
}
else
break;
}
if (p != CL) //p!=CL说明查找该结点值,则返回结点序号
return (i + 1);
else
return NULL; //未查找到该结点值,则返回NULL
}
/*插入*/
/*在带头结点的单向循环链表CL中第i个位置插入值为e的新结点*/
int InsCLinkList(CLinkList CL, int i, int e) {
Node* pre, * s;
pre = CL; //pre初值指向头结点
if (i < 1) {
printf("插入位置不合法!\n");
return ERROR;
}
int k = 0; //k用于计数
while (pre->next != CL && k < i - 1) { //查找第i-1个结点
pre = pre->next;
k++;
}
if (k < i - 1) {
printf("插入位置不合法!\n");
return ERROR;
}
s = (Node*)malloc(sizeof(Node)); //申请一个新结点
s->data = e;
s->next = pre->next; //修改指针完成插入操作
pre->next = s;
printf("插入成功!\n");
return OK;
}
/*删除*/
/*在带头结点的单链表L中删除第i个元素*/
int DelCLinkList(CLinkList CL, int i) {
Node* pre, * r;
pre = CL; //pre初值指向头结点
if (i < 1) {
printf("删除位置不合法!\n");
return ERROR;
}
int k = 0, e;
while (pre->next != CL && k < i - 1) { //查找第i-1个结点
pre = pre->next;
k++;
}
if (pre->next == CL) {
printf("删除位置不合法!\n");
return ERROR;
}
r = pre->next;
pre->next = r->next; //修改指针,删除结点r
e = r->data;
free(r);
printf("删除成功!删除的结点值为:%d\n", e);
return OK;
}
/*选择菜单函数用于实现功能的选择*/
void Menu(int select) {
int n, e;
switch (select) {
case 1:InitCLinkList(&CL); //初始化
printf("初始化成功!\n"); break;
case 2:InitCLinkList(&CL); //创建
printf("请输入元素值(以空格隔开,以0结束):");
CreateCLinkList(CL);
printf("创建成功!\n输出结果为:");
OutputCLinkList(CL);
printf("\n"); break;
case 3:printf("输出结果为:"); //输出
OutputCLinkList(CL);
printf("\n"); break;
case 4:printf("长度为:%d\n", CLinkListLength(CL)); //求表长
break;
case 5:printf("请输入要查找的序号:"); //按序号查找
scanf("%d", &n);
if (Get(CL, n) == NULL)
printf("输入错误,未查找到该结点!\n");
else
printf("序号%d的结点值为:%d\n", n, Get(CL, n)); break;
case 6:printf("请输入要查找结点的值:"); //按值查找
scanf("%d", &e);
if (Locate(CL, e) == NULL)
printf("输入错误,未查找到该结点!\n");
else
printf("值为%d的结点序号为:%d\n", e, Locate(CL, e)); break;
case 7:printf("请输入插入位置和结点值:"); //插入
scanf("%d%d", &n, &e);
InsCLinkList(CL, n, e);
printf("输出结果为:");
OutputCLinkList(CL);
printf("\n"); break;
case 8:printf("请输入要删除的结点序号:"); //删除
scanf("%d", &n);
DelCLinkList(CL, n);
printf("输出结果为:");
OutputCLinkList(CL);
printf("\n"); break;
default:printf("输入错误!\n"); break;
}
}
int main() {
InitCLinkList(&CL);
printf("--------单向循环链表基本运算--------\n");
printf("1.初始化\t2.尾插法建表\n");
printf("3.输出\t\t4.求表长\n");
printf("5.按序号查找\t6.按值查找\n");
printf("7.插入\t\t8.删除\n");
printf("0.退出\n");
printf("------------------------------------\n");
printf("请选择操作:");
int select;
scanf("%d", &select);
while (select) {
Menu(select);
printf("------------------------------------\n");
printf("请选择下一操作:");
scanf("%d", &select);
}
printf("退出成功!");
return 0;
}
3. 运行结果
参考:耿国华《数据结构——用C语言描述(第二版)》