第 2 章 线性表 ( 双链循环线性表(链式存储结构)实现)

news2024/10/9 8:31:21

1. 背景说明

 

 

2. 示例代码

1) status.h

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

#ifndef STATUS_H
#define STATUS_H

#define CHECK_NULL(pointer) if (!(pointer)) { \
	printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_NULL_PTR); \
	return NULL; \
}

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

#define CHECK_VALUE(value, ERR_CODE) if (value) { \
	printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_CODE); \
	return ERR_CODE; \
}

#define CHECK_FALSE(value, ERR_CODE) if (!(value)) { \
	printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_CODE); \
	return FALSE; \
} 

/* 函数结果状态码 */
#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) cycleDoubleLinkList.h

/* 双链循环线性表(链式存储结构)头文件实现 */

#ifndef CYCLEDOUBLELINKLIST_H
#define CYCLEDOUBLELINKLIST_H

#include "status.h"

typedef int ElemType;

typedef struct DuLNode {
	ElemType data;
	struct DuLNode *prior, *next;
} DuLNode, *DuLinkList;

/* 产生空的双向循环链表 L */
Status InitList(DuLinkList *L);

/* 操作结果:销毁双向循环链表 L */
Status DestroyList(DuLinkList *L);

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

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

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

/* 当第 i 个元素存在时,其值赋给 e 并返回 OK,否则返回 ERROR */
Status GetElem(DuLinkList L, int i, ElemType *e);

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

/* 操作结果:若 curr_e 是 L 的数据元素,且不是第一个,则用 pre_e 返回它的前驱
   否则操作失败,pre_e 无定义 */
Status PriorElem(DuLinkList L, ElemType curr_e, ElemType *pre_e);

/* 操作结果:若 curr_e 是 L 的数据元素,且不是最后一个,则用 next_e 返回它的后继
   否则操作失败,next_e 无定义 */
Status NextElem(DuLinkList L, ElemType curr_e, ElemType *next_e);

/* 在双向链表 L 中返回第 i 个元素的位置指针 */
DuLinkList GetElemP(DuLinkList L, int i);

/* 算法 2.18,在带头结点的双链循环线性表 L 中第 i 个位置之前插入元素 e,i 的合法值为 1≤ i ≤ 表长 + 1 */
Status ListInsert(DuLinkList L, int i, ElemType e);

/* 算法 2.19,删除带头结点的双链循环线性表 L 的第 i 个元素,i 的合法值为 1 ≤ i ≤ 表长 */
Status ListDelete(DuLinkList L, int i, ElemType *e);

/* 由双链循环线性表 L 的头结点出发,正序对每个数据元素调用函数 visit() */
void ListTraverse(DuLinkList L, void(*visit)(ElemType));

/* 由双链循环线性表 L 的头结点出发,逆序对每个数据元素调用函数 visit() */
void ListTraverseBack(DuLinkList L, void(*visit)(ElemType));

#endif // !CYCLEDOUBLELINKLIST_H

3) cycleDoubleLinkList.c

/* 双链循环线性表(链式存储结构)源文件实现 */

#include "cycleDoubleLinkList.h"
#include <stdlib.h>
#include <stdio.h>

static DuLinkList MakeNewDuLNode(ElemType e)
{
	DuLinkList newDuLNode = (DuLinkList)malloc(sizeof(DuLNode));
	CHECK_NULL(newDuLNode)
	newDuLNode->data = e;
	newDuLNode->prior = NULL;
	newDuLNode->next = NULL;

	return newDuLNode;
}

/* 产生空的双向循环链表 L */
Status InitList(DuLinkList *L)
{
	*L = (DuLinkList)malloc(sizeof(DuLNode));
	CHECK_VALUE(!(*L), ERR_MEMORY_ALLOCATE)
	(*L)->next = (*L)->prior = *L;

	return RET_OK;
}

/* 操作结果:销毁双向循环链表 L */
Status DestroyList(DuLinkList *L)
{
	DuLinkList p = (*L)->next;
	DuLinkList q;
	while (p != *L) {
		q = p->next;
		free(p);
		p = q;
	}

	free(*L);
	*L = NULL;

	return RET_OK;
}

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

	L->next = L->prior = L;

	return RET_OK;
}

/* 初始条件:线性表 L 已存在
   操作结果:若 L 为空表,则返回 TRUE,否则返回 FALSE */
Bollean ListEmpty(DuLinkList L)
{
	return ((L->next == L) && (L->prior == L)) ? TRUE : FALSE;
}

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

	return length;
}

/* 当第 i 个元素存在时,其值赋给 e 并返回 OK,否则返回 ERROR */
Status GetElem(DuLinkList L, int i, ElemType *e)
{
	DuLinkList p = L->next;
	int count = 0;
	while ((p != L) && (count < i - 1)) {
		++count;
		p = p->next;
	}

	CHECK_VALUE((p == L) || count > i - 1, ERR_PARA)
	*e = p->data;

	return RET_OK;
}

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

		p = p->next;
	}

	return 0;
}

/* 操作结果:若 curr_e 是 L 的数据元素,且不是第一个,则用 pre_e 返回它的前驱
   否则操作失败,pre_e 无定义 */
Status PriorElem(DuLinkList L, ElemType curr_e, ElemType *pre_e)
{
	DuLinkList p = L->next->next;
	while (p != L) {
		if (p->data == curr_e) {
			*pre_e = p->prior->data;
			return TRUE;
		}

		p = p->next;
	}

	return FALSE;
}

/* 操作结果:若 curr_e 是 L 的数据元素,且不是最后一个,则用 next_e 返回它的后继
   否则操作失败,next_e 无定义 */
Status NextElem(DuLinkList L, ElemType curr_e, ElemType *next_e)
{
	DuLinkList p = L->next->next;
	while (p != L) {
		if (p->prior->data == curr_e) {
			*next_e = p->data;
			return TRUE;
		}

		p = p->next;
	}

	return FALSE;
}

/* 在双向链表 L 中返回第 i 个元素的位置指针 */
DuLinkList GetElemP(DuLinkList L, int i)
{
	DuLinkList p = L;
	for (int j = 0; j < i; ++j) {
		p = p->next;
	}

	return p;
}

/* 在带头结点的双链循环线性表 L 中第 i 个位置之前插入元素 e,i 的合法值为 1≤ i ≤ 表长 + 1 */
Status ListInsert(DuLinkList L, int i, ElemType e)
{
	CHECK_VALUE((i < 1 || i > ListLength(L) + 1), ERR_PARA)
	DuLinkList p = GetElemP(L, i - 1);
	CHECK_VALUE(!p, ERR_NOT_FOUND)
	DuLinkList newDuLNode = MakeNewDuLNode(e);
	CHECK_VALUE(!newDuLNode, ERR_MEMORY_ALLOCATE)
	newDuLNode->prior = p;
	newDuLNode->next = p->next;
	p->next->prior = newDuLNode;
	p->next = newDuLNode;

	return RET_OK;
}

/* 删除带头结点的双链循环线性表 L 的第 i 个元素,i 的合法值为 1 ≤ i ≤ 表长 */
Status ListDelete(DuLinkList L, int i, ElemType *e)
{
	CHECK_VALUE((i < 1 || i > ListLength(L)), ERR_PARA)
	DuLinkList p = GetElemP(L, i);
	CHECK_VALUE(!p, ERR_NOT_FOUND)
	*e = p->data;
	p->prior->next = p->next;
	p->next->prior = p->prior;
	free(p);

	return RET_OK;
}

/* 由双链循环线性表 L 的头结点出发,正序对每个数据元素调用函数 visit() */
void ListTraverse(DuLinkList L, void(*visit)(ElemType))
{
	DuLinkList p = L->next;
	while (p != L) {
		visit(p->data);
		p = p->next;
	}
}

/* 由双链循环线性表 L 的头结点出发,逆序对每个数据元素调用函数 visit() */
void ListTraverseBack(DuLinkList L, void(*visit)(ElemType))
{
	DuLinkList p = L->prior;
	while (p != L) {
		visit(p->data);
		p = p->prior;
	}
}

4) main.c

/* 入口程序源文件 */

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

Status Compare(ElemType e1, ElemType e2);

void Visit(ElemType e);

int main(void)
{
	DuLinkList L;
	InitList(&L);
	for (int i = 0; i < 5; ++i) {
		ListInsert(L, i + 1, i + 1);
	}

	printf("Output Link List for sequence: ");
	ListTraverse(L, Visit);
	putchar('\n');
	printf("Output Link List for adverse: ");
	ListTraverseBack(L, Visit);
	putchar('\n');
	ElemType e;
	ListDelete(L, 2, &e);
	printf("After delete %d, Link List is: ", e);
	ListTraverse(L, Visit);
	putchar('\n');
	printf("The num of L is %d\n", ListLength(L));
	printf("List is %s\n", (ListEmpty(L) == TRUE) ? "empty" : "not empty");
	ClearList(L);
	printf("After clear L, List is %s\n", (ListEmpty(L) == TRUE) ? "empty" : "not empty");
	for (int i = 0; i < 5; ++i) {
		ListInsert(L, i + 1, i + 1);
	}

	ListTraverse(L, Visit);
	putchar('\n');
	Status ret = GetElem(L, 3, &e);
	if (ret == RET_OK) {
		printf("The %dth element of L is %d\n", 3, e);
	} else {
		printf("%dth element is not exist.\n", 3);
	}

	ret = LocateElem(L, 4, Compare);
	if (ret) {
		printf("The element of %d is %dth\n", 4, ret);
	} else {
		printf("Element %d is not exist in L\n", 4);
	}

	ret = PriorElem(L, 4, &e);
	if (ret == TRUE) {
		printf("The prior element of %d is %d\n", 4, e);
	} else {
		printf("Element %d do not have prior element\n", 4);
	}

	ret = NextElem(L, 4, &e);
	if (ret == TRUE) {
		printf("The next element of %d is %d\n", 4, e);
	} else {
		printf("Element %d do not have next element\n", 4);
	}

	DestroyList(&L);

	return 0;
}

Status Compare(ElemType e1, ElemType e2)
{
	return (e1 == e2) ? TRUE : FALSE;
}

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

3. 输出示例

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

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

相关文章

2023 年最新Java 毕业设计选题题目参考,500道 Java 毕业设计题目,值得收藏

大家好&#xff0c;我是程序员徐师兄&#xff0c;最近有很多同学咨询&#xff0c;说毕业设计了&#xff0c;不知道选怎么题目好&#xff0c;有哪些是想需要注意的。 确实毕设选题实际上对很多同学来说一个大坑&#xff0c; 每年挖坑给自己跳的人太多太多&#xff0c;选题选得好…

JavaScript关于对象的小挑战

让我们再来看看马克和约翰比较他们的体重指数的情况吧! 这一次&#xff0c;让我们用物体来实现计算! 记住&#xff1a;BMI质量/身高**2质量/&#xff08;身高*高度&#xff09;。(质量以公斤为单位&#xff0c;身高以米为单位) 为他们每个人创建一个对象&#xff0c;其属性为全…

MySQL触发器使用指南大全

一、介绍 触发器是与表有关的数据库对象&#xff0c;指在insert/update/delete之前或之后&#xff0c;触发并执行触发器中定义的SQL语句集合。触发器的这种特性可以协助应用在数据库端确保数据的完整性&#xff0c;日志记录&#xff0c;数据校验等操作。 使用别名OLD和NEW来引…

【操作系统实验】进程管理与内存分配模拟程序-含可运行有界面的Python代码

本文是博主之前做的操作系统实验&#xff0c;现在将完整代码和效果图免费放在下面&#xff0c;供大家参考&#xff0c;如果觉得有用&#xff0c;希望大家可以三连关注支持&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 实验目的 设计编写OS进程…

15. 线性代数 - 克拉默法则

文章目录 克拉默法则矩阵运算Hi,大家好。我是茶桁。 上节课我们在最后提到了一个概念「克拉默法则」,本节课,我们就来看看到底什么是克拉默法则。 克拉默法则 之前的课程我们一直在强调,矩阵是线性方程组抽象的来的。那么既然我们抽象出来了,有没有一种比较好的办法高效…

合宙Air724UG LuatOS-Air LVGL API控件-二维码(Qrcode)

二维码&#xff08;Qrcode&#xff09; 示例代码 qrcodelvgl.qrcode_create(lvgl.scr_act(),nil)lvgl.qrcode_set_txt(qrcode,"https://doc.openluat.com/home")lvgl.obj_set_size(qrcode,400,400)lvgl.obj_align(qrcode, nil, lvgl.ALIGN_CENTER, 0, 0)创建 可以通…

496. 下一个更大元素 I

class Solution { public:vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {// 存储numx2右侧第一个比它的元素数值std::unordered_map<int, int> index;std::stack<int> sta;for (int i nums2.size()-1; i &…

uniapp项目实践总结(十四)封装存储和路由方法

导语&#xff1a;在日常 APP 开发过程中&#xff0c;经常要用到数据的存储、获取和删除等操作以及页面导航之间的跳转&#xff0c;为此&#xff0c;封装了一个两个简单的方法来统一调用。 目录 原理分析方法实现实战演练案例展示 原理分析 主要是以下 API。 uni.setStorage…

xcode iOS 在app文件中开启访问 Document Directory

xcode iOS 在app文件中开启访问 Document Directory 在 Plist 中设置 LSSupportsOpeningDocumentsInPlace为 YES 且UIFileSharingEnabled为 YES &#xff08;这个不添加好像也可以&#xff09; 可以从系统的Files应用中访问应用的 Documents 目录 电脑 助手也可以访问 开…

视频号挂公众号链接最新教程方法,赶紧来看

玩视频号的朋友&#xff0c;尤其是靠挂公众号引流的朋友&#xff0c;肯定心里非常清楚&#xff0c;就在八月初&#xff0c;视频号放大招了&#xff0c;可以说这个大招是完全把公众号的路给堵死了&#xff0c;视频号出了什么新规呢&#xff0c;大家来看看。 第一个规则是&#…

无涯教程-JavaScript - IMTAN函数

描述 IMTAN函数以x yi或x yj文本格式返回复数的切线。复数的切线由以下公式计算- tan(z)正弦(z)/cos(z) 语法 IMTAN (inumber)争论 Argument描述Required/OptionalInumberA complex number for which you want the tangent.Required Notes Excel中的复数仅存储为文本。…

最新keil安装出现的无数问题记录及解决办法

报错问题现象如下&#xff1a; *** Target Target 1 uses ARM-Compiler Default Compiler Version 5 which is not available. 安装最新keil 5 出现无数个问题。 我使用GD32去跑&#xff0c;或者STM32去跑&#xff0c;都是这个问题。 一、我先解决了GD32的问题&#xff1a;…

阻塞队列学习总结

ArrayBlockingQueue&#xff1a;一个由数组结构组成的有界阻塞队列。 LinkedBlockingQueue&#xff1a;一个由链表结构组成的有界阻塞队列。 PriorityBlockingQueue&#xff1a;一个支持优先级排序的无界阻塞队列。 DelayQueue&#xff1a;一个使用优先级队列实现的延迟无界…

分库分表实战

数据分片与分片算法 分库分表的第一性原理&#xff0c;那就是&#xff1a;存储容量和性能容量。只有对核心业务表才会精心进行分库分表的设计。 首先我们了解一下数据分片是什么意思&#xff1f; 本质上的分库分表不就是数据分片吗&#xff1f;定义就是&#xff1a;按照某个…

BBR 带宽估计的延后累加

一个关于时延统计分布的小测试&#xff0c;用 netem delay jitter distribution pareto 模拟&#xff0c;得到下面的结果&#xff1a; netem 的 jitter 并不是真 jitter&#xff0c;只是通过延时阻滞部分报文模拟 jitter&#xff0c;对保序流而言&#xff0c;就表现为乱序&am…

搭建自己的OCR服务,第一步:选择合适的开源OCR项目

一、OCR是什么&#xff1f; 光学字符识别&#xff08;Optical Character Recognition, OCR&#xff09;是指对文本资料的图像文件进行分析识别处理&#xff0c;获取文字及版面信息的过程。 亦即将图像中的文字进行识别&#xff0c;并以文本的形式返回。 二、OCR的基本流程 1…

Science子刊 | 将CAR-T细胞疗法与造血干细胞移植相结合 或许 能治疗所有血液癌症...

来源&#xff1a;BRUNO DELESSARD/CHALLENGES-REA/REDUX 新的CAR-T细胞疗法有望能治疗几乎所有血液癌症。目前&#xff0c;该疗法已被批准用于五种亚型的血液癌症。宾夕法尼亚大学帕尔曼医学院的科学家们在预临床试验中展示了这种方法的潜在效能。 2023年8月31日&#xff0c;发…

动态路由的主流算法

路由器就是一台网络设备&#xff0c;它有多张网卡。当一个入口的网络包送到路由器时&#xff0c;它会根据一个本地的转发信息库&#xff0c;来决定如何正确地转发流量。这个转发信息库通常被称为路由表。 一张路由表中会有多条路由规则。每一条规则至少包含这三项信息。 目的…

vscode 调试 ROS2

1、在下列目录同层级找到.vscode文件夹 . ├── build ├── install ├── log └── src 2、 安装ros插件 3、创建tasks.json文件&#xff0c;添加下列内容 //代替命令行进行编译 {"version": "2.0.0","tasks": [{"label": &…

一窥未来:PyQt5引领下一代Python GUI开发

PyQt5 是一个用于创建图形用户界面&#xff08;GUI&#xff09;的强大工具包&#xff0c;它基于 Qt 库&#xff0c;为 Python 提供了丰富的 GUI 开发能力。无论是初学者还是有经验的开发者&#xff0c;都可以通过本文深入了解如何使用 PyQt5 来构建各种各样的界面应用程序。本文…