第 2 章 线性表 (线性表的单链表存储结构实现)

news2024/11/25 23:32:03

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			/* 队列为满错 */
typedef int Status;							/* Status 是函数的类型,其值是函数结果状态代码,如 RET_OK 等 */
typedef int Bollean;						/* Boolean 是布尔类型,其值是 TRUE 或 FALSE */

#endif // !STATUS_H

2) singleLinkList.h

/* 线性表的单链表存储结构头文件 */

#ifndef SINGLELINKLIST_H
#define SINGLELINKLIST_H

#include "status.h"

typedef int ElemType;

typedef struct LNode {
	ElemType data;
	struct LNode *next;
} *LinkList;

/* 辅助函数,创建一个新的节点 */
LinkList MakeNewLNode(ElemType e);

/* 操作结果:构造一个空的线性表 L */
Status InitList(LinkList *L);

/* 初始条件:线性表 L 已存在。操作结果:销毁线性表 L */
Status DestroyList(LinkList *L);

/* 初始条件:线性表 L 已存在。操作结果:将 L 重置为空表 */
Status ClearList(LinkList L);

/* 初始条件:线性表 L 已存在。操作结果:若 L 为空表,则返回 TRUE,否则返回 FALSE */
Status ListEmpty(LinkList L);

/* 初始条件:线性表 L 已存在。操作结果:返回 L 中数据元素个数 */
int ListLength(LinkList L);

/* 算法 2.8,L 为带头结点的单链表的头指针。当第 i 个元素存在时, 其值赋给 e 并返回 OK,否则返回 ERROR */
Status GetElem(LinkList L, int i, ElemType *e);

/* 初始条件: 线性表 L 已存在, compare() 是数据元素判定函数(满足为 1,否则为 0)
   操作结果: 返回 L 中第 1 个与 e 满足关系 compare() 的数据元素的位序。
   若这样的数据元素不存在,则返回值为 0 */
int LocateElem(LinkList L, ElemType e, Status(*compare)(ElemType, ElemType));

/* 初始条件: 线性表 L 已存在
   操作结果: 若 cur_e 是 L 的数据元素,且不是第一个,则用 pre_e 返回它的前驱
   函数返回 OK;否则操作失败, pre_e 无定义, 返回 INFEASIBLE */
Status PriorElem(LinkList L, ElemType cur_e, ElemType *pre_e);

/* 初始条件:线性表 L 已存在
   操作结果:若 cur_e 是 L 的数据元素,且不是最后一个,则用 next_e 返回它的后继
   函数返回 OK;否则操作失败,next_e无定义,返回 INFEASIBLE */
Status NextElem(LinkList L, ElemType cur_e, ElemType *next_e);

/* 算法 2.9,在带头结点的单链线性表 L 中第 i 个位置之前插入元素 e */
Status ListInsert(LinkList L, int i, ElemType e);

/* 算法 2.10,在带头结点的单链线性表 L 中,删除第 i 个元素,并由 e 返回其值 */
Status ListDelete(LinkList L, int i, ElemType *e);

/* 初始条件:线性表 L 已存在
   操作结果:依次对 L 的每个数据元素调用函数 vi()。一旦 vi() 失败,则操作失败 */
Status ListTraverse(LinkList L, void(*vi)(ElemType));

#endif

3) singleLinkList.c

/* 线性表的单链表存储结构源文件实现 */

#include "singleLinkList.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

/* 辅助函数,创建一个新的节点 */
LinkList MakeNewLNode(ElemType e)
{
	LinkList newLNode = (LinkList)malloc(sizeof(struct LNode));
	if (!newLNode) {
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_MEMORY_ALLOCATE);
		return NULL;
	}

	newLNode->data = e;
	newLNode->next = NULL;

	return newLNode;
}

/* 操作结果:构造一个空的线性表 L */
Status InitList(LinkList *L)
{
	*L = (LinkList)malloc(sizeof(struct LNode));
	if (!(*L)) {
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_MEMORY_ALLOCATE);
		return ERR_MEMORY_ALLOCATE;
	}

	(*L)->next = NULL;

	return RET_OK;
}

/* 初始条件:线性表 L 已存在。操作结果:销毁线性表 L */
Status DestroyList(LinkList *L)
{
	LinkList q;
	while (*L) {
		q = (*L)->next;
		free(*L);
		*L = q;
	}

	return RET_OK;
}

/* 初始条件:线性表 L 已存在。操作结果:将 L 重置为空表 */
Status ClearList(LinkList L)
{
	LinkList p, q;
	p = L->next;
	while (p) {
		q = p->next;
		free(p);
		p = q;
	}

	L->next = NULL;

	return RET_OK;
}

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

	return TRUE;
}

/* 初始条件:线性表 L 已存在。操作结果:返回 L 中数据元素个数 */
int ListLength(LinkList L)
{
	int count = 0;
	LinkList p = L->next;
	while (p) {
		++count;
		p = p->next;
	}

	return count;
}

/* 算法 2.8,L 为带头结点的单链表的头指针。当第 i 个元素存在时, 其值赋给 e 并返回 RET_OK,否则返回 ERROR */
Status GetElem(LinkList L, int i, ElemType *e)
{
	int j = 1;
	LinkList p = L->next;
	while (p && j < i) {
		p = p->next;
		++j;
	}

	if (!p || j > i) {			/* j > i 适用于 i < 1 时,如 i = 0 */
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_PARA);
		return ERR_PARA;
	}

	*e = p->data;

	return RET_OK;
}

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

		p = p->next;
	}

	return 0;
}

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

		p = q;
	}

	return INFEASIABLE;
}

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

		p = p->next;
	}

	return INFEASIABLE;
}

/* 算法 2.9,在带头结点的单链线性表 L 中第 i 个位置之前插入元素 e */
Status ListInsert(LinkList L, int i, ElemType e)
{
	int j = 0;
	LinkList p = L;
	while (p && j < i - 1) {
		++j;
		p = p->next;
	}

	if (!p || j > i - 1) {				/* 超出表长或者 i < 1 */
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_PARA);
		return ERR_PARA;
	}

	LinkList newLNode = MakeNewLNode(e);
	if (!newLNode) {
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_MEMORY_ALLOCATE);
		return ERR_MEMORY_ALLOCATE;
	}

	newLNode->next = p->next;
	p->next = newLNode;

	return RET_OK;
}

/* 算法 2.10,在带头结点的单链线性表 L 中,删除第 i 个元素,并由 e 返回其值 */
Status ListDelete(LinkList L, int i, ElemType *e)
{
	int j = 0;
	LinkList p = L;
	while (p->next && j < i - 1) {
		++j;
		p = p->next;
	}

	if (!p->next || j > i - 1) {	/* 理论上 j 最多只能等于 i - 1, 但此处当参数不合法时可用, 建议单独判断参数合法性 */
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_PARA);
		return ERR_PARA;
	}

	LinkList q = p->next;
	p->next = q->next;
	*e = q->data;
	free(q);

	return RET_OK;
}

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

	return RET_OK;
}

4) algorithm.h

/* 算法定义头文件 */
#ifndef ALGORITHM_H
#define ALGORITHM_H

#include "singleLinkList.h"

/* 算法 2.11,逆位序(插在表头)输入 n 个元素的值,建立带表头结构的单链线性表 L */
void CreateList(LinkList *L, int n);

/* 正位序(插在表尾)输入 n 个元素的值,建立带表头结构的单链线性表 */
void CreateList2(LinkList *L, int n);

/* 算法 2.12,已知单链线性表 La 和 Lb 的元素按值非递减排列
   归并 La 和 Lb 得到新的单链线性表 Lc,Lc 的元素也按值非递减排列
   此处需要释放 Lb 头节点故需要传入 Lb 指针变量 */
void MergeList(LinkList La, LinkList *Lb, LinkList *Lc);

#endif // !ALGORITHM_H

5) algorithm.c

/* 算法实现源文件 */
#include "algorithm.h"
#include <stdlib.h>
#include <stdio.h>

/* 算法 2.11,逆位序(插在表头)输入 n 个元素的值,建立带表头结构的单链线性表 L */
void CreateList(LinkList *L, int n)
{
	(void)InitList(L);
	printf("Please input %d integers: ", n);
	int num;
	LinkList p;
	for (int i = 0; i < n; ++i) {
		scanf_s("%d", &num);
		p = MakeNewLNode(num);
		p->next = (*L)->next;
		(*L)->next = p;
	}
}

/* 正位序(插在表尾)输入 n 个元素的值,建立带表头结构的单链线性表 */
void CreateList2(LinkList *L, int n)
{
	(void)InitList(L);
	LinkList q = *L, p;
	int num;
	printf("Please input %d integers: ", n);
	for (int i = 0; i < n; ++i) {
		scanf_s("%d", &num);
		p = MakeNewLNode(num);
		q->next = p;
		q = p;
	}
}

/* 算法 2.12,已知单链线性表 La 和 Lb 的元素按值非递减排列
   归并 La 和 Lb 得到新的单链线性表 Lc,Lc 的元素也按值非递减排列 
   此处需要释放 Lb 头节点故需要传入 Lb 指针变量 */
void MergeList(LinkList La, LinkList *Lb, LinkList *Lc)
{
	LinkList pa = La->next, pb = (*Lb)->next, pc = NULL;
	*Lc = pc = La;
	while (pa && pb) {
		if (pa->data <= pb->data) {
			pc->next = pa;
			pc = pa;
			pa = pa->next;
		}
		else {
			pc->next = pb;
			pc = pb;
			pb = pb->next;
		}
	}

	pc->next = pa ? pa : pb;
	free(*Lb);
}

6) auxiliary.h

/* 辅助函数定义头文件 */

#ifndef AUXILIARY_H
#define AUXILIARY_H
#include "singleLinkList.h"

void Visit(ElemType e);

#endif // !AUXILIARY_H

7) auxiliary.c

/* 辅助函数实现源文件 */

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

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

8) main.c

/* 主函数入口源文件 */
#include "singleLinkList.h"
#include "algorithm.h"
#include "auxiliary.h"
#include <stdio.h>

int main(void)
{
	int n = 5;
	LinkList La;
	CreateList(&La, n);
	printf("La: ");
	ListTraverse(La, Visit);
	printf("\n");

	LinkList Lb;
	CreateList2(&Lb, n);
	printf("Lb: ");
	ListTraverse(Lb, Visit);
	putchar('\n');

	LinkList Lc;
	MergeList(La, &Lb, &Lc);
	printf("Lc: ");
	ListTraverse(Lc, Visit);
	putchar('\n');

	int ret = DestroyList(&Lc);
	if (ret != RET_OK) {
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ret);
		return ret;
	}

	/* free() 的作用:仅仅是释放堆内存,不将指针置空 */
	printf("After Destroy list Lc, the address of Lc is %p\n", Lc);

	return 0;
}

3. 运行示例

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

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

相关文章

武汉凯迪正大—接触电阻测试仪器

一、凯迪正大智能回路电阻测试仪产品概述 KDHL-100A操作面板采用人体工学设计&#xff0c;符合操作习惯&#xff0c;采用高频开关电源和数字电路技术&#xff0c;适用于开关控制设备回路电阻的测量。测试电流采用国家标准推荐的直流100A。可在直流100A的情况下直接测得回路电阻…

图像色彩空间的改变

图像色彩空间的改变 OpenCV中有150多种颜鱼空间转换方法。 最广泛使用的转换方法有两种&#xff0c; BGR →Gray 和 BGR→HSV。 cv.cvtColor(input_image&#xff0c;flag) 参数: input_image:进行颜色空间转换的图像. flag:转换类型 cv.COLOR_BGR2GRAY : BGR → GRAY cv.…

恒运资本:沪指震荡跌0.34%,医药、酿酒等板块走低,光刻胶概念等活跃

6日早盘&#xff0c;两市股指再度走低&#xff0c;创业板指跌近1%&#xff1b;成交额有所下降&#xff0c;北向资金小幅净流出。 到午间收盘&#xff0c;沪指跌0.34%报3143.62点&#xff0c;深成指跌0.68%&#xff0c;创业板指跌0.89%&#xff0c;上证50指数跌0.51%&#xff1…

运行Android Automotive模拟器

在windows系统中安装MobaXterm MobaXterm free Xserver and tabbed SSH client for Windows 运行MobaXterm&#xff0c;在宿主机中进入编译后的源码根目录并执行如下命令&#xff0c;若未编译&#xff0c;请参照如下链接&#xff0c;编译车机模拟器Android Automotive编译_IT…

Linux之DNS域名解析服务

目录 Linux之DNS域名解析服务 概述 产生原因 作用 连接方式 因特网的域名结构 拓扑 分类 域名服务器类型 ​编辑 DNS域名解析过程 分类 解析图 搭建DNS域名解析服务器 概述 安装软件 bind服务中三个关键文件 主配置文件分析 一般需要修改三部分&#xff1a;…

ubuntu 20.04 设置 authorized_keys 让 VS Code ssh 远程免密连接

相关文章 VSCode SSH 连接远程ubuntu Linux 主机 前言 前面记录了 VS Code 可以通过 SSH 远程连接 ubuntu Linux 主机&#xff0c;比如代码放在远程 ubuntu 主机上&#xff0c; windows 端 VS Code 通过 ssh 远程连接 ubuntu&#xff0c;并打开 远程主机上的 代码 如果不设置…

手游折扣平台app排行,打折手游平台排行

随着手游市场的不断发展&#xff0c;出现了越来越多的手游折扣平台。在这些平台中&#xff0c;有些提供各种各样的手机游戏&#xff0c;并提供丰厚的福利。本文将向您介绍手游折扣平台app排行&#xff0c;打折手游平台排行。对于目前的游戏来说&#xff0c;无非是哪里玩更划算&…

Eclipse安装及配置tomcat

1.Eclipse安装 1.java -version检查一下有没有jdk 如没有则下载 下载路径&#xff1a;https://www.oracle.com/java/technologies/javase-jdk8-downloads.html 2.Eclipse下载链接&#xff1a;https://www.eclipse.org/downloads/ 3.安装完之后就启动你会看见一个欢迎页面&am…

网络电视盒子哪个好?数码老贾横评整理电视盒子推荐

大家好&#xff0c;我是老贾&#xff0c;今天测评的主题是网络电视盒子哪个好&#xff0c;为让结果更加真实客观&#xff0c;我购入了市面上最热销的12款电视盒子&#xff0c;花费14天时间详细对比芯片、内存、用料、系统、广告等等方面&#xff0c;最终整理了五款表现最佳的电…

摘要-签名-PKI-访问控制-DOS-欺骗技术

摘要-签名-PKI-访问控制-DOS-欺骗技术 信息摘要数字签名 信息摘要 信息摘要通过哈希函数生成的 信息摘要保证数据的完整性 MD5 和 SHA-1 数字签名 唯一确定发送方 基于非对称加密技术&#xff08;公钥和私钥技术&#xff09;

Android Framework——进程间通讯学习,从Binder使用看起

前言 Binder 是安卓中非常重要的进程间通讯工具&#xff0c;通过Binder 安卓在ServiceManager中对外提供了一系列的服务。学习Binder&#xff0c;将很好地为我们学习framework开个好头。 Android 使用多进程 Android 开启进程方式很简单&#xff0c;在AndoridMenifest中给四…

ubuntu server 更改时区:上海

1. 打开终端&#xff0c;在命令行中以超级用户或具有sudo权限的用户身份运行以下命令&#xff1a; sudo dpkg-reconfigure tzdata 这会打开一个对话框&#xff0c;用于选择系统的时区设置。 2. 在对话框中&#xff0c;使用上下箭头键在地区列表中选择"Asia"&#x…

蓝桥杯打卡Day4

文章目录 首字母大写字符串转换整数 一、首字母大写IO链接 本题思路:本题就是语法题 #include <bits/stdc.h>int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);std::cout.tie(nullptr);std::string str;std::getline(std::cin,str);for(int i0;i&…

多态(个人学习笔记黑马学习)

多态分为两类 静态多态: 函数重载和 运算符重载属于静态多态&#xff0c;复用函数名动态多态: 派生类和虚图数实现运行时多态 静态多态和动态多态区别: 静态多态的函数地址早绑定 编译阶段确定函数地址动态多态的函数地址晚绑定 运行阶段确定函数地址 1、基本语法 #include &…

IMX6ULL移植篇-uboot源码主要文件说明

一. uboot 源码分析前提 由于 uboot 会使用到一些经过编译才会生成的文件&#xff0c;因此&#xff0c;我们在分析 uboot的时候&#xff0c;需要先编译一下 uboot 源码工程。 这里所用的开发板是 nand-flash 版本。 本文学习续上一篇文章&#xff0c;如下&#xff1a; IMX6U…

zabbix 自动发现

哈喽大家好&#xff0c;我是咸鱼 昨天老大让我初始化一批服务器&#xff0c;吭哧吭哧弄完之后需要把这批机器添加到 zabbix 上去 但是我发现一台一台添加效率好低&#xff0c;而且特别繁琐&#xff0c;当时我没有想出有什么好的方法&#xff0c;今天上网搜了一下相关资料之后…

Android Automotive概述

Android开发者的新赛道 在智能手机行业初兴起时&#xff0c;包括BAT在内许多传统互联网企业都曾布局手机产业&#xff0c;但是随着手机市场的基本定型&#xff0c;造车似乎又成了各大资本下一个追逐的方向。百度、小米先后宣布造车&#xff0c;阿里巴巴则与上汽集团共同投资创…

Camunda 7.x 系列【48】候选用户和用户组

有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 2.7.9 本系列Camunda 版本 7.19.0 源码地址:https://gitee.com/pearl-organization/camunda-study-demo 文章目录 1. 概述2. 案例演示1. 概述 在之前的文档中,用户任务都是基于的Assignee设置固定的执行人…

车联网仿真工具Veins学习1

准备条件 假如你是一个小白&#xff0c;先找到相关的参考资料&#xff08;已根据上一篇博客安装好Veins&#xff09;&#xff0c;主要是官方文档和相关的博客&#xff0c;官方提供了一个example&#xff0c;我找到的资料如下&#xff1a; Frequently Asked Questions (FAQ) O…

C++ - 多态的实现原理

前言 本博客主要介绍C 当中 多态语法的实现原理&#xff0c;如果有对 多态语法 有疑问的&#xff0c;请看下面这篇博客&#xff1a; 探究&#xff0c;为什么多态的条件是那样的&#xff08;虚函数表&#xff09; 首先&#xff0c;调用虚函数必须是 父类的 指针或 引用&#xf…