数据结构之栈的实现

2023/11/30 10:20:31

文章目录

  • 前言
  • 1.栈的相关介绍
    • 1.栈的概念
    • 2.栈结构实现方式
  • 2.具体代码实现栈
    • 1.栈的相关接口
    • 2.栈结构的定义声明和栈的初始化
    • 3.栈数据的处理
      • 1.入栈
      • 2.出栈
    • 4.栈判空和获取栈中元素个数以及栈销毁
  • 3.总结

前言

之前介绍了链表的实现,现在接着介绍另一种线性结构—栈。栈和链表一样,都是很经典的数据结构。通过学习栈,为以后学习其他数据结构打下坚实的基础。


1.栈的相关介绍

1.栈的概念

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

栈的概念可以联想到桌子上放的书。我们将书一本书放另一本书上,若干本书这样挨个往上放,当我们取书时,是从最上面开始拿,如果想拿最下面的书,就得将这本书上面的书都拿下来,才能拿到最下面的书,这个放书的过程就像入栈,拿书的过程就像出栈。
在这里插入图片描述


2.栈结构实现方式

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

在这里插入图片描述

我们知道栈入数据和出数据都是从栈顶开始,如果用数组表示栈,那么入数据就相当于尾插,出数据就相当于尾删,这样的操作对数组来说是十分友好的。如果是链表来实现栈找栈顶还需要遍历,双向循环链表不用遍历可以快速找到栈顶,但是这未免有些麻烦了一点,数组用起来简单方便一点。


2.具体代码实现栈

1.栈的相关接口

void StackInit(Stack* ps);// 初始化栈
void StackPush(Stack* ps, STDataType x);//入栈
void StackPop(Stack* ps);//出栈
STDataType StackTop(Stack* ps);//获取栈顶元素
int StackSize(Stack* ps);// 获取栈中有效元素个数
int StackEmpty(Stack* ps); //检测栈是否为空,如果为空返回非零结果,如果不为空返回0
void StackDestroy(Stack* ps);//销毁栈

其实栈的实现有点像之前我们实现的顺序表,最大的区别就是栈的数据只能栈顶出或者进。所以栈的数据只能尾插尾删,同时还有个函数专门用来获取栈顶数据。这是根据栈的特性来决定栈中数据存取方式。


2.栈结构的定义声明和栈的初始化

typedef int STDataType;
typedef struct Stack
{
	STDataType* data;
	int top;		// 栈顶
	int capacity;  // 容量 
}Stack;

刚才说了,栈的实现是和顺序表有点像,因为顺序表一般也是用数组来实现的。我们这里采用动态顺序表的实现方式,实现动态栈。当栈中空间不够时,可申请动态内存空间进行增容。
代码中的top其实有点像实现通讯录时中的sz(表示存储联系人信息的个数),知识都是相通的,灵活应用很重要。


栈的初始化

void StackInit(Stack* ps)//初始化
{
	assert(ps);
	ps->data = (STDataType*)malloc(sizeof(STDataType)*4);
	ps->top = 0;
	ps->capacity=4;
	return;
}

栈顶初始化,为栈开辟一段空间用来存储数据。因为栈中没有数据top初始化为0,因为只是申请了4个结构体大小的空间,所以就没有就行判断空处理。这里注意一下,栈的数据是从栈顶开始存放的,数组的下标索引是从0开始的,没有数据时,top就是0,意味着top是指向栈顶元素的下一个位置。在实现代码时注意这一点就好了。


3.栈数据的处理

1.入栈

void StackPush(Stack* ps, STDataType x)//入栈
{
	assert(ps);
	if (ps->top == ps->capacity)
	{
     STDataType* tem = 
    (STDataType*)realloc
    (ps->data, ps->capacity*2*sizeof(STDataType));
		if (tem == NULL)
		{
			perror("StackPush:");
			exit(-1);
		}
		ps->data = tem;
		ps->capacity *= 2;
	}

	ps->data[ps->top] = x;
	ps->top++;
	return;
}

入栈就是尾插数据,也就是按顺序插入数据。因为刚才说了top是指向栈顶元素下一个位置,初始化top为0表示的是空栈,但是数组索引从0开始,因此先插入数据,然后top自增,这样做的另一个好处就是top就是栈中元素个数。空间扩容就不多说了,之前博客有介绍。


2.出栈

出栈就相当于尾删,然后top(栈顶)往下降一个单位。但是,出栈肯定是要得到某个数据,就是将栈中的数据弹出来,然后栈顶往下降。因此还需要个函数来获取栈顶的元素。

栈顶元素获取

STDataType StackTop(Stack* ps)//获取栈顶元素
{
	assert(ps);
	assert(!StackEmpty(ps));
	return ps->data[ps->top - 1];
}

因为top是指向栈顶元素下一个位置的,所以栈顶元素的索引应该是top-1.还有一点当栈为空时,就不能获取元素,所以要断言一下。


出栈

void StackPop(Stack* ps)//出栈
{
	assert(ps);
	assert(!StackEmpty(ps));
	ps->top--;
}

出栈就相当于尾删,和顺序表的尾插一样,都很简单。


4.栈判空和获取栈中元素个数以及栈销毁

栈判空非常简单,top为0就是空栈。如果top大于0就不是空栈。

栈判空

int StackEmpty(Stack* ps)//栈判空
{    assert(ps);
	return ps->top == 0;
}

其实栈判空应该用布尔值来表示比较好,c语言中用布尔值需要用到相应的头文件,这个之前的博客也提到过。


获取栈中元素个数也很简单,刚才说了top的值就是栈中元素个数

栈中数据个数


int StackSize(Stack* ps)//获取栈中有效元素个数
{  
	aseert(ps);
	return ps->top;
}

因为数组索引是0开始的,而top又是指向栈顶元素下一个位置的,刚好top就是栈元素个数。


销毁栈还是和销毁动态顺序表一样,用free释放掉申请的动态内存空间即可

销毁栈

void StackDestroy(Stack* ps)//销毁栈
{
	assert(ps);
	free(ps->data);
	ps->data = NULL;
	ps->top = 0;
	ps->capacity = 0;
	return;
}

释放掉空间后,该置空的置空,该置0的置0,实现起来还是比较简单的。


3.总结

  • 1.栈的实现相对比较简单,但是在使用栈时要注意,先获取栈顶元素,在进行出栈处理。如果先出栈,就找不到之前的栈顶元素了,如果不需要用到栈顶元素,那就不用关心这点,直接出栈就好了。
  • 2.以上内容,如有错误,欢迎指出!谢谢!

http://www.jnnr.cn/a/125277.html

相关文章

web安全渗透之钓鱼网站提权

本实验实现1:要生成一个钓鱼网址链接,诱导用户点击,实验过程是让win7去点击这个钓鱼网站链接,则会自动打开一个文件共享服务器的文件夹,在这个文件夹里面会有两个文件,当用户分别点击执行后,则会…

Web安全漏洞——SSTI模版注入(初级)

目录 前言: (一)什么是SSTI 举个栗子: 前提: 自动化工具: (二)Flask模块注入 0x01 常用的内建属性 __class__ _base__ __bases__ __mro__ __subclasses__() __dict__ __init__ __global__ __…

TCP半连接队列和全连接队列

一、什么是半连接队列和全连接队列 在TCP连接的服务端,linux内核会维护两个队列 SYN队列,也成半连接队列accept队列,全连接队列 服务端收到客户端发起的 SYN 请求后,内核会把该连接存储到半连接队列,并向客户端响应…

数据结构学习笔记——归并排序

目录一、排序思想二、算法分析三、总结一、排序思想 归并排序是将两个或两个以上的有序表组合成一个新的有序表,它采用的是分治法,例如将两个有序表合并成一个有序表,即二路归并排序。归并排序的具体步骤如下:将含有n个元素的序列…

【PAT甲级 - C++题解】1063 Set Similarity

✍个人博客:https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 📚专栏地址:PAT题解集合 📝原题地址:题目详情 - 1063 Set Similarity (pintia.cn) 🔑中文翻译:集合相似度 📣…

【JavaWeb的从0到1构建知识体系(七)】JUnit和JUL日志系统

使用JUnit可进行单元测试 首先一问:我们为什么需要单元测试? 随着我们的项目逐渐变大,比如我们之前编写的图书管理系统,我们都是边在写边在测试,而我们当时使用的测试方法,就是直接在主方法中运行测试&am…

面试:CountDownLatch、CyclicBarrier 原理

CountDownLatch 基于 AQS 的共享模式的使用;CyclicBarrier 基于 Condition 来实现的。 一、CountDownLatch原理描述 CountDownLatch是利用AQS的state来做计数器功能,当初始化CountDownLatch时,会将state值进行初始化,让调用Coun…

阿里二面:RocketMQ 消息积压了,增 加消费者有用吗?

面试官:RocketMQ 消息积压了,增 加消费者有用吗? 我:这个要看具体的场景,不同的场景下情况是不一样的。 面试官:可以详细说一下吗? 我:如果消费者的数量小于 MessageQueue 的数量…

Js逆向教程-02浏览器调试工具-Network面板

作者:虚坏叔叔 博客:https://xuhss.com 早餐店不会开到晚上,想吃的人早就来了!😄 Js逆向教程-02浏览器调试工具-Network面板 切换到Network面板 一、网络请求处理相关面板 网络请求处理相关面板有很多功能&#xff0…

OptBinning 特征分箱包使用介绍

OptBinning 特征分箱包使用介绍 OptBinning:支持数值型和分类型的最大IV分箱,并可保证分箱单调性,同事方便处理缺失值。作为一个分箱包还是挺好用,这里简答介绍了这个包中OptimalBinning和fit_transform的参数。 1、使用案例 i…

Moment.js的基本使用

一、Moment.js的简介 Moment.js是一个轻量级的JavaScript时间库,以前我们转化时间,都会进行很复杂的操作,而Moment.js的出现,简化了我们开发中对时间的处理,提高了开发效率。日常开发中,通常会对时间进行下…

何为指针,与数组名有什么区别

我常常看到很多人无法理解何为指针,以至于产生了许多奇怪的理解。有人说,一维数组就是一级级指针,二维数组就是二级指针。因为一维数组的数组名就是该数组的首元素的地址,而二维数组的数组名是一个一维数组的首元素地址。所以他们…

亲测可用的RT1052+FreeRTOS10.3移植CmBacktrace方法——2022.11.12

搜遍全网都找不到一个靠谱的RT1052可用的移植方法,自己弄了一个分享出来,禁止一切形式未经许可的转载复制。 文章目录CmBacktrace移植CmBacktrace前期准备移植过程添加CmBacktrace到工程配置CmBacktrace适配FreeRTOS使用CmBacktrace追踪错误初始化CmBack…

别说我自私,大牛亲码607页JUC源码分析来了

前言 你知道java中的juc是什么意思吗?很多人表示对于java juc不是很了解 JUC就是java.util.concurrent包,俗称java并发包,是Java开发工程师学习并发的时候需要掌握的内容。 主要内容如图所示: 在Java 5.0提供了java.util.concurrent (简称…

LeetCode链表练习(下)

文章目录前言1.链表分割1.题目分析2.代码示例2.环形链表1.题目分析2.代码示例3.142. 环形链表 II1.题目分析2.代码示例4.138. 复制带随机指针的链表1.题目分析2.代码示例5.237. 删除链表中的节点1.题目分析2.代码示例6.总结前言 本文还是继续介绍链表经典题,中间会…

【微服务SpringCloud-Alibaba】:Nacos 配置中心

文章目录1、Nacos 配置中心2、快速入门2.1、添加配置文件2.2、配置的获取3、配置文件分类1、Nacos 配置中心 在 SpringCloud 中,我们使用了 Config 组件管理所有配置文件,使用了 Bus 消息总线更新配置,两者需要配合使用才能动态的管理配置文…

计算机网络---UDP协议

(一)UDP概述 UDP 仅在IP的数据报服务之上增加了两个最基本的服务:复用和分用以及差错检测。如果应用开发者选择UDP而非 TCP,那么应用程序几乎直接与IP打交道。为什么应用开发者宁愿在UDP 之上构建应用,也不选择 TCP&am…

Appium自动化测试<三>

本文接着Appium自动化测试<二> 写:文章戳这里 一、Appium 元素定位方式 需要导入的库:from appium.webdriver.common.appiumby import AppiumBy 常用的元素定位方式: 1. id 定位元素2. class_name 定位元素3. con…

C++ builder XE 关于intraweb TChart转换成IWimage的网页显示处理

//先随机生成三条柱状图形对比,但是如果光是TChart是无法显示在intraweb网页上的,需要转成图片显示 void __fastcall TIWForm1::IWButton3Click(TObject *Sender) { Chart1->ClearChart(); Chart1->AlignalTop; Chart1->Height300; //高度 Chart1->View…

python,字典修改key键值

#字典修改key键值 #要修改的字典 l {a:3,b:2} #将键值和值,分别用列表保存,并初始化l key list(l.keys()) value list(l.values()) l {} #将key列表,和value列表填充回去 for i in range(len(key)):l[i] value[i] l # l[a] 12 # l[a]l[…
最新文章