单循环链表实现(设立尾指针)(第二章 P35)

2023-10-31

设立尾指针的单循环链表

 

单链的循环链表结点的存储结构和单链表的存储结构一样,所不同的是:最后一个结点的 next 域指向头结点,而不是“空”。这样,由表尾很容易找到表头。

但若链表较长,则由表头找到表尾较费时,因而,单循环链表往往设立尾指针而不是头指针。

例:设立尾指针且具有 2 个结点(4,7)的单循环链表:

 

空(仅有头结点)的单循环链表 L:

 

循环链表的操作和线性链表基本一致,差别仅在于算法中的循环条件不是 p 或 p->next 是否为空,而是它们是否等于尾指针(我这里为方便设立的是尾指针,设立头指针也是一样的)。

 

typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
typedef int ElemType;

#include<malloc.h> /* malloc()等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<process.h> /* exit() */

/* 函数结果状态代码 */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
//#define OVERFLOW -2 


/* -----------------------      线性表的单链表存储结构    ------------------------*/

struct LNode
{
	ElemType data;
	struct LNode *next;
};
typedef struct LNode *LinkList; /* 另一种定义LinkList的方法 */


/* ---------------------------------------------------------------------------*/

Status compare(ElemType c1, ElemType c2)
{
	if (c1 == c2)
		return TRUE;
	else
		return FALSE;
}

void visit(ElemType c)
{
	printf("%d ", c);
}


/* -------------        设立尾指针的单循环链表基本操作的函数原型说明     ---------------*/
Status InitList_CL(LinkList *L);
Status DestroyList_CL(LinkList *L);
Status ClearList_CL(LinkList *L);
Status ListEmpty_CL(LinkList L);
int ListLength_CL(LinkList L);
Status GetElem_CL(LinkList L, int i, ElemType *e);
int LocateElem_CL(LinkList L, ElemType e, Status(*compare)(ElemType, ElemType));
Status PriorElem_CL(LinkList L, ElemType cur_e, ElemType *pre_e);
Status NextElem_CL(LinkList L, ElemType cur_e, ElemType *next_e);
Status ListInsert_CL(LinkList *L, int i, ElemType e);
Status ListDelete_CL(LinkList *L, int i, ElemType *e);
Status ListTraverse_CL(LinkList L, void(*vi)(ElemType));


/* ---------------------------------     设立尾指针的单循环链表的12个基本操作  -----------------------------------*/


Status InitList_CL(LinkList *L)
{ /* 操作结果:构造一个空的线性表L */
	*L = (LinkList)malloc(sizeof(struct LNode)); /* 产生头结点,并使L指向此头结点 */
	if (!*L) /* 存储分配失败 */
		exit(OVERFLOW);
	(*L)->next = *L; /* 指针域指向头结点 */
	return OK;
}

Status DestroyList_CL(LinkList *L)
{ /* 操作结果:销毁线性表L */
	LinkList q, p = (*L)->next; /* p指向头结点 */
	while (p != *L) /* 没到表尾 */
	{
		q = p->next;
		free(p);
		p = q;
	}
	free(*L);
	*L = NULL;
	return OK;
}

Status ClearList_CL(LinkList *L) /* 改变L */
{ /* 初始条件:线性表L已存在。操作结果:将L重置为空表 */
	LinkList p, q;
	*L = (*L)->next; /* L指向头结点 */
	p = (*L)->next; /* p指向第一个结点 */
	while (p != *L) /* 没到表尾 */
	{
		q = p->next;
		free(p);
		p = q;
	}
	(*L)->next = *L; /* 头结点指针域指向自身 */
	return OK;
}

Status ListEmpty_CL(LinkList L)
{ /* 初始条件:线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE */
	if (L->next == L) /* 空 */
		return TRUE;
	else
		return FALSE;
}

int ListLength_CL(LinkList L)
{ /* 初始条件:L已存在。操作结果:返回L中数据元素个数 */
	int i = 0;
	LinkList p = L->next; /* p指向头结点 */
	while (p != L) /* 没到表尾 */
	{
		i++;
		p = p->next;
	}
	return i;
}

Status GetElem_CL(LinkList L, int i, ElemType *e)
{ /* 当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR */
	int j = 1; /* 初始化,j为计数器 */
	LinkList p = L->next->next; /* p指向第一个结点 */
	if (i <= 0 || i > ListLength_CL(L)) /* 第i个元素不存在 */
		return ERROR;
	while (j < i)
	{ /* 顺指针向后查找,直到p指向第i个元素 */
		p = p->next;
		j++;
	}
	*e = p->data; /* 取第i个元素 */
	return OK;
}

int LocateElem_CL(LinkList L, ElemType e, Status(*compare)(ElemType, ElemType))
{ /* 初始条件:线性表L已存在,compare()是数据元素判定函数 */
  /* 操作结果:返回L中第1个与e满足关系compare()的数据元素的位序。 */
  /*           若这样的数据元素不存在,则返回值为0 */
	int i = 0;
	LinkList p = L->next->next; /* p指向第一个结点 */
	while (p != L->next)
	{
		i++;
		if (compare(p->data, e)) /* 满足关系 */
			return i;
		p = p->next;
	}
	return 0;
}

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

Status NextElem_CL(LinkList L, ElemType cur_e, ElemType *next_e)
{ /* 初始条件:线性表L已存在 */
  /* 操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继, */
  /*           否则操作失败,next_e无定义 */
	LinkList p = L->next->next; /* p指向第一个结点 */
	while (p != L) /* p没到表尾 */
	{
		if (p->data == cur_e)
		{
			*next_e = p->next->data;
			return TRUE;
		}
		p = p->next;
	}
	return FALSE;
}

Status ListInsert_CL(LinkList *L, int i, ElemType e) /* 改变L */
{ /* 在L的第i个位置之前插入元素e */
	LinkList p = (*L)->next, s; /* p指向头结点 */
	int j = 0;
	if (i <= 0 || i > ListLength_CL(*L) + 1) /* 无法在第i个元素之前插入 */
		return ERROR;
	while (j < i - 1) /* 寻找第i-1个结点 */
	{
		p = p->next;
		j++;
	}
	s = (LinkList)malloc(sizeof(struct LNode)); /* 生成新结点 */
	s->data = e; /* 插入L中 */
	s->next = p->next;
	p->next = s;
	if (p == *L) /* 改变尾结点 */
		*L = s;
	return OK;
}

Status ListDelete_CL(LinkList *L, int i, ElemType *e) /* 改变L */
{ /* 删除L的第i个元素,并由e返回其值 */
	LinkList p = (*L)->next, q; /* p指向头结点 */
	int j = 0;
	if (i <= 0 || i > ListLength_CL(*L)) /* 第i个元素不存在 */
		return ERROR;
	while (j < i - 1) /* 寻找第i-1个结点 */
	{
		p = p->next;
		j++;
	}
	q = p->next; /* q指向待删除结点 */
	p->next = q->next;
	*e = q->data;
	if (*L == q) /* 删除的是表尾元素 */
		*L = p;
	free(q); /* 释放待删除结点 */
	return OK;
}

Status ListTraverse_CL(LinkList L, void(*vi)(ElemType))
{ /* 初始条件:L已存在。操作结果:依次对L的每个数据元素调用函数vi()。一旦vi()失败,则操作失败 */
	LinkList p = L->next->next;
	while (p != L->next)
	{
		vi(p->data);
		p = p->next;
	}
	printf("\n");
	return OK;
}




/*   检验以上操作的主程序  */

void main()
{
	LinkList L;
	ElemType e;
	int j;
	Status i;
	i = InitList_CL(&L); /* 初始化单循环链表L */
	printf("初始化单循环链表L i=%d (1:初始化成功)\n", i);
	i = ListEmpty_CL(L);
	printf("L是否空 i=%d(1:空 0:否)\n", i);
	ListInsert_CL(&L, 1, 3); /* 在L中依次插入3,5 */
	ListInsert_CL(&L, 2, 5);
	i = GetElem_CL(L, 1, &e);
	j = ListLength_CL(L);
	printf("L中数据元素个数=%d,第1个元素的值为%d。\n", j, e);
	printf("L中的数据元素依次为:");
	ListTraverse_CL(L, visit);
	PriorElem_CL(L, 5, &e); /* 求元素5的前驱 */
	printf("5前面的元素的值为%d。\n", e);
	NextElem_CL(L, 3, &e); /* 求元素3的后继 */
	printf("3后面的元素的值为%d。\n", e);
	printf("L是否空 %d(1:空 0:否)\n", ListEmpty_CL(L));
	j = LocateElem_CL(L, 5, compare);
	if (j)
		printf("L的第%d个元素为5。\n", j);
	else
		printf("不存在值为5的元素\n");
	i = ListDelete_CL(&L, 2, &e);
	printf("删除L的第2个元素:\n");
	if (i)
	{
		printf("删除的元素值为%d,现在L中的数据元素依次为:", e);
		ListTraverse_CL(L, visit);
	}
	else
		printf("删除不成功!\n");
	printf("清空L:%d(1: 成功)\n", ClearList_CL(&L));
	printf("清空L后,L是否空:%d(1:空 0:否)\n", ListEmpty_CL(L));
	printf("销毁L:%d(1: 成功)\n", DestroyList_CL(&L));
}

运行结果:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

单循环链表实现(设立尾指针)(第二章 P35) 的相关文章

  • 富士施乐2022网络扫描设置_富士施乐sc2020网络扫描怎么设置?

    1 在计算机客户端添加一个命名为SMB 命名随意 的共享文件夹 这个文件夹是用来存储局域网网络扫描的文件 使用简单的共享方式设置文件夹属性 勾选 在网络上共享这个文件夹 和 允许网络用户更改我的文件 2 在已经安装好多功能办公设备的计算机客
  • undionly.kpxe php,VLOG

    经过研究 终于可以将ESXI的系统通过IPXE网络启动安装到无盘的软路由或者PC上了 当然也可以通过这种方法安装window linux等等其他的系统 一 编译IPXE增加功能与自定义脚本 一 iPXE 概要 按iPXE 官网的介绍是这样的
  • Java提高篇(二七)-----TreeMap

    原文出自 http cmsblogs com p 1013 尊重作者的成果 转载请注明出处 个人站点 http cmsblogs com TreeMap的实现是红黑树算法的实现 所以要了解TreeMap就必须对红黑树有一定的了解 其实这篇博
  • IOS-Xcode Compile flags

    flag 功能 fno objc arc 该文件不启用ARC fo objc arc 该文件启用ARC w 去除警告
  • 【google版efficientdet】官方版efficientdet训练自己的数据集,终于训练成功了

    看全网还没有一篇攻略 本文是第一个 有心人当点赞下 有问题可以下方留言 互相交流 如转载请注明出处 不枉解决各种各样的bug 环境 v100 cuda10 1 tensorflow2 1 0 python3 7 7 只保证这个版本是可行的
  • NUC980开源项目5-安装repo

    上面是我的微信和QQ群 欢迎新朋友的加入 项目码云地址 国内下载速度快 https gitee com jun626 nuc980 open source project 项目github地址 https github com Jun117

随机推荐

  • Pandas 报错 TypeError: ‘Series‘ objects are mutable, thus they cannot be hashed

    一 需求 根据原始 CSV 文件的列 A 的值 添加一列 B 二 尝试 1 1 将 A 列与 B 列对应的值写入字典 dict A 列为 key B 列为 value 2 将 CSV 文件处理为 DataFrame 3 import pan
  • Python入门02:详细来了解一下Requests库

    那个叫做 Urllib 的库让我们的 python 假装是浏览器 接下来我们要来玩一个新的库 这个库的名称叫做 Requests 这个库比 urllib 可是要牛逼一丢丢的 毕竟 Requests 是在 urllib 的基础上搞出来的 通过
  • 个人笔记随记——在CSDN写随记原因,部分是为了自己复习,查看。

    在CSDN写随记原因 部分是为了自己复习 查看 部分原因是用来分享经验 大家共同进步 之前我的几个电脑里面有个自己的个人数据库 所以笔记都在那里记录 因为现在除了码字 经常不携带电脑 导致笔记不能随时观看 所以现在即在CSDN开了个人博客
  • C++前置声明用法

    前置声明的目的是避免在某个 h文件中include其他头文件 取而代之的是用class struct 声明 类的前置声明就是告诉编译器有这么一个类 它的名字是XXX 甚至不需要知道它具有哪些成员 注意 这里只是声明类 没有分配空间 实例化成
  • kubernetes结合portworx

    参考网址 https docs portworx com scheduler kubernetes install html https docs portworx com scheduler kubernetes support html
  • IDEA配置JDBC

    IDEA配置JDBC 驱动下载 MySQL 首先进入MySQL官网 进入downloads 选择页面最下方 MySQL Community GPL Downloads 选择Connector J link 选择plantform indep
  • 『网络安全』蜜罐到蜜网入门指南(二)蜜罐的起源、作用及分类

    原创不易 点个赞呗 如果喜欢 欢迎随意赞赏 前言 大家好 网络安全 蜜罐到蜜网入门指南 进入第二篇 在第一篇 我们由网络安全入手 由浅入深 引出蜜罐概念 从这一篇开始 我们将主要围绕蜜罐 honeypot 密网 honeynet 继续编写后
  • 前端生成PDF文件实现方案

    一 技术选型 1 html转换成canvas后生成图片导出pdf 本文选用 html转canvas插件 html2canvas是一款将HTML代码转换成Canvas的插件 canvas生成pdf jsPDF是一个使用Javascript语言
  • LeetCode专题:栈和队列(持续更新,已更17题)

    目录 LeetCode150 逆波兰表达式求值 问题描述 代码分析 LeetCode225 用队列实现栈 问题描述 代码分析 LeetCode232 用栈实现队列 问题描述 代码分析 O n 解法 均摊 O 1 解法 关于 均摊复杂度 的说
  • 136. Single Number

    class Solution public int singleNumber vector
  • 用border渐变色实现UI 标题头等高短竖线

    现在的UI 越来越喜欢给标题前面加上短竖线 大家通常的方法 一个是画div图形 用position 方式来定位 一个是用 伪类来给前面增加给元素 实现短竖线 今天在这里实现无dom 的第三种方式 border渐变色 废话不多说 用用到的有
  • 程序员视角m1 Macbook air使用指南和指令备忘录

    m1 Mac使用指南指令备忘录 硬件外设 外接显示器HiDpi homebrew 必备网站 软件推荐 Parallels Desktop Silicon Bob IINA iterm2远程 mysql和redis启动 OhMyZsh设置 磁
  • 1016 部分A+B (15 分)- PAT乙级真题

    题滴链接https pintia cn problem sets 994805260223102976 problems 994805306310115328 1016 部分A B 15 分 正整数 A 的 D A 为 1 位整数 部分 定
  • 实现分页展示

    当数据量较多时 用户需要拖动页面才可以浏览更多消息 分页显示的步骤 思路 确定每页显示的数据量 确定分页显示所需的总页面 编写SQL查询语句 实现数据查询 在JSP页面中进行分页显示设置 一 计算显示总页数 1 select count 1
  • ES6代码转为ES5代码的在线转换工具以及运行工具

    学习es6是一个很有意思的过程 里面新增的语法及语法糖都能大大减少我们的代码量 但有些语法是目前浏览器无法支持的 所以我们需要转换一下 为了方便学习以及测试 下面推荐两款使用的es6在线转换工具 1 Babeljs 在线转换地址 2 es6
  • 神经网络学习小记录70——Keras 使用Google Colab进行深度学习

    神经网络学习小记录70 Keras 使用Google Colab进行深度学习 注意事项 学习前言 什么是Google Colab Colab官网 利用Colab进行训练 一 数据集与预训练权重的上传 1 数据集的上传 2 预训练权重的上传
  • 在idea中如何在控制台输出日志?——用log4j

    简单记录下idea中如何配置使得在控制台输出日志 首先做个对比 输出日志和不输出日志有什么区别 下面的例子是我在学习mybatis中查询数据库时返回的结果 不输出日志的结果显示如下 输出日志的结果显示如下 经过对比 是不是在输出结果的同时把
  • java 语言 if else语句的使用方法

    if else语句的结果如下 if 条件1 代码块1 else if 条件2 代码块2 else 代码块3 if else语句使用方法 如果条件1是true则执行 代码块1 如果条件2是true则执行代码块2 否则执行代码块3 下面是例子
  • XXX项目总结

    目录 1 SQLite 数据库 1 1 创建数据库连接 1 2 打开数据库连接 1 3 关闭数据库连接 1 4 查询数据库示例 结果为单条数据 1 5 查询数据库示例2 结果为多条数据 2 数据转换 2 1 QString 转 std st
  • 单循环链表实现(设立尾指针)(第二章 P35)

    设立尾指针的单循环链表 单链的循环链表结点的存储结构和单链表的存储结构一样 所不同的是 最后一个结点的 next 域指向头结点 而不是 空 这样 由表尾很容易找到表头 但若链表较长 则由表头找到表尾较费时 因而 单循环链表往往设立尾指针而不