栈和队列详解(1)

目录

一、什么是栈?

二、创建一个我们自己的栈

1.前置准备

1.1需要的三个文件

 1.2结构体的创建和头文件的引用

 2.接口的实现

2.1初始化栈结构体

2.2尾插(压栈)

2.3栈存放的元素个数和判断栈是否为空

2.4获取栈顶元素

2.5出栈

2.6摧毁栈

2.7测试接口

三、所有代码

1.接口实现

2.栈的头文件

3.测试代码


一、什么是栈?

栈是计算机科学中的一种数据结构,它是一种线性结构,按照先进后出的原则进行存储和访问。栈通常也称作堆栈、堆叠或简称电梯。

在栈中,添加或删除元素只能在同一端进行,这一端被称为栈顶。当向栈顶添加一个元素时,我们称之为入栈;当从栈顶删除一个元素时,我们称之为出栈。对于栈的一项重要特性是,每次只能访问位于栈顶的元素,因此栈是不支持随机访问的数据结构。栈和我们之前所学习过的顺序表很相似,区别就在于,顺序表支持尾插尾删,头插头删,而栈只支持后进先出也就是只支持尾插尾删。它就像一个竖井,当队伍走进这个井后,要退出来也只能是队伍的末端最先退出。这里博主给大家画了张图,方便大家好理解。

二、创建一个我们自己的栈

1.前置准备

1.1需要的三个文件

在开始之前,我们最好创建三个文件,一个放栈函数的实现,一个用来测试栈函数,最后一个放栈函数的引用和头文件的引用,这样到时侯想要使用栈函数直接包这一个头文件即可。创建完之后,呈现出来的效果与下图差不多即可。

 1.2结构体的创建和头文件的引用

在进行操作之前,我们先在存放头文件和栈函数的文件中包几个常用的头文件,并且定义一下栈的结构体类型,栈只需要后进先出,也就是尾插尾删,那么使用数组亦或者使用链表实现难度是差不多的,这里我们使用数组实现。

使用数组实现要注意的便是,我们应该使用数组指针的形式实现,而不是单纯就一个数组,如果单纯就一个数组 ,就是一个静态的栈空间,而静态的栈空间在实际中几乎是没有任何用处的,这里我们要实现的是动态的。既然要实现的是动态的,那么我们应该想办法存储一下数组存放的元素个数,以及这个数组的容量大小,这样才能够判断出这个栈空间是否满了,从而根据需求扩大空间。因此我们创建的结构体应该要有一个数组指针,一个存放容量的大小,一个存放数组里面已经存放的元素个数。

最后呈现出来的差不多就是这个样子

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int STDateType;
//到时修改类型时只用改这里的一个就可以,不需要一个个修改
//同样,这也是为了和单一的int作区分
typedef struct stack
{
	STDateType* stack;//栈空间
	int top;//已经存放的元素个数
	int capacity;//容量大小
}ST;//创建栈的结构体,并将它的名字自定义为ST

 2.接口的实现

2.1初始化栈结构体

初始化栈结构体,一共有三步,第一步是将栈空间的空间开辟好,第二步是初始化栈结构体的容量,最后一步初始化栈结构体中存放元素个数的变量。

void init_stack(ST* s1)
{
	assert(s1);
	//传过来的是一个指针,不应该是空指针,空指针无法操作,故断言
	s1->stack = (STDateType*)malloc(sizeof(STDateType)*4);
	//将栈空间初始化成只可以存放4个元素的空间
	if (s1->stack == NULL)
	{
		perror("init_stack");
		//如果连基本的初始化都完成失败,就没有进行下去的必要了
		exit(-1);
	}
	s1->capacity = 4;
	//容量初始化成4
	s1->top = 0;
	//已经存放的元素个数初始化为0
}

2.2尾插(压栈)

压栈需要注意的一点便是,当栈满了的时候我们应该要考虑扩容

void push_stack(ST* s1, STDateType x)
{
	assert(s1);
	if (s1->capacity == s1->top)
	//空间满了,要扩容
	{
		int newcapacity = (s1->capacity) * 2;
		//扩容至原来的两倍
		s1->stack=(STDateType*)realloc(s1->stack, sizeof(STDateType)*newcapacity);
		if (s1->stack == NULL)
		{
			perror("push_stack");
			exit(-1);//扩容失败也别玩了
		}
		s1->capacity = newcapacity;
		//扩容成功,容量改变
	}
	s1->stack[s1->top] = x;//压栈
	s1->top++;//压栈成功,存放的元素个数+1
}

2.3栈存放的元素个数和判断栈是否为空

可能有小伙伴不明白为什么又要设计这两个接口,因为这两个信息都可以直接通过栈的结构体获得,好像没什么作用啊。设计这两个接口并使用它们而不是直接通过结构体的内容来判断是因为,当我们的需求发生改变了,所创建的结构体可能也会跟着修改,可能提取的方式会发生一些改变。如果我们在使用栈的时候已经直接通过结构体的内容进行了多次的判断,那么我们要修改起来,要修改多次,很不方便,这样做的好处就是只用修改一次即可。

栈存放的元素个数

int size_stack(ST* s1)
{
	assert(s1);
	return s1->top;
	//返回元素个数
}

 判断栈是否为空

int empty_stack(ST* s1)
{
	assert(s1);
	return s1->top == 0;
	//当存放的元素个数等于0意味着空
    //为空返回1(真),不为空返回0(假)
}

2.4获取栈顶元素

需要注意的点是,首先栈不能够是空的,其次top是元素的个数,不是当前元素的下标,上一个才是对应元素的下标。举个例子,当栈有一个元素时,top就为1了,而1指的是数组的第二个元素。

STDateType sttop(ST* s1)
{
	assert(s1);
	assert(!empty_stack(s1));
	//栈不能为空,为空则出不了栈
	return s1->stack[s1->top - 1];
}

2.5出栈

出栈相当简单,直接将存放元素个数的内容-1即可,如此就不可能再次访问到它

void pop_stack(ST* s1)
{
	assert(s1);
	assert(!empty_stack(s1));
	//栈不能为空
	s1->top--;
}

2.6摧毁栈

这个很简单,没什么好说的,直接将栈结构体的空间释放掉,并将对应的内容归零即可。

void destory_stack(ST* s1)
{
	assert(s1);
	s1->capacity = 0;
	s1->top = 0;
	free(s1->stack);
	s1->stack = NULL;
}

2.7测试接口

测试代码:
 

#include"stack.h"
void test1()
{
	ST s1;
	init_stack(&s1);
	push_stack(&s1, 1);
	push_stack(&s1, 2);
	push_stack(&s1, 3);
	push_stack(&s1, 4);
	push_stack(&s1, 5);
	printf("%d\n", size_stack(&s1));
	while (!empty_stack(&s1))
	{
		printf("%d ", sttop(&s1));
		pop_stack(&s1);
		//边打印栈顶元素边出栈
	}
	destory_stack(&s1);
    //摧毁栈
}
int main()
{
	test1();
}

测试结果:

三、所有代码

1.接口实现

#include"stack.h"
void init_stack(ST* s1)
{
	assert(s1);
	//传过来的是一个指针,不应该是空指针,空指针无法操作,故断言
	s1->stack = (STDateType*)malloc(sizeof(STDateType)*4);
	//将栈空间初始化成只可以存放4个元素的空间
	if (s1->stack == NULL)
	{
		perror("init_stack");
		//如果连基本的初始化都完成失败,就没有进行下去的必要了
		exit(-1);
	}
	s1->capacity = 4;
	//容量初始化成4
	s1->top = 0;
	//已经存放的元素个数初始化为0
}
void push_stack(ST* s1, STDateType x)
{
	assert(s1);
	if (s1->capacity == s1->top)
	//空间满了,要扩容
	{
		int newcapacity = (s1->capacity) * 2;
		//扩容至原来的两倍
		s1->stack=(STDateType*)realloc(s1->stack, sizeof(STDateType)*newcapacity);
		if (s1->stack == NULL)
		{
			perror("push_stack");
			exit(-1);//扩容失败也别玩了
		}
		s1->capacity = newcapacity;
		//扩容成功,容量改变
	}
	s1->stack[s1->top] = x;//压栈
	s1->top++;//压栈成功,存放的元素个数+1
}
void pop_stack(ST* s1)
{
	assert(s1);
	assert(!empty_stack(s1));
	//栈不能为空
	s1->top--;
}
STDateType sttop(ST* s1)
{
	assert(s1);
	assert(!empty_stack(s1));
	//栈不能为空,为空则出不了栈
	return s1->stack[s1->top - 1];
}
int size_stack(ST* s1)
{
	assert(s1);
	return s1->top;
	//返回元素个数
}
int empty_stack(ST* s1)
{
	assert(s1);
	return s1->top == 0;
	//当存放的元素个数等于0意味着空
	//为空返回1(真),不为空返回0(假)
}
void destory_stack(ST* s1)
{
	assert(s1);
	s1->capacity = 0;
	s1->top = 0;
	free(s1->stack);
	s1->stack = NULL;
}

2.栈的头文件

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int STDateType;
//到时修改类型时只用改这里的一个就可以,不需要一个个修改
//同样,这也是为了和单一的int作区分
typedef struct stack
{
	STDateType* stack;//栈空间
	int top;//已经存放的元素个数
	int capacity;//容量大小
}ST;//创建栈的结构体,并将它的名字自定义为ST
void init_stack(ST* s1);
void push_stack(ST* s1,STDateType x);
STDateType sttop(ST* s1);
int size_stack(ST*s1);
int empty_stack(ST* s1);
void destory_stack(ST* s1);
void pop_stack(ST* s1);

3.测试代码

#include"stack.h"
void test1()
{
	ST s1;
	init_stack(&s1);
	push_stack(&s1, 1);
	push_stack(&s1, 2);
	push_stack(&s1, 3);
	push_stack(&s1, 4);
	push_stack(&s1, 5);
	printf("%d\n", size_stack(&s1));
	while (!empty_stack(&s1))
	{
		printf("%d ", sttop(&s1));
		pop_stack(&s1);
		//边打印栈顶元素边出栈
	}
	destory_stack(&s1);
    //摧毁栈
}
int main()
{
	test1();
}

好了,栈就说完了,再来个三小时,博主爆肝一篇队列的。

感谢各位友友的来访,祝各位友友前程似锦O(∩_∩)O

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Qt扫盲-QWidget理论使用总结

QWidget理论使用总结 一、概述二、顶层 控件 和子 控件三、复合控件四、自定义控件和绘制五、大小提示和大小策略六、事件七、一组函数和属性八、QWidget样式表九、透明度和双缓冲十、创建半透明窗口 一、概述 widget 是用户界面的最小单位&#xff1a;它从window系统接收鼠标…

scope,deep穿透的实际应用

一.父组件代码 <template><div id"app"><h1 class"box"><pageName> </pageName></h1></div> </template><script> import pageName from "../src/components/pageName.vue"; export de…

threejs点击模型实现模型边缘高亮的选中效果--更改后提高帧率

先来个效果图 之前写的那个稍微有点问题&#xff0c;帧率只有30&#xff0c;参照官方代码修改后&#xff0c;帧率可以达到50了&#xff0c;在不全屏的状态下&#xff0c;帧率60 1.首先需要导入库 // 用于模型边缘高亮 import { EffectComposer } from "three/examples/js…

基于 eclipse-temurin 镜像部署spring boot 应用

基于 eclipse-temurin 镜像部署spring boot 应用 使用场景示例项目 使用场景 在CI流程中&#xff0c;一般都会集成 打包&#xff0c;构建镜像&#xff0c;分发&#xff0c;启动容器之类的流程&#xff1b; 这里提供一个示例&#xff0c;进攻参考 示例项目 项目结构如下 run…

佛祖保佑,永不宕机,永无bug

当我们的程序编译通过&#xff0c;能预防的bug也都预防了&#xff0c;其它的就只能交给天意了。当然请求佛祖的保佑也是必不可少的。 下面是一些常用的保佑图&#xff1a; 佛祖保佑图 ——————————————————————————————————————————…

架构实践方法

一、识别复杂度 将主要的复杂度问题列出来&#xff0c;然后根据业务、技术、团队等综合情况进行排序&#xff0c;优先解决当前面临的最主要的复杂度问题。对于按照复杂度优先级解决的方式&#xff0c;存在一个普遍的担忧&#xff1a;如果按照优先级来解决复杂度&#xff0c;可…

基于人工智能的中医图像分类系统设计与实现

华佗AI 《支持中医,永远传承古老文化》 本存储库包含一个针对中药的人工智能图像分类系统。该项目的目标是通过输入图像准确识别和分类各种中草药和成分。 个人授权许可证 版权所有 2023至2050特此授予任何获得华佗AI应用程序(以下简称“软件”)副本的人免费许可,可根据以…

Java并发编程(四)线程同步 中 [AQS/Lock]

概述 Java中可以通过加锁&#xff0c;来保证多个线程访问某一个公共资源时&#xff0c;资源的访问安全性。Java提出了两种方式来加锁 第一种是我们上文提到的通过关键字synchronized加锁&#xff0c;synchronized底层托管给JVM执行的&#xff0c;并且在java 1.6 以后做了很多…

第三章 图论 No.10无向图的双连通分量

文章目录 定义Tarjan求e-DCCTarjan求v-DCC395. 冗余路径1183. 电力396. 矿场搭建 定义 无向图有两种双连通分量 边双连通分量&#xff0c;e-DCC点双连通分量&#xff0c;v-DCC 桥&#xff1a;删除这条无向边后&#xff0c;图变得不连通&#xff0c;这条边被称为桥 边双连通分…

Jenkins 修改默认管理员帐号

1、新增一个新的超级管理员用户&#xff0c;并验证能正常登录 2、进入 Jenkins 用户管理目录&#xff1a; /data/software/jenkins/users 3、修改超级管理文件夹的名称为其他名称&#xff0c;如&#xff1a;mv admin_*** ifadm_*** 4、重启Jenkins容器

「C/C++」C/C++搭建程序框架

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「C/C」C/C程序设计&#x1f4da;全部专栏「UG/NX」NX二次开发「UG/NX」BlockUI集合「VS」Visual Studio「QT」QT5程序设计「C/C」C/C程序设计「Win」Windows程序设计「DSA」数据结构与算法「File」数据文件格式 目录 术语介绍…

记录一下Java实体转json字段顺序问题

特殊需求&#xff0c;和C交互他们那边要求字段顺序要和他们定义的一致(批框架) 如下&#xff1a; Data public class UserDto {private String name;private Integer age;private String addr; }未转换前打印&#xff1a; 转换后打印&#xff1a; 可以看到转换为json顺序打印…

029 - integer types 整数类型

MySQL支持SQL标准整数类型 INTEGER&#xff08;或INT&#xff09;和 SMALLINT。作为一个可扩展标准&#xff0c;MySQL也支持整数类型 TINYINT&#xff0c;MEDIUMINT和 BIGINT。下表显示了每种整数类型所需的存储空间和范围。 表11.1 MySQL支持的整数类型的必需存储和范围 类型…

PLY模型格式详解【3D】

本文介绍PLY 多边形文件格式&#xff0c;这是一种用于存储被描述为多边形集合的图形对象。 PLY文件格式的目标是提供一种简单且易于实现但通用的格式足以适用于各种模型。 PLY有两种子格式&#xff1a;易于入门的 ASCII 表示形式和用于紧凑存储和快速保存和加载的二进制格式。 …

案例14 Spring MVC文件上传案例

基于Spring MVC实现文件上传&#xff1a; 使用commons-fileupload实现上传文件到本地目录。 实现上传文件到阿里云OSS和从阿里云OSS下载文件到本地。 1. 创建项目 选择Maven快速构建web项目&#xff0c;项目名称为case14-springmvc03。 ​ 2. 配置Maven依赖 <?xml ver…

点淘的MCN机构申请详细入驻指南!

消费趋势的变化&#xff0c;来自消费人群的变化。 后疫情时代&#xff0c;经济复苏的反弹力度不足&#xff0c;人们开始怀疑我们正从前几年的消费升级&#xff0c;跌入消费降级的时代&#xff0c;但这并不能准确概括消费市场的变化。 仔细翻看各大奢侈品集团的财报&#xff0…

nvm下载node导致npm报错无法使用

有个依赖库需要更新下node&#xff0c;用nvm下载后项目跑不起来了&#xff0c;npm -v 还报错 其实一开始是npm下载不来&#xff0c;然后换了淘宝镜像后还是报错 然后就只能手动下载下了 进入node.js官网 https://nodejs.org/en/download 下载后注意要安装在你nvm目录中&#x…

绕过 open_basedir

目录 0x01 首先了解什么是 open_basedir 0x02 通过命令执行绕过 0x03 通过symlink 绕过 &#xff08;软连接&#xff09; 0x04利用glob://绕过 方式1——DirectoryIteratorglob:// 方式2——opendir()readdir()glob:// 0x05 通过 ini_set和chdir来绕过 在ctfshow 72遇到…

实践|Linux 中查找和删除重复文件

动动发财的小手&#xff0c;点个赞吧&#xff01; 如果您习惯使用下载管理器从互联网上下载各种内容&#xff0c;那么组织您的主目录甚至系统可能会特别困难。 通常&#xff0c;您可能会发现您下载了相同的 mp3、pdf 和 epub&#xff08;以及各种其他文件扩展名&#xff09;并将…

OpenCV实例(九)基于深度学习的运动目标检测(一)YOLO运动目标检测算法

基于深度学习的运动目标检测&#xff08;一&#xff09; 1.YOLO算法检测流程2.YOLO算法网络架构3.网络训练模型3.1 训练策略3.2 代价函数的设定 2012年&#xff0c;随着深度学习技术的不断突破&#xff0c;开始兴起基于深度学习的目标检测算法的研究浪潮。 2014年&#xff0c;…