第 2 章 线性表 (线性表的静态单链表存储结构(一个数组可生成若干静态链表)实现)

news2024/11/29 4:51:05

1. 背景说明

静态单链表实现类似于单链表,只是指针域变成了数组下标。

2. 示例代码

1) status.h

/* DataStructure 预定义常量和类型头文件 */

#ifndef STATUS_H
#define STATUS_H

/* 函数结果状态码 */
#define TRUE 					1			/* 返回值为真 */
#define FALSE 					0			/* 返回值为假 */
#define RET_OK 					0			/* 返回值正确 */
#define INFEASIABLE    		   	2			/* 返回值未知 */
#define ERR_MEMORY     		   	3			/* 访问内存错 */
#define ERR_NULL_PTR   			4			/* 空指针错误 */
#define ERR_MEMORY_ALLOCATE		5			/* 内存分配错 */
#define ERR_NULL_STACK			6			/* 栈元素为空 */
#define ERR_PARA				7			/* 函数参数错 */
#define ERR_OPEN_FILE			8			/* 打开文件错 */
#define ERR_NULL_QUEUE			9			/* 队列为空错 */
#define ERR_FULL_QUEUE			10			/* 队列为满错 */
#define ERR_NOT_FOUND			11			/* 表项不存在 */
typedef int Status;							/* Status 是函数的类型,其值是函数结果状态代码,如 RET_OK 等 */
typedef int Bollean;						/* Boolean 是布尔类型,其值是 TRUE 或 FALSE */

#endif // !STATUS_H

2)  staticLinkListMulti.h

/* 线性表的静态单链表存储结构(一个数组可生成若干静态链表)实现头文件 */

#ifndef STATICLINKLISTMULTI_H
#define STATICLINKLISTMULTI_H

#include "status.h"

#define MAX_SIZE 100

typedef int ElemType;

typedef struct {
	ElemType data;
	int curr;
} SLinkList[MAX_SIZE];

/* 算法 2.15, 若备用链表非空,则返回分配的结点下标(备用链表的第一个结点),否则返回 0 */
int Malloc(SLinkList space);

/* 算法 2.16, 将下标为 i 的空闲结点回收到备用链表(成为备用链表的第一个结点) */
void Free(SLinkList L, int i);

/* 静态数组无法被销毁 */
void DestroyList(void);

/* 算法 2.14, 将一维数组 L 中各分量链成一个备用链表,L[0].curr 为头指针。'0' 表示空指针 */
void InitSpace(SLinkList L);

/* 构造一个空链表,返回值为空表在数组中的位序 */
int InitList(SLinkList L);

/* 初始条件:L 中表头位序为 n 的静态链表已存在。
   操作结果:将此表重置为空表 */
Status ClearList(SLinkList L, int n);

/* 判断 L 中表头位序为 n 的链表是否空,若是空表返回 TRUE; 否则返回 FALSE */
Bollean ListEmpty(SLinkList L, int n);

/* 返回 L 中表头位序为 n 的链表的数据元素个数 */
int ListLength(SLinkList L, int n);

/* 用 e 返回 L 中表头位序为 n 的链表的第 i 个元素的值 */
Status GetElem(SLinkList L, int n, int i, ElemType *e);

/* 算法 2.13, 在 L 中表头位序为 n 的静态单链表中查找第 1 个值为 e 的元素
   若找到,则返回它在 L 中的位序,否则返回 0 */
int LocateElem(SLinkList L, int n, ElemType e);

/* 初始条件:在 L 中表头位序为 n 的静态单链表已存在
   操作结果:若 curr_e 是此单链表的数据元素,且不是第一个
   则用 pre_e 返回它的前驱,否则操作失败,pre_e 无定义 */
Status PriorElem(SLinkList L, int n, ElemType curr_e, ElemType *pre_e);

/* 初始条件:在 L 中表头位序为 n 的静态单链表已存在
   操作结果:若 curr_e 是此单链表的数据元素,且不是最后一个
   则用 next_e 返回它的后继,否则操作失败,next_e 无定义 */
Status NextElem(SLinkList L, int n, ElemType curr_e, ElemType *next_e);

/* 在 L 中表头位序为 n 的链表的第 i 个元素之前插入新的数据元素 e */
Status ListInsert(SLinkList L, int n, int i, ElemType e);

/* 删除在 L 中表头位序为 n 的链表的第 i 个数据元素 e,并返回其值 */
Status ListDelete(SLinkList L, int n, int i, ElemType *e);

/* 依次对 L 中表头位序为 n 的链表的每个数据元素,调用函数 vi()。一旦 vi() 失败,则操作失败 */
Status ListTraverse(SLinkList L, int n, void(*vi)(ElemType));

#endif // !STATICLINKLISTMULTI_H

3) staticLinkListMulti.c

/*  线性表的静态单链表存储结构(一个数组可生成若干静态链表)实现源文件 */

#include "staticLinkListMulti.h"
#include <stdio.h>

/* 算法 2.15, 若备用链表非空,则返回分配的结点下标(备用链表的第一个结点),否则返回 0 */
int Malloc(SLinkList space)
{
	int i = space[0].curr;
	if (i) {
		space[0].curr = space[i].curr;
	}

	return i;
}

/* 算法 2.16, 将下标为 i 的空闲结点回收到备用链表(成为备用链表的第一个结点) */
void Free(SLinkList space, int i)
{
	space[i].curr = space[0].curr;
	space[0].curr = i;
}

/* 静态数组无法被销毁 */
void DestroyList(void)
{
	printf("Can not destroy the static link list\n");
}

/* 算法 2.14, 将一维数组 L 中各分量链成一个备用链表,L[0].curr 为头指针。'0' 表示空指针 */
void InitSpace(SLinkList L)
{
	for (int i = 0; i < MAX_SIZE - 1; ++i) {
		L[i].curr = i + 1;
	}

	L[MAX_SIZE - 1].curr = 0;
}

/* 构造一个空链表,返回值为空表在数组中的位序 */
int InitList(SLinkList L)
{
	int i = Malloc(L);
	L[i].curr = 0;

	return i;
}

/* 初始条件:L 中表头位序为 n 的静态链表已存在。
   操作结果:将此表重置为空表 */
Status ClearList(SLinkList L, int n)
{
	int i = L[n].curr;
	L[n].curr = 0;
	int head = L[0].curr;
	L[0].curr = i;
	int j;
	while (i) {
		j = i;
		i = L[i].curr;
	}

	L[j].curr = head;

	return RET_OK;
}

/* 判断 L 中表头位序为 n 的链表是否空,若是空表返回 TRUE; 否则返回 FALSE */
Bollean ListEmpty(SLinkList L, int n)
{
	return (L[n].curr == 0) ? TRUE : FALSE;
}

/* 返回 L 中表头位序为 n 的链表的数据元素个数 */
int ListLength(SLinkList L, int n)
{
	int i = L[n].curr;
	int length = 0;
	while (i) {
		++length;
		i = L[i].curr;
	}

	return length;
}

/* 用 e 返回 L 中表头位序为 n 的链表的第 i 个元素的值 */
Status GetElem(SLinkList L, int n, int i, ElemType *e)
{
	if ((i < 1) || (i > ListLength(L, n))) {
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_PARA);
		return ERR_PARA;
	}

	int head = n;
	for (int j = 0; j < i; ++j) {
		head = L[head].curr;
	}

	*e = L[head].data;

	return RET_OK;
}

/* 算法 2.13, 在 L 中表头位序为 n 的静态单链表中查找第 1 个值为 e 的元素
   若找到,则返回它在 L 中的位序,否则返回 0 */
int LocateElem(SLinkList L, int n, ElemType e)
{
	int i = L[n].curr;
	while ((i) && (L[i].data != e)) {
		i = L[i].curr;
	}

	return i;
}

/* 初始条件:在 L 中表头位序为 n 的静态单链表已存在
   操作结果:若 curr_e 是此单链表的数据元素,且不是第一个
   则用 pre_e 返回它的前驱,否则操作失败,pre_e 无定义 */
Status PriorElem(SLinkList L, int n, ElemType curr_e, ElemType *pre_e)
{
	int i = L[n].curr;
	int pre;
	do {
		pre = i;
		i = L[i].curr;
	} while ((i) && (curr_e != L[i].data));

	if (!i) {
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_NOT_FOUND);
		return ERR_NOT_FOUND;
	}

	*pre_e = L[pre].data;

	return RET_OK;
}

/* 初始条件:在 L 中表头位序为 n 的静态单链表已存在
   操作结果:若 curr_e 是此单链表的数据元素,且不是最后一个
   则用 next_e 返回它的后继,否则操作失败,next_e 无定义 */
Status NextElem(SLinkList L, int n, ElemType curr_e, ElemType *next_e)
{
	int i = LocateElem(L, n, curr_e);
	if (i) {
		i = L[i].curr;
		if (i) {
			*next_e = L[i].data;
			
			return RET_OK;
		}
	}

	printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_NOT_FOUND);

	return ERR_NOT_FOUND;
}

/* 在 L 中表头位序为 n 的链表的第 i 个元素之前插入新的数据元素 e */
Status ListInsert(SLinkList L, int n, int i, ElemType e)
{
	if ((i < 1) || (i > ListLength(L, n) + 1)) {
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_PARA);
		return ERR_PARA;
	}

	int newNode = Malloc(L);
	if (!newNode) {
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_MEMORY_ALLOCATE);
		return ERR_MEMORY_ALLOCATE;
	}

	L[newNode].data = e;
	int head = n;
	for (int j = 0; j < i - 1; ++j) {
		head = L[head].curr;
	}

	L[newNode].curr = L[head].curr;
	L[head].curr = newNode;

	return RET_OK;
}

/* 删除在 L 中表头位序为 n 的链表的第 i 个数据元素 e,并返回其值 */
Status ListDelete(SLinkList L, int n, int i, ElemType *e)
{
	if ((i < 1) || (i > ListLength(L, n))) {
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_PARA);
		return ERR_PARA;
	}

	int head = n;
	for (int j = 0; j < i - 1; ++j) {
		head = L[head].curr;
	}

	i = L[head].curr;
	L[head].curr = L[i].curr;
	*e = L[i].data;
	Free(L, i);

	return RET_OK;
}

/* 依次对 L 中表头位序为 n 的链表的每个数据元素,调用函数 vi()。一旦 vi() 失败,则操作失败 */
Status ListTraverse(SLinkList L, int n, void(*vi)(ElemType))
{
	int i = L[n].curr;
	while (i) {
		vi(L[i].data);
		i = L[i].curr;
	}

	return RET_OK;
}

4) mian.c

/* 入口查询源文件 */

#include "staticLinkListMulti.h"
#include <stdio.h>

void Visit(ElemType e);

int main(void)
{
	SLinkList L;
	InitSpace(L);
	int La = InitList(L);
	int Lb = InitList(L);
	printf("La is %s, The length of La is %d\n", (ListEmpty(L, La) == TRUE) ? "empty" : "not empty",
		ListLength(L, La));
	for (int i = 0; i < 5; ++i) {
		ListInsert(L, La, 1, i + 1);
	}

	printf("After insert 1 ~ 5 in the head of La, La is : ");
	ListTraverse(L, La, Visit);
	printf("\n");
	for (int i = 0; i < 5; ++i) {
		ListInsert(L, Lb, i + 1, i + 1);
	}

	printf("After insert 1 ~ 5 in the end of Lb, Lb is: ");
	ListTraverse(L, Lb, Visit);
	printf("\n");
	printf("La is %s, The length of La is %d\n", (ListEmpty(L, La) == TRUE) ? "empty" : "not empty",
		ListLength(L, La));
	ClearList(L, La);
	printf("After clear La, La is: ");
	ListTraverse(L, La, Visit);
	printf("La is %s, The length of La is %d\n", (ListEmpty(L, La) == TRUE) ? "empty" : "not empty",
		ListLength(L, La));
	for (int i = 2; i < 8; i += 5) {
		ElemType e;
		int ret = GetElem(L, Lb, i, &e);
		if (ret == RET_OK) {
			printf("The %dth element of Lb is %d\n", i, e);
		} else {
			printf("The %dth element of Lb is not exist\n", i);
		}
	}

	for (int i = 0; i < 2; ++i) {
		int ret = LocateElem(L, Lb, i);
		if (ret) {
			printf("The order of element of %d of Lb in static link list is %d\n", i, ret);
		} else {
			printf("The element of %d is not exist in Lb\n", i);
		}
	}

	for (int i = 1; i <= 2; ++i) {
		ElemType e;
		GetElem(L, Lb, i, &e);
		ElemType pre;
		int ret = PriorElem(L, Lb, e, &pre);
		if (ret != RET_OK) {
			printf("There is no previous element of element %d\n", e);
		} else {
			printf("The previous element of element %d is %d\n", e, pre);
		}
	}

	for (int i = ListLength(L, Lb) - 1; i <= ListLength(L, Lb); ++i) {
		ElemType e;
		GetElem(L, Lb, i, &e);
		ElemType next;
		int ret = NextElem(L, Lb, e, &next);
		if (ret != RET_OK) {
			printf("There is no next element of element %d in Lb\n", e);
		} else {
			printf("The next element of %d in Lb is %d\n", e, next);
		}
	}

	int length = ListLength(L, Lb);
	for (int i = length + 1; i >= length; --i) {
		ElemType e;
		int ret = ListDelete(L, Lb, i, &e);
		if (ret == RET_OK) {
			printf("The %dth element of Lb is %d, has been deleted\n", i, e);
		} else {
			printf("%dth elemetn of Lb is not exist\n", i);
		}
	}

	printf("Now Lb is: ");
	ListTraverse(L, Lb, Visit);

	return 0;
}

void Visit(ElemType e)
{
	printf("%d ", e);
}

3. 输出示例

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/987155.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从策略到执行:实施战略定位的实战手册

有了完美的战略定位蓝图&#xff0c;但如果不知道如何执行&#xff0c;那一切都是徒劳。今天&#xff0c;我们将揭示从策略到执行的战略定位秘密路径。首先我们先明确一下战略定位的相关概念以及实施战略定位的用途。 战略定位是什么意思? 战略定位可以视为企业在市场或竞争环…

Jetpack Compose 教程

一、简介 Jetpack Compose 是用于构建原生 Android 界面的新工具包。它使用更少的代码、强大的工具和直观的 Kotlin API&#xff0c;可以帮助您简化并加快 Android 界面开发。 在本教程中&#xff0c;您将使用声明性的函数构建一个简单的界面组件。您无需修改任何 XML 布局&am…

读高性能MySQL(第4版)笔记04_操作系统和硬件优化

1. 从软件本身和它运行的典型工作负载来看&#xff0c;MySQL通常也更适合运行在廉价硬件上 2. 基本资源 2.1. CPU 2.2. 内存 2.3. 磁盘 2.4. 瓶颈 2.5. 网络资源 3. CPU 3.1. 最常见的瓶颈是CPU耗尽 3.2. 检查CPU使用率来确定工作负载是否受CPU限制 3.3. 低延迟&…

JavaScipt中如何实现函数缓存?函数缓存有哪些场景?

1、函数缓存是什么&#xff1f; 函数缓存就是将函数运行的结果进行缓存。本质上就是用空间&#xff08;缓存存储&#xff09;换时间&#xff08;计算过程&#xff09; 常用于缓存数据计算结果和缓存对象。 缓存只是一个临时的数据存储&#xff0c;它保存数据&#xff0c;以便将…

异步编程 - 09 Spring框架中的异步执行_@Async注解异步执行原理源码解析

文章目录 概述小结好文推荐 概述 在Spring中调用线程将在调用含有Async注释的方法时立即返回&#xff0c;Spring是如何做到的呢&#xff1f;其实是其对标注Async注解的类做了代理&#xff0c;比如下面的类Async-AnnotationExample。 public class AsyncAnnotationExample {As…

Qt 5.15集成Crypto++ 8.8.0(MSVC 2019)笔记

一、背景 笔者已介绍过在Qt 5.15.x中使用MinGW&#xff08;8.10版本&#xff09;编译并集成Crypto 8.8.0。 但是该编译出来的库&#xff08;.a和.dll&#xff09;不适用MSVC&#xff08;2019版本&#xff09;构建环境&#xff0c;需要重新编译&#xff08;.lib或和.dll&#xf…

C++11新特性② | 左值、左值引用、右值与右值引用

目录 1、引言 2、值类别及相关概念 3、左值、右值 4、左值引用、右值引用 5、移动语义 5.1、为什么需要移动语义 5.2、移动语义定义 5.3、转移构造函数 5.4、转移赋值函数 6、标准库函数 std::move 7、完美转发 std::forward VC常用功能开发汇总&#xff08;专栏文章…

Mybatis 使用typeHandler自定义类型转换

之前我们介绍了使用Mybatis完成数据的增删改查操作&#xff1b;本篇我们介绍使用Mybatis提供的typeHandler自定义类型转换。 如果您对Mybatis的增删改查操作不太了解&#xff0c;可以参考&#xff1a; Mybatis 查询数据https://blog.csdn.net/m1729339749/article/details/13…

explain 实战-----查看hive sql执行计划

目录 1.join/left join/full join 语句会过滤关联字段 null 的值吗&#xff1f; &#xff08;1&#xff09;join &#xff08;2&#xff09; left join /full join 2.group by 分组语句会进行排序吗&#xff1f; 1.join/left join/full join 语句会过滤关联字段 null 的值吗…

Qt 5.15编译(MinGW)及集成Crypto++ 8.8.0笔记

一、背景 为使用AES加密库&#xff08;AES/CBC加解密&#xff09;&#xff0c;选用Crypto 库&#xff08;官网&#xff09;。   最新Crypto C库依次为&#xff1a;8.8.0版本&#xff08;2023-6-25&#xff09;、8.7.0&#xff08;2022-8-7&#xff09;和8.6.0&#xff08;202…

绘图系统三:支持散点图、极坐标和子图绘制

文章目录 新增散点图绘制绑定与回调极坐标功能子图绘制功能源代码 &#x1f4c8;一 三维绘图系统&#x1f4c8;二 多图绘制系统 新增散点图绘制 同一坐标系中绘制多个图像是很常见的需求&#xff0c;比如数据拟合的时候&#xff0c;用散点图表示原始数据&#xff0c;用曲线图…

vue3 webpack打包流程及安装 (1)

npm run build 也可以打包 如果没有特殊需求 可以使用 效果其实是差不多的 --------------------------------------------------------------------------------------------------------------------------------- webpack网址 &#xff1a; 起步 | webpack 中文文档 (docsc…

记录docker 部署nessus

1、开启容器 docker run -itd --nameramisec_nessus -p 8834:8834 ramisec/nessus 2、登录 &#xff1a;注意是https https://ip8843 3、修改admin密码 #进入容器 docker exec -it ramisec_nessus /bin/bash#列出用户名 /opt/nessus/sbin/nessuscli lsuser#修改密码&a…

(html+CSS)垂直居中

line-height 设置文字行高等于父元素的高度 vertical-align 用于设置一个元素的垂直对齐方式&#xff0c;但是它只针对于行内元素或者行内块元素有效。 属性值说明baseline默认&#xff0c;元素放置在父元素的基线上top把元素的顶端与行中最高元素的顶端对齐middle把此元素…

递归算法学习——黄金矿工,不同路径III

目录 ​编辑 一&#xff0c;黄金矿工 1.题意 2.题目分析 3.题目接口 4.解题思路及代码 二&#xff0c;不同路径III 1.题意 2.解释 3.题目接口 4.解题思路及代码 一&#xff0c;黄金矿工 1.题意 你要开发一座金矿&#xff0c;地质勘测学家已经探明了这座金矿中的资源…

YMatrix 5.0 与天翼云完成产品兼容性认证

近日&#xff0c;北京四维纵横数据技术有限公司与天翼云宣布完成产品兼容性认证。经过双方严格的测试验证&#xff0c;超融合数据库 YMatrix 5.0 与天翼云兼容性良好&#xff0c;可基于天翼云稳定运行。 数据库系统作为基础软件的核心&#xff0c;自主可控势在必行。在此背景下…

项目(智慧教室)第一部分:cubemx配置,工程文件的移植,触摸屏的检测,项目bug说明

第一章&#xff1a;需求与配置 一。项目需求 二。实现外设控制 注意&#xff1a; 先配置引脚&#xff0c;再配置外设。否则会出现一些不可预料的问题 1.时钟&#xff0c;串口&#xff0c;灯&#xff0c;蜂鸣器配置 &#xff08;1&#xff09;RCC配置为外部时钟&#xff0c;修…

Android 开发小贴士

Android 开发小贴士 Unable to merge dex 原因&#xff1a; 1. 包引用重复 2. 方法数超限 3. 或者几个库之间有重复代码块(特别是在整理module时容易犯) 解决&#xff1a; 1. app的build.gradle中 // 1. 添加配置 defaultConfig {......multiDexEnabled true }// 2. 清除缓…

pico学习进程记录已经开发项目

Pico pin脚定义 Pico 运行准备 下载uf2文件 https://pico.org.cn/ &#xff08;注意运行micropython的文件和运行c/c的不一样&#xff09; 装载uf2文件&#xff1a;按住pico的按键&#xff0c;然后通过micro usb连接电脑&#xff08;注意&#xff1a;如果用的线材&#xff0c;…

菜鸟教程《Python 3 教程》笔记(19):错误与异常

菜鸟教程《Python 3 教程》笔记&#xff08;19&#xff09; 19 错误和异常19.1 assert&#xff08;断言&#xff09;19.2 异常处理19.2.1 try/except19.2.2 try/except...else19.2.3 try-finally 语句 19.3 抛出异常19.4 用户自定义异常19.5 清理行为19.5.1 定义清理行为19.5.2…