数据结构笔记(五)-- 循环链表的实现
单循环链表的实现
单循环链表就是让单链表的尾结点指向头结点
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;
}
数据结构笔记(五)-- 循环链表的实现相关推荐
- 数据结构笔记五_树(c++超详细版)
目录 树 1.树的概念 1.1 树的逻辑结构和基本运算 1.1.1 树的定义 1.1.2 树的常见基本操作 1.2 树的物理结构 2.二叉树 2.1 二叉树的概念 2.1.1 二叉树的定义 2.1.2 ...
- 数据结构笔记(王道考研) 第五章:树和二叉树
大部分内容基于中国大学MOOC的2021考研数据结构课程所做的笔记,该课属于付费课程(不过盗版网盘资源也不难找...).后续又根据23年考研的大纲对内容做了一些调整,将二叉排序树和平衡二叉树的内容挪到 ...
- 数据结构笔记--线性表定义与实现(Swift)
数据结构笔记系列 数据结构笔记-两个有序链表合并成一个有序链表 线性表 线性表是最常用且最简单的一种数据结构,简言之,一个线性表是 n 个数据元素的有序序列. 特点 只有一个首结点和尾结点: 除首 ...
- 数据结构笔记(王道考研) 第八章:排序
大部分内容基于中国大学MOOC的2021考研数据结构课程所做的笔记,该课属于付费课程(不过盗版网盘资源也不难找...).后续又根据23年考研的大纲对内容做了一些调整,将二叉排序树和平衡二叉树的内容挪到 ...
- 一、考研数据结构笔记——引言及目录
一.关于我理解的数据结构 1. 引言 本人自2021年3月准备考研,考研主要是为了提升学历,本科院校不是理想.迫切需要提高学历. 写这刊博客,主要是总结我考研路上对数据结构的一些理解,以及为了方便我后 ...
- 18、数据结构笔记之十八链表实现稀疏矩阵
18.数据结构笔记之十八链表实现稀疏矩阵 "必须如蜜蜂一样,采过许多花,才能酿出蜜来." 上篇中实现了栈在多项式实现中的例子,再来看下稀疏矩阵通过链表方式实现. 关键字:十字链表存 ...
- 数据结构笔记(王道考研) 第一章:绪论
大部分内容基于中国大学MOOC的2021考研数据结构课程所做的笔记,该课属于付费课程(不过盗版网盘资源也不难找...).后续又根据23年考研的大纲对内容做了一些调整,将二叉排序树和平衡二叉树的内容挪到 ...
- 数据结构笔记(王道考研) 第七章:查找
大部分内容基于中国大学MOOC的2021考研数据结构课程所做的笔记,该课属于付费课程(不过盗版网盘资源也不难找...).后续又根据23年考研的大纲对内容做了一些调整,将二叉排序树和平衡二叉树的内容挪到 ...
- 2022天勤考研数据结构笔记 第2章 线性表
2022天勤考研数据结构笔记 第2章 线性表(更新中) 第2章 线性表 2.1 结构体定义 2.2 顺序表 2.3 单链表 2.4 双链表 2.5 循环链表 2.6 逆置问题(408重要考点) 第2章 ...
- 浙大2020年Mooc数据结构笔记--第三讲 树(下)
浙大2020年Mooc数据结构笔记–第三讲 树(下) 〇.前言 这几天开始跟着学数据结构,鉴于当初数据结构实在学的太弱,加之这项工作算是为大家之后复习.机试铺路.确实是一个迫切需要做的大规模工作.行胜 ...
最新文章
- 银行业数据中心性能测试的策略与实践(PPT)
- Python 多进程pool.map()方法的使用
- 前端学习(1672):前端系列实战课程之加速减速运动
- Markdown写作入门
- java更改用户邮箱_git 修改提交邮箱以及用户名-亲测
- 通过Homestead安装Laravel
- 微信小程序没登录跳到登录页怎么做_微信小程序退出按钮回退到登录页面
- DES算法是对称算法吗,能否通过在线工具进行DES解密?
- linux 360云盘下载文件夹里,360安全云盘Linux版图文使用说明
- MATLAB clc clear
- 企业做好绩效管理的四种方法
- 刘元普双生贵子(但行好事,莫问前程)
- 015:苹果和虫子2
- 随手记录导入导出功能
- C# 计算指定年月的当月工作日方法
- register关键字
- 清华大学计算机王佳希,【旧文】北大清华2012年拟录取保送生名单及简析(北京市)...
- c语言域宽参数,输入%5d是什么意思?
- ElementUI的消息提示框及确认框
- Kaggle小技巧:TTA(test time augmentation)测试时增强