顺序结构实现栈

news2024/12/25 12:28:26

顺序结构实现栈

    • 1. 栈
      • 1.1 栈的概念及结构
      • 1.2栈的实现
    • 2. 栈的各种函数实现
    • 3. 全部代码实现

1. 栈

1.1 栈的概念及结构

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

压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。

出栈:栈的删除操作叫做出栈。出数据也在栈顶。

如图所示:

在这里插入图片描述

入栈的时候只能从最上方入数据,取的时候也只能从最上方拿数据

在这里插入图片描述

1.2栈的实现

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

数组实现栈

在这里插入图片描述
链表实现栈
在这里插入图片描述

如果用单链表实现栈最好用头部做栈顶,因为头插,头删比较方便

2. 栈的各种函数实现

首先,我们先定义一个栈的结构

typedef int STDataType;

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

初始化栈

void STInit(ST* st)
{
	assert(st);

	st->a = NULL;
	st->capacity = 0;
	//st->top = -1 //top 指向栈顶元素
	st->top = 0;//top 指向栈顶元素的下一个
}

这里的top可以初始化成0也可以初始化为-1,但是初始化为0,这里的top就相当于顺序表力的size,那么top始终指向要插入元素的下一个,后续操作的时候也会很方便。

销毁栈

void STDestroy(ST* st)
{
	assert(st);

	free(st->a);
	st->a = NULL;
	st->capacity = 0;
	st->top = 0;
}

因为栈的空间是动态开辟的,所以在栈使用结束后,需要把动态开辟的空间释放,避免造成内存泄漏。

入栈

void STPush(ST* st,STDataType x)
{
	assert(st);

	STCheckcapacity(st);

	st->a[st->top] = x;
	st->top++;
}

这里也可以不把扩容的代码单独写成一个函数,因为这里只有这一个地方会用到扩容操作,但是还是建议封装成一个函数,一方面可以提高代码的可读性,另一方面平时我们写代码的时候这个操作一般都是封装成一个函数,所以这样写可以在一定程度上避免代码出错。

检查是否需要扩容

void STCheckcapacity(ST* st)
{
	assert(st);

	if (st->top == st->capacity)
	{
		int newcapacity = st->capacity == 0 ? 4 : st->capacity * 2;

		STDataType* ptr = (STDataType*)realloc(st->a, sizeof(STDataType) * newcapacity);
		if (ptr == NULL)
		{
			perror("realloc fail");
			exit(1);
		}

		st->a = ptr;
		st->capacity = newcapacity;
	}
}

出栈

void STPop(ST* st)
{
	assert(st);
	assert(!STEmpty(st));

	st->top--;
}

注意:栈为空的时候不能删除

取出栈顶元素

STDataType STTop(ST* st)
{
	assert(st);
	assert(!STEmpty(st));

	return st->a[st->top - 1];
}

注意:栈为空的时候不能取栈顶元素,top因为初始化为0,所以指向要插入元素的下一个,所以top-1就是最后一个元素的位置

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

bool STEmpty(ST* st)
{
	assert(st);

	return st->top == 0;
}

这里的栈的top就相当于顺序表里面的size即有效元素的个数,所以直接判断top是否为0就可以了,当top等于0的时候为栈为空,返回真。

获取栈中有效元素个数

int STSize(ST* st)
{
	assert(st);

	return st->top;
}

这里的栈的top就相当于顺序表里面的size即有效元素的个数,所以直接返回top就可以了。

3. 全部代码实现

Stack.h

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

typedef int STDataType;

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

//初始化栈
void STInit(ST* st);
//销毁栈
void STDestroy(ST* st);
//入栈
void STPush(ST* st,STDataType x);
//出栈
void STPop(ST* st);
//取出栈顶元素
STDataType STTop(ST* st);
//检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
bool STEmpty(ST* st);
//获取栈中有效元素个数
int STSize(ST* st);

Stack.c

#include "Stack.h"
//初始化栈
void STInit(ST* st)
{
	assert(st);

	st->a = NULL;
	st->capacity = 0;
	//st->top = -1 //top 指向栈顶元素
	st->top = 0;//top 指向栈顶元素的下一个
}
//销毁栈
void STDestroy(ST* st)
{
	assert(st);

	free(st->a);
	st->a = NULL;
	st->capacity = 0;
	st->top = 0;
}

void STCheckcapacity(ST* st)
{
	assert(st);

	if (st->top == st->capacity)
	{
		int newcapacity = st->capacity == 0 ? 4 : st->capacity * 2;

		STDataType* ptr = (STDataType*)realloc(st->a, sizeof(STDataType) * newcapacity);
		if (ptr == NULL)
		{
			perror("realloc fail");
			exit(1);
		}

		st->a = ptr;
		st->capacity = newcapacity;
	}
}
//入栈
void STPush(ST* st,STDataType x)
{
	assert(st);

	STCheckcapacity(st);

	st->a[st->top] = x;
	st->top++;
}
//出栈
void STPop(ST* st)
{
	assert(st);
	assert(!STEmpty(st));

	st->top--;
}
//取出栈顶元素
STDataType STTop(ST* st)
{
	assert(st);
	assert(!STEmpty(st));

	return st->a[st->top - 1];
}
//检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
bool STEmpty(ST* st)
{
	assert(st);

	return st->top == 0;
}
//获取栈中有效元素个数
int STSize(ST* st)
{
	assert(st);

	return st->top;
}

Test.c

#include "Stack.h"

int main()
{
	ST st;
	STInit(&st);
	STPush(&st, 1);
	STPush(&st, 2);
	STPush(&st, 3);
	STPush(&st, 4);
	while (!STEmpty(&st))
	{
		printf("%d ", STTop(&st));
		STPop(&st);
	}
	printf("\n");
	STDestroy(&st);

	return 0;
}

因为栈是后进先出的,所以要访问栈里面的元素时,必须要把栈当前元素取出才能访问下一个元素,每可以看到在打印栈里面的内容时,会把栈变成空,那么栈里面的内容就没有了,但时这也是实际当中的需求,所以不会有什么影响。

运行结果如图:
在这里插入图片描述

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

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

相关文章

浅析太阳能电池量子效率测试系统的主要组成部分

太阳能电池量子效率测试系统是用于对太阳能电池进行量子效率测试的设备。量子效率是指太阳能电池在接收光照射时&#xff0c;将光子转化为电子的效率。太阳能电池的量子效率越高&#xff0c;其转化光能为电能的效率就越高。主要由以下几个组成部分构成&#xff1a; 光源&#x…

MIT-BEVFusion系列八--onnx导出2 spconv network网络导出

这里写目录标题 export-scn.py加载模型设置每层的精度属性初始化输入参数导出模型model.encoder_layers 设置初始化参数设置 indice_key 属性更改 lidar backbone 的 forward更改lidar网络内各个层的forward带参数装饰器&#xff0c;钩子函数代码使用装饰器修改forward举例 跟踪…

SpringBoot实战第五天

最后在开发一个文件上传接口&#xff0c;结束后端部分开发 文件上传接口 先看接口文档 阅读接口文档&#xff0c;唯一问题就是项目暂时还没有传到服务器上&#xff0c;所以对文件的存储与读取暂时在项目本地进行 Controller层 RestController public class FileUploadCont…

探索设计模式的魅力:揭秘模版方法模式-让你的代码既灵活又可维护

设计模式专栏&#xff1a;http://t.csdnimg.cn/U54zu 目录 一、开篇二、应用场景一坨坨代码实现存在的问题 三、解决方案模式方法结构示意图及说明用模板方法模式重构示例解决的问题 四、工作原理使用模板方法模式重写示例结构图核心结构&#xff1a;抽象类和具体实现 五、总结…

IDEA 的28 个天花板技巧,yyds!

IDEA 作为Java开发工具的后起之秀,几乎以碾压之势把其他对手甩在了身后,主要原因还是归功于:好用;虽然有点重,但依旧瑕不掩瑜,内置了非常多的功能,大大提高了日常的开发效率,下面汇总了常用的28个使用小技巧,学会之后,让你的撸码效率直接起飞... 注意:不同idea版本菜…

计算机二级之sql语言的学习(数据模型—概念模型)

概念模型 含义: 概念模型用于信息世界&#xff08;作用对象&#xff09;的建模&#xff0c;是实现现实世界到信息世界&#xff08;所以万丈高楼平地起&#xff0c;不断地学习相关的基础知识&#xff0c;保持不断地重复才能掌握最为基础的基础知识&#xff09;的概念抽象&#…

SG5032VEN晶体振荡器SPXO

在高速数字通信和精密电子系统中&#xff0c;时钟信号的质量至关重要。SG5032VEN晶体振荡器&#xff08;SPXO&#xff09;凭借其低相位抖动的LVDS输出&#xff0c;为这些应用提供了理想选择。提供频率范围:200.1 MHz ~ 500mhz&#xff0c;满足了从高速网络到数据中心等不同应用…

Java编程在工资信息管理中的最佳实践

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

【c++】析构函数

1.特征 析构函数是特殊的成员函数&#xff0c;其特征如下&#xff1a; 1.析构函数名是在类名前加上字符~。 2.无参数无返回值类型。 3.一个类只能有一个析构函数。若未显式定义&#xff0c;系统会自动生成默认的析构函数。注意&#xff1a;析构函数不能重载。 4.对象生命周…

HTML-多媒体嵌入-MDN文档学习笔记

HTML-多媒体与嵌入 查看更多学习笔记&#xff1a;GitHub&#xff1a;LoveEmiliaForever MDN中文官网 HTML-中的图片 将图片放入网页 可以使用<img/>来将图片嵌入网页&#xff0c;它是一个空元素&#xff0c;最少只需src属性即可工作 <img src"图片链接"…

【Python】测量WAV文件播放时长

问题 windows播放WAV音频文件&#xff0c;一般使用API函数&#xff0c;如PlaySound。实际使用发现&#xff0c;从调用PlaySound到实际开始播放存在200ms以上的延时&#xff0c;在游戏编程中音效实时性是个需要解决的问题。 本文主要讨论&#xff0c;windows播放WAV文件的衍生…

JVM-JVM中对象的生命周期

申明&#xff1a;文章内容是本人学习极客时间课程所写&#xff0c;文字和图片基本来源于课程资料&#xff0c;在某些地方会插入一点自己的理解&#xff0c;未用于商业用途&#xff0c;侵删。 原资料地址&#xff1a;课程资料 对象的创建 常量池检查:检查new指令是否能在常量池…

ESP32-Cam学习(1)——拍摄第一张照片

1.开发板介绍 使用的ESP32-Cam实物图为&#xff1a; 在某宝可以轻易买到。它分为主板&#xff0c;和底板。底板的主要功能是供电、程序下载等等。主板才是ESP32芯片的核心。 2.固件烧录 使用摄像头之前&#xff0c;需要给ESP32刷入支持摄像头的固件库&#xff0c;其下载地址为…

(07)Hive——窗口函数详解

一、 窗口函数知识点 1.1 窗户函数的定义 窗口函数可以拆分为【窗口函数】。窗口函数官网指路&#xff1a; LanguageManual WindowingAndAnalytics - Apache Hive - Apache Software Foundationhttps://cwiki.apache.org/confluence/display/Hive/LanguageManual%20Windowing…

线索化二叉树(先序,中序,后序)+线索化二叉树的遍历【java详解】

目录 线索化二叉树的基本介绍&#xff1a; 举个栗子&#xff1a; 二叉树的中序线索化&#xff1a; 创建HeroNode类&#xff0c;表示节点信息&#xff1a; 编写中序线索化方法代码&#xff1a; 中序线索化遍历代码&#xff1a; 测试代码&#xff1a; 测试结果&#xff1a…

OpenAI发布Sora技术报告深度解读!真的太强了!

&#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主、前后端开发、人工智能研究生。公粽号&#xff1a;洲与AI。 &#x1f388; 本文专栏&#xff1a;本文收录…

NodeJS背后的人:Express

NodeJS背后的人&#xff1a;Express 本篇文章&#xff0c;学习记录于&#xff1a;尚硅谷&#x1f3a2; 文章简单学习总结&#xff1a;如有错误 大佬 &#x1f449;点. 前置知识&#xff1a;需要掌握了解&#xff1a; JavaScript基础语法 、Node.JS环境API 、前端工程\模块化 …

代码随想录算法训练营第53天 | 121.买卖股票的最佳时机 + 122.买卖股票的最佳时机II

今日任务 121. 买卖股票的最佳时机 122.买卖股票的最佳时机II 121.买卖股票的最佳时机 - Easy 题目链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第…

Rust 语言学习杂谈 (end) (各种工作中遇到的疑难杂症)

1.在运行 “cargo build --release” 的时候&#xff0c;到底发生了什么&#xff1f; 源 (GPT4.0) : 当我们运行 cargo build --release 命令时&#xff0c;实际上在进行一系列复杂的步骤来编译和构建 Rust 项目的发布版本。这个过程大致可以分解为以下几个步骤&#xff1a;…

Java - SPI机制

本文参考&#xff1a;SPI机制 SPI&#xff08;Service Provider Interface&#xff09;&#xff0c;是JDK内置的一种服务提供发现机制&#xff0c;可以用来启动框架扩展和替换组件&#xff0c;主要是被框架的开发人员使用&#xff0c;比如 java.sql.Driver接口&#xff0c;其他…