单循环链表的实现

单循环链表就是让单链表的尾结点指向头结点

1、构造一个空的线性表L

void InitList(LinkList &L)//传递实参而非形参
{// 操作结果:构造一个空的线性表LL = (LinkList)malloc(sizeof(LNode));// 产生头结点,并使L指向此头结点if (L == NULL){printf("内存分配是失败,退出程序\n");exit(-1);}L->next = L; // 指针域指向头结点
}

2、判断单循环链表是否为空

如果单循环链表为空则头结点指针域指向自己

bool ListEmpty(LinkList L)
{// 初始条件:线性表L已存在。操作结果:若L为空表,则返回true,否则返回false//判断要点 如果单循环链表为空则头结点指针域指向自己if (L == L->next){return true; }       else{return false;}
}

3、向单循环链表中追加结点值为e的结点

bool ListAddElem(LinkList L,ElemType e)
{// 初始条件:线性表L已存在。//操作结果:在L的头结点的左边添加结点LinkList p = L;//p指向头结点while (p->next != L)//p指向头结点左边的结点(类似于单链表的最后一个结点){p = p->next;}LinkList pNewNode = (LinkList)malloc(sizeof(LNode));//创建新节点if (pNewNode == NULL){printf("内存分配失败!\n");return false;}p->next = pNewNode;//新结点的地址给最后一个结点的nextpNewNode->data = e;//新结点赋值pNewNode->next = L;//新结点指向头结点return true;
}

4、遍历输出结点值

void ListTraverse(LinkList L)
{if (L->next == L){printf("单循环链表为空\n");}LinkList p = L;while (p->next != L){p = p->next;printf("  %d",p->data);}printf("\n");
}

5、获取单循环链表的结点元素个数

int ListLength(LinkList L)
{int i = 0;LinkList p = L;while (p->next != L){i++;p = p->next; }return i;
}

6、清空单循环链表

void ClearList(LinkList &L)
{// 初始条件:线性表L已存在。操作结果:将L重置为空表LinkList p, q;p = L;while (p->next != L)//p的指针域不等于L{q = p;//保存pp = p->next;//p指向下一个结点free(q);//释放q}L->next = L;//头结点指针域指向自己
}

7、销毁单循环链表

void DestroyList(LinkList L)
{ // 操作结果:销毁线性表LLinkList p, q;p = L;while (p->next != L)//p的指针域不等于L{q = p;//保存pp = p->next;//p指向下一个结点free(q);//释放q}free(L);
}

8、顺时针获取第i个结点的元素值

bool GetElem(LinkList L,int i ,ElemType &e)
{if (i<1||i>ListLength(L))//i值不在范围之内{return false;}int j = 0;LinkList p = L;//p指向头结点while (j<i){p = p->next;j++;}e = p->data;return true;
}

9、查询链表中满足条件的地址一个结点

//9.1判断两个ElemType类型数据的是否相等
bool compare(ElemType e1, ElemType  e2)
{if (e1 == e2){return true;}elsereturn false;
}
//9、查询链表中满足条件的地址一个结点
int LocateElem(LinkList L, ElemType e, bool(*compare)(ElemType, ElemType))
{ // 初始条件:线性表L已存在,compare()是数据元素判定函数// 操作结果:返回L中第1个与e满足关系compare()的数据元素的位序。//           若这样的数据元素不存在,则返回值为0int i = 0;LinkList p = L; // p指向头结点while (p->next != L){p = p->next;i++;if (compare(p->data, e)) // 满足关系return i;      }return 0;
}

10、 查询结点值为cur_e的结点的直接前驱结点值

bool PriorElem(LinkList L,ElemType cur_e,ElemType &pre_e)
{ // 初始条件:线性表L已存在// 操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱,//           否则操作失败,pre_e无定义LinkList q = NULL, p = L; // p指向第一个结点if (p->next->data == cur_e){printf("首结点没有前驱");return false;// 操作失败}while (  p->next != L) // p没到表尾{q = p;p = p->next;if (p->data == cur_e){pre_e = q->data;return true;}}return false; // 操作失败
}

11、 查询结点值为cur_e的结点的直接后驱结点值

bool NextElem(LinkList L, ElemType cur_e, ElemType &next_e)
{ // 初始条件:线性表L已存在// 操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继,//           否则操作失败,next_e无定义LinkList p = L->next; // p指向第一个结点while (p->next != L) // p指向结点的指针域没有指向头结点,只有最后一个结点的指针域指向头结点,即p不指向最后一个结点{if (p->data == cur_e){next_e = p->next->data;//满足条件获取后继结点值return true;}p = p->next;//不满足条件p指向下一个结点}return false; // 操作失败
}

12、在L的第i个位置之前插入元素e

同单链表的插入,区别在于尾结点的标志是头结点的地址而非空

bool ListInsert(LinkList &L, int i, ElemType e) // 改变L
{ // 初始条件:线性表L已存在// 操作结果:在L的第i个位置之前插入元素eLinkList p = L;int j = 0;if (i <= 0 || i > ListLength(L) + 1) // 无法在第i个元素之前插入return false;//找到第i-1个结点while (j<i-1){p = p->next;j++;}//创建新的结点LinkList NewNode = (LinkList)malloc(sizeof(LNode));if (NewNode == NULL){printf("内存分配失败\n");return false;}NewNode->data = e;NewNode->next = p->next;p->next = NewNode;return true;
}

13、删除第i个元素

同单链表的插入,区别在于尾结点的标志是头结点的地址而非空

bool ListDelete(LinkList &L, int i, ElemType &e)
{ // 初始条件:线性表L已存在// 操作结果:删除L的第i个位置的元素并通过e返回LinkList q,p = L;int j = 0;if (i <= 0 || i > ListLength(L) + 1) // 超出范围无法删除第i个元素return false;//找到第i-1个结点while (j < i - 1){p = p->next;j++;}q = p->next;//保存第i结点的指针e = q->data;//保存第i个结点的值p->next = q->next;//第i-1个结点指向第i+1个结点free(q);//释放第i个结点return true;
}

最后给出完整代码

// 单循环链表
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h> //定义数据类型;
typedef int ElemType;//定义结点结构;
typedef struct Node
{ElemType data;struct Node * next;
}LNode, *LinkList;//LNode等价于struct Node,LinkList等价于struct Node*//函数声明
//1、构造一个空的线性表L
void InitList(LinkList &L);
//2、判断单循环链表是否为空
bool ListEmpty(LinkList L);
//3、向单循环链表中追加结点值为e的结点
bool ListAddElem(LinkList L, ElemType e);
//4、遍历输出结点值
void ListTraverse(LinkList L);
//5、获取单循环链表的结点元素个数
int ListLength(LinkList L);
//6、清空单循环链表
void ClearList(LinkList &L);
//7、销毁单循环链表
void DestroyList(LinkList L);
//8、顺时针获取第i个结点的元素值
bool GetElem(LinkList L, int i, ElemType &e);
//9、查询链表中满足条件的地址一个结点
int LocateElem(LinkList L, ElemType e, bool(*compare)(ElemType, ElemType));
//9.1判断两个ElemType类型数据的是否相等
bool compare(ElemType e1, ElemType  e2);
//10、 查询结点值为cur_e的结点的直接前驱结点值
bool PriorElem(LinkList L, ElemType cur_e, ElemType &pre_e);
//11、 查询结点值为cur_e的结点的直接后驱结点值
bool NextElem(LinkList L, ElemType cur_e, ElemType &next_e);
//12、// 在L的第i个位置之前插入元素e
bool ListInsert(LinkList &L, int i, ElemType e);
//13、删除第i个元素
bool ListDelete(LinkList &L, int i, ElemType &e);int main()
{LinkList L = NULL;InitList(L);printf("1、单循环链表L的地址为 %p\n",L);if (ListEmpty(L)){printf("2、链表为空\n");}else{printf("2、链表不为空\n");}ElemType e = 0;if (ListAddElem(L, e))printf("3、追加成功\n");elseprintf("3、追加失败|n");for (int i = 0; i < 10; i++){ListAddElem(L, i+1);}ListTraverse(L);printf("5、单循环链表的结点元素个数为 %d\n",ListLength(L));ClearList(L);ListTraverse(L);if (ListEmpty(L)){printf("6、链表为空\n");}else{printf("6、链表不为空\n");}for (int i = 0; i < 10; i++){ListAddElem(L, i + 1);}ListTraverse(L);ElemType e1 = 0, e2 = 10, cur_e = 9, pre_e,next_e;int i = 5;GetElem(L, i, e1);printf("8、获取到第%d个结点元素值为 %d\n",i,e1);printf("9、值为%d的结点的序位为 %d\n",e2,LocateElem( L, e2, compare));if (PriorElem( L,  cur_e, pre_e)){printf("10、值为%d的结点的前驱为 %d\n", cur_e, pre_e);}else{printf("10、值为%d的结点的前驱为获取失败\n", cur_e);}if (NextElem(L, cur_e, next_e)){printf("11、值为%d的结点的后继为 %d\n", cur_e, next_e);}else{printf("11、值为%d的结点的后继为获取失败\n", cur_e);}ListTraverse(L);if (ListInsert(L, i, 100)){printf("12、在第 %d 个结点前插入 %d 成功\n", i,100);}else{printf("12、在第 %d 个结点前插入 %d 失败\n", i,100);}ListTraverse(L);if (ListDelete(L, i, e)){printf("13、删除的第 %d 个结点的值为 %d 成功\n", i, e);}else{printf("13、删除的第 %d 个结点失败\n", i);}ListTraverse(L);return 0;
}//1、构造一个空的线性表L
void InitList(LinkList &L)//传递实参而非形参
{// 操作结果:构造一个空的线性表LL = (LinkList)malloc(sizeof(LNode));// 产生头结点,并使L指向此头结点if (L == NULL){printf("内存分配是失败,退出程序\n");exit(-1);}L->next = L; // 指针域指向头结点
}//2、判断单循环链表是否为空
bool ListEmpty(LinkList L)
{// 初始条件:线性表L已存在。操作结果:若L为空表,则返回true,否则返回false//判断要点 如果单循环链表为空则头结点指针域指向自己if (L == L->next){return true; }       else{return false;}
}//3、向单循环链表中追加结点值为e的结点
bool ListAddElem(LinkList L,ElemType e)
{// 初始条件:线性表L已存在。//操作结果:在L的头结点的左边添加结点LinkList p = L;//p指向头结点while (p->next != L)//p指向头结点左边的结点(类似于单链表的最后一个结点){p = p->next;}LinkList pNewNode = (LinkList)malloc(sizeof(LNode));//创建新节点if (pNewNode == NULL){printf("内存分配失败!\n");return false;}p->next = pNewNode;//新结点的地址给最后一个结点的nextpNewNode->data = e;//新结点赋值pNewNode->next = L;//新结点指向头结点return true;
}//4、遍历输出结点值
void ListTraverse(LinkList L)
{if (L->next == L){printf("单循环链表为空\n");}LinkList p = L;while (p->next != L){p = p->next;printf("  %d",p->data);}printf("\n");
}//5、获取单循环链表的结点元素个数
int ListLength(LinkList L)
{int i = 0;LinkList p = L;while (p->next != L){i++;p = p->next; }return i;
}
//6、清空单循环链表
void ClearList(LinkList &L)
{// 初始条件:线性表L已存在。操作结果:将L重置为空表LinkList p, q;p = L;while (p->next != L)//p的指针域不等于L{q = p;//保存pp = p->next;//p指向下一个结点free(q);//释放q}L->next = L;//头结点指针域指向自己
}//7、销毁单循环链表
void DestroyList(LinkList L)
{ // 操作结果:销毁线性表LLinkList p, q;p = L;while (p->next != L)//p的指针域不等于L{q = p;//保存pp = p->next;//p指向下一个结点free(q);//释放q}free(L);
}// 8、顺时针获取第i个结点的元素值
bool GetElem(LinkList L,int i ,ElemType &e)
{if (i<1||i>ListLength(L))//i值不在范围之内{return false;}int j = 0;LinkList p = L;//p指向头结点while (j<i){p = p->next;j++;}e = p->data;return true;
}
//9.1判断两个ElemType类型数据的是否相等
bool compare(ElemType e1, ElemType  e2)
{if (e1 == e2){return true;}elsereturn false;
}
//9、查询链表中满足条件的地址一个结点
int LocateElem(LinkList L, ElemType e, bool(*compare)(ElemType, ElemType))
{ // 初始条件:线性表L已存在,compare()是数据元素判定函数// 操作结果:返回L中第1个与e满足关系compare()的数据元素的位序。//           若这样的数据元素不存在,则返回值为0int i = 0;LinkList p = L; // p指向头结点while (p->next != L){p = p->next;i++;if (compare(p->data, e)) // 满足关系return i;      }return 0;
}
//10、 查询结点值为cur_e的结点的直接前驱结点值
bool PriorElem(LinkList L,ElemType cur_e,ElemType &pre_e)
{ // 初始条件:线性表L已存在// 操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱,//           否则操作失败,pre_e无定义LinkList q = NULL, p = L; // p指向第一个结点if (p->next->data == cur_e){printf("首结点没有前驱");return false;// 操作失败}while (  p->next != L) // p没到表尾{q = p;p = p->next;if (p->data == cur_e){pre_e = q->data;return true;}}return false; // 操作失败
}//11、 查询结点值为cur_e的结点的直接后驱结点值
bool NextElem(LinkList L, ElemType cur_e, ElemType &next_e)
{ // 初始条件:线性表L已存在// 操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继,//           否则操作失败,next_e无定义LinkList p = L->next; // p指向第一个结点while (p->next != L) // p指向结点的指针域没有指向头结点,只有最后一个结点的指针域指向头结点,即p不指向最后一个结点{if (p->data == cur_e){next_e = p->next->data;//满足条件获取后继结点值return true;}p = p->next;//不满足条件p指向下一个结点}return false; // 操作失败
}
//12、在L的第i个位置之前插入元素e
bool ListInsert(LinkList &L, int i, ElemType e) // 改变L
{ // 初始条件:线性表L已存在// 操作结果:在L的第i个位置之前插入元素eLinkList p = L;int j = 0;if (i <= 0 || i > ListLength(L) + 1) // 无法在第i个元素之前插入return false;//找到第i-1个结点while (j<i-1){p = p->next;j++;}//创建新的结点LinkList NewNode = (LinkList)malloc(sizeof(LNode));if (NewNode == NULL){printf("内存分配失败\n");return false;}NewNode->data = e;NewNode->next = p->next;p->next = NewNode;return true;
}
//13、删除第i个元素
bool ListDelete(LinkList &L, int i, ElemType &e)
{ // 初始条件:线性表L已存在// 操作结果:删除L的第i个位置的元素并通过e返回LinkList q,p = L;int j = 0;if (i <= 0 || i > ListLength(L) + 1) // 超出范围无法删除第i个元素return false;//找到第i-1个结点while (j < i - 1){p = p->next;j++;}q = p->next;//保存第i结点的指针e = q->data;//保存第i个结点的值p->next = q->next;//第i-1个结点指向第i+1个结点free(q);//释放第i个结点return true;
}

数据结构笔记(五)-- 循环链表的实现相关推荐

  1. 数据结构笔记五_树(c++超详细版)

    目录 树 1.树的概念 1.1 树的逻辑结构和基本运算 1.1.1 树的定义 1.1.2 树的常见基本操作 1.2 树的物理结构 2.二叉树 2.1 二叉树的概念 2.1.1 二叉树的定义 2.1.2 ...

  2. 数据结构笔记(王道考研) 第五章:树和二叉树

    大部分内容基于中国大学MOOC的2021考研数据结构课程所做的笔记,该课属于付费课程(不过盗版网盘资源也不难找...).后续又根据23年考研的大纲对内容做了一些调整,将二叉排序树和平衡二叉树的内容挪到 ...

  3. 数据结构笔记--线性表定义与实现(Swift)

    数据结构笔记系列 数据结构笔记-两个有序链表合并成一个有序链表 线性表   线性表是最常用且最简单的一种数据结构,简言之,一个线性表是 n 个数据元素的有序序列. 特点 只有一个首结点和尾结点: 除首 ...

  4. 数据结构笔记(王道考研) 第八章:排序

    大部分内容基于中国大学MOOC的2021考研数据结构课程所做的笔记,该课属于付费课程(不过盗版网盘资源也不难找...).后续又根据23年考研的大纲对内容做了一些调整,将二叉排序树和平衡二叉树的内容挪到 ...

  5. 一、考研数据结构笔记——引言及目录

    一.关于我理解的数据结构 1. 引言 本人自2021年3月准备考研,考研主要是为了提升学历,本科院校不是理想.迫切需要提高学历. 写这刊博客,主要是总结我考研路上对数据结构的一些理解,以及为了方便我后 ...

  6. 18、数据结构笔记之十八链表实现稀疏矩阵

    18.数据结构笔记之十八链表实现稀疏矩阵 "必须如蜜蜂一样,采过许多花,才能酿出蜜来." 上篇中实现了栈在多项式实现中的例子,再来看下稀疏矩阵通过链表方式实现. 关键字:十字链表存 ...

  7. 数据结构笔记(王道考研) 第一章:绪论

    大部分内容基于中国大学MOOC的2021考研数据结构课程所做的笔记,该课属于付费课程(不过盗版网盘资源也不难找...).后续又根据23年考研的大纲对内容做了一些调整,将二叉排序树和平衡二叉树的内容挪到 ...

  8. 数据结构笔记(王道考研) 第七章:查找

    大部分内容基于中国大学MOOC的2021考研数据结构课程所做的笔记,该课属于付费课程(不过盗版网盘资源也不难找...).后续又根据23年考研的大纲对内容做了一些调整,将二叉排序树和平衡二叉树的内容挪到 ...

  9. 2022天勤考研数据结构笔记 第2章 线性表

    2022天勤考研数据结构笔记 第2章 线性表(更新中) 第2章 线性表 2.1 结构体定义 2.2 顺序表 2.3 单链表 2.4 双链表 2.5 循环链表 2.6 逆置问题(408重要考点) 第2章 ...

  10. 浙大2020年Mooc数据结构笔记--第三讲 树(下)

    浙大2020年Mooc数据结构笔记–第三讲 树(下) 〇.前言 这几天开始跟着学数据结构,鉴于当初数据结构实在学的太弱,加之这项工作算是为大家之后复习.机试铺路.确实是一个迫切需要做的大规模工作.行胜 ...

最新文章

  1. 银行业数据中心性能测试的策略与实践(PPT)
  2. Python 多进程pool.map()方法的使用
  3. 前端学习(1672):前端系列实战课程之加速减速运动
  4. Markdown写作入门
  5. java更改用户邮箱_git 修改提交邮箱以及用户名-亲测
  6. 通过Homestead安装Laravel
  7. 微信小程序没登录跳到登录页怎么做_微信小程序退出按钮回退到登录页面
  8. DES算法是对称算法吗,能否通过在线工具进行DES解密?
  9. linux 360云盘下载文件夹里,360安全云盘Linux版图文使用说明
  10. MATLAB clc clear
  11. 企业做好绩效管理的四种方法
  12. 刘元普双生贵子(但行好事,莫问前程)
  13. 015:苹果和虫子2
  14. 随手记录导入导出功能
  15. C# 计算指定年月的当月工作日方法
  16. register关键字
  17. 清华大学计算机王佳希,【旧文】北大清华2012年拟录取保送生名单及简析(北京市)...
  18. c语言域宽参数,输入%5d是什么意思?
  19. ElementUI的消息提示框及确认框
  20. Kaggle小技巧:TTA(test time augmentation)测试时增强

热门文章

  1. python数据分析系列教程——Pandas全解
  2. 【Proteus仿真8086】往8086 内存中写入数据
  3. multisim仿真D触发器设计的模六计数器并在数码管显示0-5
  4. Shell 脚本语法
  5. 纯CSS3动画按钮效果
  6. mysql分组查询n条记录
  7. 阿里云部署flask
  8. Android打包使用自有证书认证
  9. dynamic结合匿名类型 匿名对象传参
  10. 楼市信贷新政力度超市场预期 房企放风要涨价