数据结构栈和堆列

news2024/12/24 9:42:29

目录

栈:

栈的概念:

栈的实现:

栈接口的实现:

1.初始化栈:

2.入栈:

3.出栈:

4. 获取栈顶元素:

5.获取栈中有效数据的个数:

 6.检测栈是否为空,如果为空返回非零结果,如果不为空返回0:

 7.销毁栈:

队列:

队列的概念:

队列的实现:

接口的实现:

1.初始化队列:

2. 队尾入队列:

3.队头出队列:

4.获取队列头部元素:

 5.获取队列尾元素:

6.获取队列中有效数据个数:

7.检测队列是否为空,如果为空返回非零结果,如果非空返回0:

8.销毁队列:


栈:

栈的概念:

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵循先进先出LIFO(Last In First Out)的原则

  • 压栈:栈的插入操作叫做进栈/入栈,入数据在栈顶
  • 出栈:栈的删除操作叫做出栈。出数据也在栈顶

栈的实现:

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。

C语言单链表-CSDN博客  C语言实现顺序表(增,删,改,查)-CSDN博客 0基础小白学C语言看这一篇就够了(C语言详讲万字!!!)_用c++设计一个程序,实现输入任意一个数(不大于10的5次方),计算从1加到这个数-CSDN博客

栈接口的实现:

栈和顺序表一样,可以做成动态的也可以做成静态的,因为静态的一般是用在那种给定长度的地方,所以这里使用动态的实现栈。

实现之前我们需要各个文件,分别是头文件"Stack.h",以及两个源文件"Stack.c"和"Test.c",他们的作用如下:

  • Stack.h:栈的结构体,头文件引用,接口函数的声明。
  • Stack.c:接口函数的实现。
  • Test.c:测试各个函数的功能。

如下我们先来展示各种接口的声明Stack.h:

#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int STDataType;
typedef struct Stack {
	STDataType*a;
	int top;
	int capacity;
}ST;

void STInit(ST* ps);
void STDestroy(ST* ps);
void STPush(ST*ps,STDataType x);
void STPop(ST* ps);
STDataType STTop(ST* ps);

int STSize(ST* ps);
bool STEmpty(ST* ps);

1.初始化栈:

把传递进来的第一个栈的置空和值为0

void STInit(ST* ps) {
	assert(ps);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}
2.入栈:

入栈之前判断栈的大小是否足够,如果足够那么直接将数据存入对应的位置然后有效值++就行,如果空间不够那么需要扩容,如果扩容失败直接报错误信息。

void STPush(ST* ps, STDataType x) {
	assert(ps);
	if (ps->top==ps->capacity) {
		int newCapacity = ps->capacity * 2 == 0 ? 4 : ps->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newCapacity);
		if (tmp==NULL) {
			perror("realloc fail");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = newCapacity;
	}
	ps->a[ps->top] = x;
	ps -> top++;
}
3.出栈:

首先断言以下以免出现栈都没有还在出栈,然后有效数据减减就行了。

void STPop(ST* ps) {
	assert(ps);
	assert(ps->top > 0);
	--ps->top;
}
4. 获取栈顶元素:

直接返回数据没啥好说的。

STDataType STTop(ST* ps) {
	assert(ps);
	assert(ps->top > 0);
	return  ps->a[ps->top - 1];
}
5.获取栈中有效数据的个数:

直接返回栈顶元素。

int STSize(ST* ps) {
	assert(ps);
	return ps->top;
}
 6.检测栈是否为空,如果为空返回非零结果,如果不为空返回0:

返回类型是一个布尔型也就是不是false就是true。

bool STEmpty(ST* ps) {
	assert(ps);
	return ps->top == 0;
}
 7.销毁栈:

把栈释放之后然后把指针置空,值值为0.

void STDestroy(ST* ps) {
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->top = ps->capacity=0;
}

如下是全代码的示例Stack.c:

#include"Stack.h"

void STInit(ST* ps) {
	assert(ps);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}
void STDestroy(ST* ps) {
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->top = ps->capacity=0;
}

void STPush(ST* ps, STDataType x) {
	assert(ps);
	if (ps->top==ps->capacity) {
		int newCapacity = ps->capacity * 2 == 0 ? 4 : ps->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newCapacity);
		if (tmp==NULL) {
			perror("realloc fail");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = newCapacity;
	}
	ps->a[ps->top] = x;
	ps -> top++;
}

void STPop(ST* ps) {
	assert(ps);
	assert(ps->top > 0);
	--ps->top;
}
STDataType STTop(ST* ps) {
	assert(ps);
	assert(ps->top > 0);
	return  ps->a[ps->top - 1];
}
int STSize(ST* ps) {
	assert(ps);
	return ps->top;
}
bool STEmpty(ST* ps) {
	assert(ps);
	return ps->top == 0;
}

如下我们用Test.c文件测试整个代码运行是否正常:

#include"Stack.h"

void TestStack1() {
	ST st;
	STInit(&st);
	STPush(&st, 1);
	STPush(&st, 2);
	STPush(&st, 3);
	STPush(&st, 4);
	STPush(&st, 5);

	while (!STEmpty(&st)) {
		printf("%d ",STTop(&st));
		STPop(&st);
	}
	printf("\n"); 

	STDestroy(&st);
}
int main() {
	TestStack1();
	return 0;
}

队列:

队列的概念:

队列:只允许一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)入队列:进入插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头

队列的实现:

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。

接口的实现:

我们首先创建一个头文件"Queue.h"和两个源文件分别是"Queue.c"跟"Test.c",他们的作用为:

  • Queue.h:头文件的引用接口函数的声明,以及栈的结构体。
  • Queue.c:接口的实现。
  • Test.c:测试每个接口。

如下代码是Queue.h中所有接口以及头文件引用的代码:

#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int QDataType;
typedef struct QueueNode {
	struct QueueNode* next;
	QDataType data;
}QNode;

typedef struct Queue {
	QNode* head;
	QNode* tail;
	int size;
}Que;


void QueueInit(Que* pq);
void QueueDestroy(Que* pq);
void QueuePush(Que*pq,QDataType x);
void QueuePop(Que* pq);
QDataType QueueFront(Que* pq);
QDataType QueueBack(Que* pq);
bool QueueEmpty(Que* pq);
int QueueSize(Que* p);


1.初始化队列:

把拿到的头指针和尾指针置空,然后把其值置为0...

void QueueInit(Que* pq) {
	assert(pq);
	pq->head = pq->tail = NULL;
	pq->size = 0;
}
2. 队尾入队列:

先使用malloc创建出一个队列,然后判断创建是否成功,如若成功执行下列代码,首先把指针置空然后给数据赋值,最后判断一下是第几个元素如果是第一个那么直接让头指针和尾指针都指向它即可,如果不是那么需要改变尾指针的指向,然后有效数据加加。

void QueuePush(Que* pq, QDataType x) {
	assert(pq);
	QNode* newnode = malloc(sizeof(QNode));
	if (newnode == NULL) {
		perror("malloc fail");
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;
	if (pq->tail==NULL) {
		pq->head = pq->tail = newnode;
	}
	else {
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
	pq->size++;
}
3.队头出队列:

出数据大致原理就是保存第一个然后让头指针指向下一个然后再把之前那个释放了,最后有效数据个数减减即可。

void QueuePop(Que* pq) {

	assert(pq);
	assert(!QueueEmpty(pq));

	if (pq->head->next == NULL) {
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else {
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
	pq->size--;
}
4.获取队列头部元素:

队头有一个指针head直接拿取即可。

QDataType QueueFront(Que* pq) {
	assert(pq);
	assert(!QueueEmpty(pq));

	return pq->head->data;
}
 5.获取队列尾元素:

队尾有一个指针也就是tail直接拿取即可。

QDataType QueueBack(Que* pq) {
	assert(pq);
	assert(!QueueEmpty(pq));

	return pq->tail->data;
}
6.获取队列中有效数据个数:

直接拿取有效数据size即可。

int QueueSize(Que* pq) {
	assert(pq);
	return pq->size;
}
7.检测队列是否为空,如果为空返回非零结果,如果非空返回0:

首先断言,返回时是一个表达式用来判断是否是真还是假。

bool QueueEmpty(Que* pq) {
	assert(pq);
	return pq->head == NULL;
}
8.销毁队列:

使用循环从队列的头部一直释放即可,最后把传进来的pq指针置空。

void QueueDestroy(Que* pq) {
	assert(pq);
	QNode* cur = pq->head;
	while (cur) {
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
	pq->size = 0;
}

下列是队列接口实现的全部代码Queue.c中的:

#include"Queue.h"

void QueueInit(Que* pq) {
	assert(pq);
	pq->head = pq->tail = NULL;
	pq->size = 0;
}



void QueueDestroy(Que* pq) {
	assert(pq);
	QNode* cur = pq->head;
	while (cur) {
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
	pq->size = 0;
}

void QueuePush(Que* pq, QDataType x) {
	assert(pq);
	QNode* newnode = malloc(sizeof(QNode));
	if (newnode == NULL) {
		perror("malloc fail");
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;
	if (pq->tail==NULL) {
		pq->head = pq->tail = newnode;
	}
	else {
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
	pq->size++;
}

void QueuePop(Que* pq) {

	assert(pq);
	assert(!QueueEmpty(pq));

	if (pq->head->next == NULL) {
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else {
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
	pq->size--;
}
QDataType QueueFront(Que* pq) {
	assert(pq);
	assert(!QueueEmpty(pq));

	return pq->head->data;
}


QDataType QueueBack(Que* pq) {
	assert(pq);
	assert(!QueueEmpty(pq));

	return pq->tail->data;
}

bool QueueEmpty(Que* pq) {
	assert(pq);
	return pq->head == NULL;
}
int QueueSize(Que* pq) {
	assert(pq);
	return pq->size;
}

然后test.c测试代码是否能够正常运行:

#include"Queue.h"

void TestQueue() {
	Que q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePush(&q, 4);

	while (!QueueEmpty(&q)) {
		printf("%d ", QueueFront(&q));
		QueuePop(&q);
	}
	printf("\n");

	QueueDestroy(&q);
}

int main() {
	TestQueue();
}


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

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

相关文章

rocketmq管理工具rocketmq-console安装

rocketmq-console是一个图形化管理控制台&#xff0c;提供Broker集群状态查看&#xff0c;Topic管理&#xff0c;Producer、Consumer状态展示&#xff0c;消息查询等常用功能&#xff0c;这个功能在安装好RocketMQ后需要额外单独安装、运行。 中文文档地址&#xff1a;https:/…

基于模糊PID控制器的的无刷直流电机速度控制simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1无刷直流电机模型与速度控制 4.2 模糊PID控制器设计 5.完整工程文件 1.课题概述 基于模糊PID控制器的的无刷直流电机速度控制simulink建模与仿真。基于模糊PID控制器的无刷直流电机&#xff08;Brus…

量化交易入门(四十)什么是ASI指标,怎么用它炒股

一、什么是ASI指标 ASI指标全称为Accumulation Swing Index,即积累摆动指数。它是一种用于衡量市场供需关系强度的技术指标,由Welles Wilder开发。ASI指标结合了价格和成交量的变化,试图从动量的角度来衡量多空双方的力量对比。其计算公式如下: 计算价格的变化值:ΔP 今日收盘…

【Python系列】数据遍历

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

dddddd

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和…

使用Java流API构建树形结构数据

简介&#xff1a; 在实际开发中&#xff0c;构建树状层次结构是常见需求&#xff0c;如组织架构、目录结构或菜单系统。本教案通过解析给定的Java代码&#xff0c;展示如何使用Java 8 Stream API将扁平化的菜单数据转换为具有层级关系的树形结构。 1. 核心类定义 - Menu Data…

时间管理系统的设计与实现|Springboot+ Mysql+Java+ B/S结构(可运行源码+数据库+设计文档)大学生

本项目包含可运行源码数据库LW&#xff0c;文末可获取本项目的所有资料。 推荐阅读300套最新项目持续更新中..... 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 2024年56套包含ja…

JAVAEE—Callable接口,ReentrantLock,synchronized的工作过程

文章目录 Callable接口的用法Callable与FutureTask类 加锁的工作过程什么是偏向锁呢&#xff1f;举个例子 轻量级锁重量级锁 ReentrantLockReentrantLock 的用法: Callable接口的用法 Callable 是一个 interface . 相当于把线程封装了一个 “返回值”. 方便程序猿借助多线程的…

YoloV8改进策略:Neck改进|GCNet(独家原创)|附结构图

摘要 本文使用GCNet注意力改进YoloV8,在YoloV8的Neck中加入GCNet实现涨点。改进方法简单易用&#xff0c;欢迎大家使用&#xff01; 论文:《GCNet: Non-local Networks Meet Squeeze-Excitation Networks and Beyond》 非局部网络&#xff08;NLNet&#xff09;通过为每个查…

【教程】Kotlin语言学习笔记(六)——泛型

写在前面&#xff1a; 如果文章对你有帮助&#xff0c;记得点赞关注加收藏一波&#xff0c;利于以后需要的时候复习&#xff0c;多谢支持&#xff01; 【Kotlin语言学习】系列文章 第一章 《认识Kotlin》 第二章 《数据类型》 第三章 《数据容器》 第四章 《方法》 第五章 《L…

如何远程电脑连接?

远程电脑连接是指通过网络将计算机与远程设备连接起来&#xff0c;实现远程管理和操作的技术。在现代信息化社会中&#xff0c;远程电脑连接成为了人们工作和生活中的重要方面。远程电脑连接可以极大地提高工作效率和便利性&#xff0c;让我们能够在不同地点的计算机之间进行协…

【Servlet】服务器内部转发以及客户端重定向

文章目录 一、服务器内部转发&#xff1a;request.getRequestDispatcher("...").forward(request, response);二、客户端重定向&#xff1a;response.sendRedirect("");三、服务器内部转发代码示例四、客户端重定向代码示例 一、服务器内部转发&#xff1a…

【Vue】vue3简介与环境配置

文章目录 项目编码规范什么是 Vue&#xff1f;安装node环境nvm针对node版本惊醒管理的工具 项目编码规范 组合式API Typescript setup(语法糖) 什么是 Vue&#xff1f; Vue 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建&#xff0c;…

史上最强 PyTorch 2.2 GPU 版最新安装教程

一 深度学习主机 1.1 配置 先附上电脑配置图&#xff0c;如下&#xff1a; 利用公司的办公电脑对配置进行升级改造完成。除了显卡和电源&#xff0c;其他硬件都是公司电脑原装。 1.2 显卡 有钱直接上 RTX4090&#xff0c;也不能复用公司的电脑&#xff0c;其他配置跟不上。…

路由和远程访问是什么?

路由和远程访问在现代互联网时代中&#xff0c;扮演着至关重要的角色。它们为我们提供了便捷的信息传递途径&#xff0c;让不同地区的电脑、设备以及人们之间能够轻松进行通信和交流。 对于路由来说&#xff0c;它是连接互联网上的各个网络的核心设备。一台路由器可以将来自不同…

Linux——线程控制

目录 前言 一、线程创建 1.创建线程 2.线程传递结构体 3.创建多线程 4.收到信号的线程 二、线程终止 三、线程等待 四、线程分离 五、取消线程 六、线程库管理的原理 七、站在语言角度理解pthread库 八、线程的局部存储 前言 前面我们学习了线程概念和线程创建&…

揭开HTTP状态码的神秘面纱:基本概念全解析

在客户端与服务器之间的信息传输过程中&#xff0c;我们可以将其比喻为客户与快递员之间的包裹传递。那么服务器是如何通知客户端&#xff0c;操作是成功还是失败&#xff1f;或者有其他的一些情况呢&#xff1f;&#xff08;就像客户可以查询快递的状态&#xff09; 而这背后…

搜维尔科技:SenseGlove Nova 允许以最简单的方式操作机器人并与物体交互

扩展 Robotics 和 QuarkXR 人机界面 XR 应用 Extend Robotics 利用扩展现实技术&#xff0c;让没有机器人专业知识的个人能够远程控制机器人。他们的 AMAS 解决方案使操作员能够不受地理限制地轻松控制机器人。 需要解决的挑战【搜维尔科技】 目前&#xff0c;操作机器人是一…

10秒钟用python接入讯飞星火API(保姆级)

正文&#xff1a; 科大讯飞是中国领先的人工智能公众公司&#xff0c;其讯飞星火API为开发者提供了丰富的接口和服务&#xff0c;以支持各种语音和语言技术的应用。 步骤一&#xff1a;注册账号并创建应用 首先&#xff0c;您需要访问科大讯飞开放平台官网&#xff0c;注册一个…

最优算法100例之21-数组的逆序对

专栏主页:计算机专业基础知识总结(适用于期末复习考研刷题求职面试)系列文章https://blog.csdn.net/seeker1994/category_12585732.html 题目描述 逆序数: 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一…