数据结构之栈的超详细讲解

news2025/1/10 11:37:40

目录

引言

一.栈的概念

二.栈的结构

三.栈的实现

栈结构的实现

栈操作函数的声明

栈中方法的实现

栈的初始化

栈的销毁

入栈

出栈

取栈顶元素

判断栈中是否为空

获取栈中数据个数

四.测试 

代码展示:

结构展示:

五.小结

六.完整代码

Stack.h

Stack.c

text.c


引言

这个专题是专门对栈进行详细的讲解,栈这个数据结构其实和之前的顺序表和单链表一样,同样是线性结构,但它的限制更大,如果想看之前单链表和顺序表数据结构的实现,或者是之后的数据结构我现在还没出的,都可以订阅我这个数据结构初阶的专栏--http://t.csdnimg.cn/sz4xS.好了,话不多说,点赞关注我们开始!

一.栈的概念

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

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

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

栈这个数据结构可以总结为四个字:后进先出

二.栈的结构

因为栈也是一种线性结构,所以并不复杂,如下图所示:

栈这种结构在我们生活中其实并不少见,比如我们打羽毛球用的羽毛球桶,装子弹的弹匣,都满足后进先出的一个特性. 

三.栈的实现

栈结构的实现

我们可以用三种方法实现栈这个结构:

方法一:

我们用双向链表构建栈,如下图所示:

这样做的好处是:双向链表能很轻松的寻找前面的节点

方法二:

我们用单链表构建栈,如下图所示:

我们用单链表构建栈时,我们入栈时需要头插,因为单链表找前面的节点是不好找的

方法三:

我们用动态数组构建栈:

这个方法就类似于基于动态数组构建顺序表

那么这三种方法选择哪一种呢?

首先因为单链表的原因,我们先把双向链表PASS掉

接下来就在单链表和动态数组中选择

其实两者相差不大,但由于动态数组具有元素高效率存储,所以这里选择动态数组实现栈

代码展示:

//栈的结构
typedef int STDataType;

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

 注意:这里的STDataType和之前的链表和顺序表一样,方便后面进行类型的替换

a时我们的动态数组

top是我们的栈顶指针

capacity是我们的空间容量

栈操作函数的声明

对于线性表来说,操作函数大同小异,所以栈的操作函数其实跟单链表和顺序表差不多

下面便是操作函数的声明:

//函数的声明
//初始化和销毁
void STInit(ST* pst);
void STDestory(ST* pst);
//入栈和出栈
void STPush(ST* pst, STDataType x);
void STPop(ST* pst);
//取栈顶元素
STDataType STTop(ST* pst);
//判空
bool STEmpty(ST* pst);
//获取数据个数
int STSize(ST* pst);

栈中方法的实现

栈的初始化

注意:

栈这里的初始化分为两种方式:

1.top指向-1,top指向栈顶元素,如下图所示:

注意:这里的top不能指向为0,因为这样的话,当top指为0时,不知道是否含有数据

2.top指向0,top指向栈顶元素的下一位,如下图所示:

这里我用了第二种,因为这里的top即为元素个数,对于后面的操作会方便一点.

//初始化和销毁
void STInit(ST* pst)
{
	assert(pst);
	pst->a = NULL;
	//top指向栈顶数据的下一个位置
	pst->top = 0;

	//top指向栈顶数据
	//pst->top = -1;
	pst->capacity = 0;
}

栈的销毁

void STDestory(ST* pst)
{
	assert(pst);

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

注意最后要将top和capacity置为0

入栈

和顺序表的插入数据类似,首先进行断言处理,再看空间是否够用,不够用就进行两倍扩容.

注意:这里使用了三目操作符,因为我们初始化capacity为0,两倍扩容之后还是为0,所以当它为0时,直接初始化为4,或者其他值.

void STPush(ST* pst, STDataType x)
{
	assert(pst);
	//扩容
	if (pst->top == pst->capacity)
	{
		int newcapcacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(pst->a, newcapcacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			return;
		}
		pst->a = tmp;
		pst->capacity = newcapcacity;
	}
	pst->a[pst->top] = x;
	pst->top++;
}

出栈

这个很简单,只需top--即可

void STPop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);
	pst->top--;
}

取栈顶元素

注意:这里需要额外对top进行判空处理

//取栈顶元素
STDataType STTop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);

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

判断栈中是否为空

top即为我们栈中元素的个数

//判空
bool STEmpty(ST* pst)
{
	assert(pst);

	return pst->top == 0;
}

获取栈中数据个数

//获取数据个数
int STSize(ST* pst)
{
	assert(pst);

	return pst->top;
}

四.测试 

我们入栈一些元素,再将它们打印出来.

代码展示:

#include "Stack.h"

int main()
{
	ST s;
	STInit(&s);
	STPush(&s, 1);
	STPush(&s, 2);
	STPush(&s, 3);
	STPush(&s, 4);
	//遍历栈中的元素
	while (!STEmpty(&s))
	{
		printf("%d ", STTop(&s));
		STPop(&s);
	}

}

结构展示:

后进先出没有问题

五.小结

栈这个数据结构对比顺序表和单链表的实现真的简单了不少,但它的OJ题可不简单,后面我会更新关于栈的经典OJ练习,如果觉得这篇博客对你有帮助的话,一定要点赞关注哦!如果你有任何问题后可以打在评论区,大家一起学习,共同进步!

六.完整代码

Stack.h

#pragma once
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
//栈的结构
typedef int STDataType;

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

//函数的声明
//初始化和销毁
void STInit(ST* pst);
void STDestory(ST* pst);
//入栈和出栈
void STPush(ST* pst, STDataType x);
void STPop(ST* pst);
//取栈顶元素
STDataType STTop(ST* pst);
//判空
bool STEmpty(ST* pst);
//获取数据个数
int STSize(ST* pst);

Stack.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "Stack.h"

//初始化和销毁
void STInit(ST* pst)
{
	assert(pst);
	pst->a = NULL;
	//top指向栈顶数据的下一个位置
	pst->top = 0;

	//top指向栈顶数据
	//pst->top = -1;
	pst->capacity = 0;
}
void STDestory(ST* pst)
{
	assert(pst);

	free(pst->a);
	pst->a = NULL;
	pst->top = pst->capacity = 0;
}
//入栈和出栈
void STPush(ST* pst, STDataType x)
{
	assert(pst);
	//扩容
	if (pst->top == pst->capacity)
	{
		int newcapcacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(pst->a, newcapcacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			return;
		}
		pst->a = tmp;
		pst->capacity = newcapcacity;
	}
	pst->a[pst->top] = x;
	pst->top++;
}
void STPop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);
	pst->top--;
}
//取栈顶元素
STDataType STTop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);

	return pst->a[pst->top - 1];
}
//判空
bool STEmpty(ST* pst)
{
	assert(pst);

	return pst->top == 0;
}
//获取数据个数
int STSize(ST* pst)
{
	assert(pst);

	return pst->top;
}

text.c

#include "Stack.h"

int main()
{
	ST s;
	STInit(&s);
	STPush(&s, 1);
	STPush(&s, 2);
	STPush(&s, 3);
	STPush(&s, 4);
	//遍历栈中的元素
	while (!STEmpty(&s))
	{
		printf("%d ", STTop(&s));
		STPop(&s);
	}

}

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

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

相关文章

看Diffusion模型如何提升端到端自动驾驶的能力

文章链接&#xff1a;https://openreview.net/pdf?idyaXYQinjOA 自动驾驶领域在分割和规划模型性能方面取得了显著进展&#xff0c;这得益于大量数据集和创新的架构。然而&#xff0c;这些模型在遇到罕见子群&#xff0c;比如雨天条件时&#xff0c;往往表现不佳。获取必要的…

编程入门(六)【Linux系统基础操作二】

读者大大们好呀&#xff01;&#xff01;!☀️☀️☀️ &#x1f525; 欢迎来到我的博客 &#x1f440;期待大大的关注哦❗️❗️❗️ &#x1f680;欢迎收看我的主页文章➡️寻至善的主页 文章目录 &#x1f525;前言&#x1f680;文件与目录的操作命令cd change directory的缩…

RSA理解版本2

RSA原理理解 起源&#xff1a; RSA是一种公钥密码算法&#xff0c;它的名字是由它的三位开发者&#xff0c;即Ron Rivest、Adi Shamir 和 Leonard Adleman 的姓氏的首字母组成的。 简介&#xff1a; RSA加密算法是一种非对称加密算法&#xff0c;在公开密钥加密和电子商业中…

JWK和JWT 学习

JWK和JWT 介绍 JWK (JSON Web Key) 和 JWT (JSON Web Token) 是现代Web应用程序中用于安全通信的两个重要概念。它们都是基于JSON的&#xff0c;并且是OAuth 2.0和OpenID Connect等协议的核心组成部分。 官方文档 JWT官方网站 JWK和JWK Set的RFC文档 JWT的RFC文档 JWK (JS…

linux内核网络源码--通知链

内核的很多子系统之间有很强的依赖性&#xff0c;其中一个子系统侦测到或者产生的事件&#xff0c;其他子系统可能都有兴趣&#xff0c;为了实现这种交互需求&#xff0c;linux使用了所谓的通知链。 本章我们将看到 通知链如何声明以及网络代码定义了哪些链 内核子系统如何向通…

Qt | QLCDNumber 类(LCD 数字),LCD 表示液晶显示屏

01、上节回顾 Qt 基础教程合集02、QLCDNumber 1、QLCDNumber 类用于显示类似于 LCD 显示屏上的字符(见右图) ​ 2、QLCDNumber 类是 QFrame 类的直接子类,因此 QLCDNumber 以使用从 QFrame 类继承而来的边框效果 3、QLCDNumber 可显示的符号有:0,1,2,3,4,5,6,7,8,…

Docker——consul的容器服务更新与发现

一、什么是服务注册与发现 服务注册与发现是微服务架构中不可或缺的重要组件。起初服务都是单节点的&#xff0c;不保障高可用性&#xff0c;也不考虑服务的压力承载&#xff0c;服务之间调用单纯的通过接口访问。直到后来出现了多个节点的分布式架构&#xff0c;起初的解决手段…

OceanBase 如何实现多层面的资源隔离

OceanBase的资源隔离涵盖了多个方面&#xff0c;如物理机器间的隔离、不同租户之间的隔离、同一租户内的隔离&#xff0c;以及针对大型查询请求的隔离等。在实际应用OceanBase的过程中&#xff0c;我们经常会遇到这些操作场景或产生相关需求。这篇文章针对这些内容进行了简要的…

数据库系统原理实验报告5 | 数据查询

整理自博主本科《数据库系统原理》专业课自己完成的实验报告&#xff0c;以便各位学习数据库系统概论的小伙伴们参考、学习。 专业课本&#xff1a; ———— 本次实验使用到的图形化工具&#xff1a;Heidisql 目录 一、实验目的 二、实验内容 1.找出读者所在城市是“shangh…

垂起固定翼+多旋翼无人机+集群组网:高低空域协同组网通信技术详解

垂起固定翼、多旋翼无人机与自组网的结合&#xff0c;为高低空域协同组网通信技术提供了创新的解决方案。这种结合充分利用了各种技术的优势&#xff0c;使得无人机在高低空域中的协同作业和通信更加高效和灵活。 首先&#xff0c;垂起固定翼无人机以其垂直起降能力和长航时的…

第28章-PPPoE

1. 以太网接入的典型应用 1.1. IP技术的应用与发展 1.2. 以太网接入的典型应用场景之一——大型园区接入的典型应用 2. PPPoE技术的基本原理 2.1. 技术背景 2.2. PPPoE工作原理 2.3. PPPoE的两个阶段&#xff1a;Discovery阶段和PPPSession阶段 2.4. PPPoE的帧结构 2.5. PPPoE…

如何高效封装App?小猪APP分发平台一站式解决方案

在移动应用开发领域&#xff0c;App封装&#xff08;App Packaging&#xff09;是一个至关重要的环节&#xff0c;它不仅关乎应用的安全性&#xff0c;还直接影响到最终用户体验和市场推广策略。本文旨在通过实战指南&#xff0c;揭示如何高效完成App封装&#xff0c;并介绍如何…

python爬虫(二) 之 42号网汽车文章爬虫

python爬虫&#xff08;二&#xff09; 之 42号网汽车文章爬虫 今天在咸鱼上有个买家找我一个42号网汽车文章的爬虫&#xff0c;目前需求已经做完了&#xff0c;现在将这部分代码开源&#xff0c;供大家参考。爬虫能够抓取到网站上所有文章的数据&#xff0c;大概一小时左右就…

buuctf[pwn]

buuctf[PWN] 题目&#xff1a;rip(栈对齐) 知识点&#xff1a;栈对齐 题目地址&#xff1a;BUUCTF在线评测 (buuoj.cn)知识点&#xff1a;64位ubuntu18以上系统调用system函数时需要栈对齐&#xff0c;因为64位下的system函数有个movaps指令&#xff0c;这个指令要求内存地址…

​《MATLAB科研绘图与学术图表绘制从入门到精通》示例:绘制德国每日风能和太阳能产量3D线图

在MATLAB中&#xff0c;要绘制3D线图&#xff0c;可以使用 plot3 函数。 在《MATLAB科研绘图与学术图表绘制从入门到精通》书中通过绘制德国每日风能和太阳能产量3D线图解释了如何在MATLAB中绘制3D线图。 购书地址&#xff1a;https://item.jd.com/14102657.html

读天才与算法:人脑与AI的数学思维笔记20_数学图灵测试

1. 数学图灵测试 1.1. 能不能将这种计算机证明语言翻译成易于与人交流的方式呢&#xff1f; 1.1.1. 剑桥大学的两位数学家蒂莫西高尔斯&#xff08;Timothy Gowers&#xff09;和莫汉加内萨林加姆&#xff08;Mohan Ganesalingam&#xff09;开展了此项研究 1.1.1.1. 他们决…

已解决SyntaxError: EOL while scanning string literal 亲测有效!!!

已解决SyntaxError: EOL while scanning string literal 亲测有效&#xff01;&#xff01;&#xff01; 亲测有效 报错问题解决思路解决方法 报错问题 SyntaxError: EOL while scanning string literal 这个错误通常发生在Python代码中&#xff0c;表示字符串字面量没有被正确…

撸爆公众号流量主,简单无脑,单日变现2000+

详情介绍 目前公众号流量主的收益非常的好&#xff0c;不管你是小白还是老鸟&#xff0c;都能拿到一个很好的收益&#xff0c;轻轻松松日入2000&#xff0c;接下来我给大家带来一个保姆级的教学&#xff0c;大家跟着操作就可以了

360手机去除广告 360手机关闭弹窗广告 360手机刷机

360手机去除广告 360手机关闭弹窗广告 360手机刷机 360手机去广告 360手机刷机 360手机弹窗广告 永久去除360手机的各种广告教程 360手机禁止更新 360手机关闭广告 360手机去除内部广告 360手机资源网 360手机刷机资源下载链接&#xff1a;360rom.github.io 参考&#xff1a;…

C语言/数据结构——每日一题(链表的中间节点)

一.前言 今天我在LeetCode刷到了一道单链表题&#xff0c;想着和大家分享一下这道题&#xff1a;https://leetcode.cn/problems/middle-of-the-linked-list。废话不多说让我们开始今天的知识分享吧。 二.正文 1.1题目描述 1.2题目分析 这道题有一个非常简便的方法——快慢指…