【数据结构】千字深入浅出讲解栈(附原码 | 超详解)

在这里插入图片描述

🚀write in front🚀
📝个人主页:认真写博客的夏目浅石.
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝
📣系列专栏:C语言实现数据结构
💬总结:希望你看完之后,能对你有所帮助,不足请指正!共同学习交流 🖊
✉️如果无聊的话,就来逛逛我的博客栈吧stack-frame.cn

文章目录

  • 前言
  • 一、栈的概念
  • 二、栈的结构
  • 三、栈的实现
    • 3.1 结构设计
    • 3.2 接口总览
    • 3.3 初始化
    • 3.4 销毁
    • 3.5 判断栈是否为空
    • 3.6 入栈
    • 3.7 出栈
    • 3.8 取栈顶元素
    • 3.9 计算栈的大小
  • 四、 完整代码
    • Stack.h
    • Stack.c
    • test.c
  • 总结


前言

这几天看了数据结构的栈这一节,真的收获很大,第一次看没有动手敲代码就是感觉学了和没学一样,今天也是从新又看了一遍,并且边学边敲代码,终于算是非常理解栈这个东西了,今天就把我所学到的知识给大家分享一下


一、栈的概念

是一个特殊的 线性表

只允许在固定的一段进行插入删除元素的操作。进行数据插入和删除操作的一端称为栈顶,不进行操作的一端称为栈底

栈中的元素遵守 后进先出 (LIFO - Last In First Out) 的原则。也就是先进的后出,后进的先出

栈对于数据的管理主要有两种操作:

  1. 压栈:栈的插入操作叫做进栈 / 压栈 / 入栈,从栈顶进行压栈。
  2. 出栈:栈的删除操作叫做 出栈,从栈顶进行出栈。
    在这里插入图片描述

二、栈的结构

栈一般可以使用 数组或链表 实现。让我们分析一下使用这两种方法实现,栈的结构分别是什么样的。

在分析之前,我们要明确的一点是,栈只对 栈顶 的元素进行操作。

那么对于 顺序栈链式栈 ,那个更加好呢?那必定是 顺序栈,因为使用顺序栈的 尾插尾删非常方便, 且 cpu缓存利用率也更高。而且对于顺序栈实现起来相对简单,所以我们接下来就实现 顺序栈 。

三、栈的实现

3.1 结构设计

我们既然是实现 顺序栈,那么它的结构肯定就和 顺序表 差不多:

typedef struct Stack
{
	STDatatype* a; // 指向动态开辟的数组
	int capacity; // 栈的容量
	int top; // 标识 栈顶的下一个位置的下标 或 栈顶的下标
}ST;

这里的 top 我们需要好好理解一下。当top初始值不同时,top可以表示 栈顶的下一个位置的下标栈顶下标

  1. top = 0top 表示栈顶的下一个位置的下标:

在这里插入图片描述
2. 当 top = -1top 表示栈顶的下标:

在这里插入图片描述

top 初始值为 -1,那么需要先 ++top再压栈。否则会越界。当 最后一次压栈时,为先 ++top 再压栈,top 最后的位置就是栈顶的下标处。

3.2 接口总览

void StackInit(ST* ps); // 初始化
void StackDestroy(ST* ps); // 销毁
void StackPush(ST* ps, STDatatype x); // 压栈
void StackPop(ST* ps); // 出栈
STDatatype StackTop(ST* ps); // 取栈顶元素
bool StackEmpty(ST* ps); // 判空
int StackSize(ST* ps); // 计算栈的大小

3.3 初始化

我们实现的是顺序栈,那么就和顺序表一样,需要创建结构体变量,传结构体的地址,进行初始化。

在初始化的时候就给栈开上四个单位的空间,并且将起始容量设定为4。

注意了我们这里设定的 top = 0,那么表示 top 为栈顶的下一个位置的下标。

void StackInit(ST* ps)
{
	// 结构体一定不为空,所以需要断言
	assert(ps);

	ps->a = (STDatatype*)malloc(sizeof(STDatatype) * 4);
	if (ps->a == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	ps->capacity = 4;
	ps->top = 0;
}

3.4 销毁

对于栈的销毁,那么我们就只需要释放动态开辟的空间,将指针置空。并将 capacity 和 top 两个变量置 0即可。

void StackDestroy(ST* ps)
{
	assert(ps);

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

3.5 判断栈是否为空

我们起初设定 top = 0,所以判断栈是否为空,那么只需要看 top 是否为0就可以了。如果为0,返回真 ;不为0,返回假。

bool StackEmpty(ST* ps)
{
	assert(ps);
	
    // 如果 ps->top == 0,返回真
    // 如果 ps->top !=0,返回假
	return ps->top == 0;
}

3.6 入栈

void StackPush(ST* ps, STDatatype x)
{
	assert(ps);

	// 检查容量
	if (ps->top == ps->capacity)
	{
		STDatatype* tmp = (STDatatype*)realloc(ps->a, sizeof(STDatatype) * ps->capacity * 2);
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity *= 2;
	}
	// 插入元素
	// top 为栈顶的下一个元素
	// 先插入再 ++ 
	ps->a[ps->top] = x;
	ps->top++;
}

3.7 出栈

void StackPop(ST* ps)
{
	assert(ps);

	// 如果栈空,则不能删除
	assert(!StackEmpty(ps));
	ps->top--;
}

3.8 取栈顶元素

STDatatype StackTop(ST* ps)
{
	assert(ps);

	assert(!StackEmpty(ps));

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

3.9 计算栈的大小

int StackSize(ST* ps)
{
	assert(ps);

	return ps->top;
}

四、 完整代码

Stack.h

#pragma once

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

typedef int STDatatype;

typedef struct Stack
{
	STDatatype* a;
	int capacity;
	int top;   // 初始为0,表示栈顶位置下一个位置下标
    		   // 初始为-1,表示栈顶位置的下标
}ST;

void StackInit(ST* ps);
void StackDestroy(ST* ps);
void StackPush(ST* ps, STDatatype x);
void StackPop(ST* ps);
STDatatype StackTop(ST* ps);
bool StackEmpty(ST* ps);
int StackSize(ST* ps);

Stack.c

#define _CRT_SECURE_NO_WARNINGS 1 

#include "Stack.h"

// top 为栈顶 初识值为 -1

void StackInit(ST* ps)
{
	// 结构体一定不为空
	assert(ps);

	ps->a = (STDatatype*)malloc(sizeof(STDatatype) * 4);
	if (ps->a == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	ps->capacity = 4;
	ps->top = -1;
}

void StackDestroy(ST* ps)
{
	assert(ps);

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

void StackPush(ST* ps, STDatatype x)
{
	assert(ps);

	// 检查容量
	// 此时 top 一开始为 -1,不能表示栈中元素的数目
	// top + 1 才是正确的

	if (ps->top + 1 == ps->capacity)
	{
		STDatatype* tmp = (STDatatype*)realloc(ps->a, sizeof(STDatatype) * ps->capacity * 2);
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity *= 2;
	}
	// 插入元素
	// top 为栈顶元素
	// 先 ++ 再插入
	ps->a[++ps->top] = x;
}

void StackPop(ST* ps)
{
	assert(ps);

	// 如果栈空,则不能删除
	assert(!StackEmpty(ps));
	ps->top--;
}

STDatatype StackTop(ST* ps)
{
	assert(ps);

	assert(!StackEmpty(ps));

	return ps->a[ps->top];
}

bool StackEmpty(ST* ps)
{
	assert(ps);

	return ps->top == -1;
}

int StackSize(ST* ps)
{
	assert(ps);

	return ps->top + 1;
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1 

#include "Stack.h"

void TestST1()
{
	ST st;
	StackInit(&st);

	StackPush(&st, 1);
	StackPush(&st, 2);
	StackPush(&st, 3);
	StackPush(&st, 4);
	StackPush(&st, 5);

	StackPop(&st);
	StackPop(&st);

	printf("%d\n", StackTop(&st));
}

int main()
{
	TestST1();
}

总结

  今天学习了栈的知识,初次写数据结构的知识,给我的感觉就是,学三遍不如手敲代码一遍来的实在,所以数据结构的学习我将多画图,多敲代码来学习,希望大家吸取经验和我一起学习数据结构,为后面打比赛刷题打下坚实基础。

  我是夏目浅石,希望和你一起学习进步,刷题无数!!!希望各位大佬能一键三连支持一下博主,hhhh~我们下期见喽
在这里插入图片描述
如果无聊的话,就来逛逛我的博客栈吧stack-frame.cn

原创不易,还希望各位大佬支持一下 \textcolor{blue}{原创不易,还希望各位大佬支持一下} 原创不易,还希望各位大佬支持一下

👍 点赞,你的认可是我创作的动力! \textcolor{9c81c1}{点赞,你的认可是我创作的动力!} 点赞,你的认可是我创作的动力!

⭐️ 收藏,你的青睐是我努力的方向! \textcolor{ed7976}{收藏,你的青睐是我努力的方向!} 收藏,你的青睐是我努力的方向!

✏️ 评论,你的意见是我进步的财富! \textcolor{98c091}{评论,你的意见是我进步的财富!} 评论,你的意见是我进步的财富!

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

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

相关文章

K8S + GitLab + Jenkins自动化发布项目实践(一)

K8S GitLab Jenkins自动化发布项目实践&#xff08;一&#xff09;发布流程设计安装Docker服务部署Harbor作为镜像仓库部署GitLab作为代码仓库常用Git命令发布流程设计 #mermaid-svg-pe9VmFytb9GmqMvG {font-family:"trebuchet ms",verdana,arial,sans-serif;font-…

微软Bing加入ChatGPT后如何用?教你12种问法黄金公式学会了,又能研究新副业赚钱又能加快学习速度

自从Bing连上chatgpt之后&#xff0c;chatgpt的回答不再像之前那样模棱两可&#xff0c;变得准确起来&#xff0c;至少给出的答案比起往常的会有更多一些的参考价值&#xff0c;也可以帮助大家能够更加深入细节去问问题和梳理问题的流程和解答的方式 当然问法不同得出的答案也是…

不做孔乙己也不做骆驼祥子

对教书育人的探讨前言一、为什么要“育人”1.育人为先2.育人是快乐的二、怎么“育人”前言 借着本次师德师风建设的主题&#xff0c;跟各位老师谈一谈对于“育人”的一些观点&#xff0c;和教育的一些看法。本文仅代表自己的观点&#xff0c;有不到位的地方&#xff0c;大家可以…

Linux虚拟机安装MySQL教程

文章目录一、安装步骤如下一、安装步骤如下 新建文件夹/opt/mysql&#xff0c;并cd进去运行wget http:/dev.mysql.com/get/mysq1-5.7.26-1.el7.x86_64.rpm-bundle.tar&#xff0c;下载mysql安装包 PS: centos7.6自带的类mysql数据库是mariadb&#xff0c;会跟mysql 冲突&…

单片机 | 51单片机原理

【金善愚】 单片机应用原理篇 笔记整理 课程视频 &#xff1a;https://space.bilibili.com/483942191/channel/collectiondetail?sid51090 文章目录一、引脚分布介绍1.分类2.电源引脚3.时钟引脚(2根)4.控制引脚(4根)5.端口引脚(32根)二、存储器结构及空间分布介绍1.存储器的划…

Android 14 新功能之 HighLights:快速实现文本高亮~

日常开发中可能会遇到给 TextView 的全部或部分文本增加高亮效果的需求&#xff0c;以前可能是通过 Spannable 或者 Html 标签实现。 升级 Android 14 后就不用这么迂回了&#xff0c;因其首次引入直接设置高亮的 API&#xff1a;HighLights。需要留意的是 HighLights API 和 …

香橙派5使用NPU加速yolov5的实时视频推理(二)

三、将best.onnx转为RKNN格式 这一步就需要我们进入到Ubuntu20.04系统中了&#xff0c;我的Ubuntu系统中已经下载好了anaconda&#xff0c;使用anaconda的好处就是可以方便的安装一些库&#xff0c;而且还可以利用conda来配置虚拟环境&#xff0c;做到环境与环境之间相互独立。…

STM32开发基础知识入门

C语言基础 位操作 对基本类型变量可以在位级别进行操作。 1) 不改变其他位的值的状况下&#xff0c;对某几个位进行设值。 先对需要设置的位用&操作符进行清零操作&#xff0c;然后用|操作符设值。 2) 移位操作提高代码的可读性。 3) ~取反操作使用技巧 可用于对某…

【UML】软件需求说明书

目录&#x1f981; 故事的开端一. &#x1f981; 引言1.1编写目的1.2背景1.3定义1.4参考资料二. &#x1f981; 任务概述2.1目标2.2用户的特点2.3假定和约束三. &#x1f981; 需求规定3.1 功能性需求3.1.1系统用例图3.1.2用户登录用例3.1.3学员注册用例3.1.4 学员修改个人信息…

基于 PyTorch + LSTM 进行时间序列预测(附完整源码)

时间序列数据&#xff0c;顾名思义是一种随时间变化的数据类型。 例如&#xff0c;24小时内的温度、一个月内各种产品的价格、某家公司一年内的股票价格等。深度学习模型如长短期记忆网络&#xff08;LSTM&#xff09;能够捕捉时间序列数据中的模式&#xff0c;因此可以用于预…

【C/C++】程序的内存开辟

在C/C语言中&#xff0c;不同的类型开辟的空间区域都是不一样的. 这节我们就简单了解下开辟不同的类型内存所存放的区域在哪里. 文章目录栈区&#xff08;stack&#xff09;堆区&#xff08;heap&#xff09;数据段&#xff08;静态区&#xff09;常量存储区内存开辟布局图栈区…

批量保存网页为单个网页文件

有时候&#xff0c;总有会遇到一些奇怪的需求&#xff0c;各种搜索都找不到答案&#xff0c;本次记录批量保存网页到单个网页文件。使用背景&#xff1a;只想简单的解决问题&#xff0c;不涉及编程网页带格式,将网页存为PDF格式会变量太大&#xff0c;一个个的处理太累涉及技术…

《毫无意义的工作》读书思考——互联网中,技术管理岗的价值或作用是什么?

目录 一、背景 二、书中咋说的 三、价值或作用可以从哪些方面思考&#xff1f; 四、写在最后 一、背景 日常工作中&#xff0c;自己经历的、身边人的吐槽&#xff0c;常常会有对纯技术管理者意义的怀疑。工作若干年&#xff0c;遇到各种各样的管理者&#xff0c;但让人吐槽…

【2023年第十一届泰迪杯数据挖掘挑战赛】B题:产品订单的数据分析与需求预测 建模及python代码详解 问题一

相关链接 【2023年第十一届泰迪杯数据挖掘挑战赛】B题&#xff1a;产品订单的数据分析与需求预测 建模及python代码详解 问题一 【2023年第十一届泰迪杯数据挖掘挑战赛】B题&#xff1a;产品订单的数据分析与需求预测 建模及python代码详解 问题二 1 题目 一&#xff0e;问题…

【Linux】进程理解与学习Ⅲ-环境变量

环境&#xff1a;centos7.6&#xff0c;腾讯云服务器Linux文章都放在了专栏&#xff1a;【Linux】欢迎支持订阅&#x1f339;相关文章推荐&#xff1a;【Linux】冯.诺依曼体系结构与操作系统【Linux】进程理解与学习Ⅰ-进程概念浅谈Linux下的shell--BASH【Linux】进程理解与学习…

学习系统编程No.10【文件描述符】

引言&#xff1a; 北京时间&#xff1a;2023/3/25&#xff0c;昨天摆烂一天&#xff0c;今天再次坐牢7小时&#xff0c;难受尽在不言中&#xff0c;并且对于笔试题&#xff0c;还是非常的困难&#xff0c;可能是我做题不够多&#xff0c;也可能是没有好好的总结之前做过的一些…

UE4/5 C++网络服务器编程纪录【零】--准备篇

前言之前利用业余时间重新复习UE4/5的C开发&#xff0c;闲来无事做了个基于独立服务器的多人在线&#xff08;目前限定客户数量是20人以内&#xff09;DEMO&#xff0c;核心功能在我之前发的B站视频里面有&#xff0c;战斗、动作、交互以及场景演示都有了&#xff0c;有朋友看了…

Spring容器实现原理-Spring的结构组成与核心类

Spring容器基本用法 bean是Spring中最核心的东西&#xff0c;因为Spring就像是个大水桶&#xff0c;而bean就像是容器中的水&#xff0c;水桶脱离了水便没有什么用处了&#xff0c;让我们先看看bean的定义&#xff1a; /*** ClassName MyTestBean* Author jiaxinxiao* Date 2…

2021全球开放数据应用创新大赛-法律咨询问答亚军方案

赛题分析 任务&#xff1a;给定用户问题&#xff0c;根据多个候选答案生成回复&#xff0c;属于文本生成任务。 问题信用逾期了&#xff0c;银行打电话骚扰我父母&#xff0c;改如何处理候选答案1. 按照约定还款 2.报警标准回复你好&#xff0c;这种情况只能按照约定还款&…

Python 练习 六

1、(最大数的出现)编写程序读取整数,找出它们中的最大值&#xff0c;然后计算它的出现次数。假设输入以数字0结束。假设你输入的是“352555 0";程序找出的最大数是5&#xff0c;而5的出现次数是4。(提示:维护两个变量max和 count。变量max存储的是当前最大数&#xff0c;而…