当前位置: 首页 > news >正文

【数据结构初阶】手把手带你实现栈

前言

在进入数据结构初阶的学习之后,我们学习了顺序表和链表,当然栈也是一种特殊的数据结构,他的特点是后进先出。


栈的概念及结构

栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

我们切记,此处的栈是数据结构中的栈,与我们操作系统处学习的栈是不同的,它是一个数据存储的位置,而这里的栈是数据存储时的结构,是两个学科中不同的术语。

栈的入数据叫做进栈,压栈或者入栈,出数据时叫做出栈,栈的压栈和出栈都是在栈顶操作的,所以符合后进先出或者先进后出。

我们的生活中就有很多关于栈的示例,比如我们在坐电梯的时候,后上来的人到达目的地之后先出电梯,先上来的人后出电梯。

栈的接口实现

我们在学习完顺序表和链表之后,我们就要考虑顺序表和链表的优劣点来实现栈,我们知道栈的入栈和出栈都是一端,所以可以使用顺序表的尾插和尾删,也可以使用链表的头插头删以及尾插尾删,但是在都可以实现的情况下,我们就要选择消耗最小的顺序表。

(1)定义结构体

typedef int datetype;typedef struct Stack
{datetype* a;int capacity;int top;
}stack;

我们使用typedef定义栈中存储数据的类型,这样方便我们在日后的使用中进行修改,我们将栈的结构定义为一个动态的顺序表,通过a指针来控制,同时记录栈顶的位置,以及最大容量。 

(2)栈的初始化

void stackInit(stack* p)
{assert(p);p->a = NULL;p->capacity = 0;p->top = 0;
}

对p进行断言,能够防止不小心传入NULL后解引用程序崩溃,初始化各个数据。

(3)压栈

void stackPush(stack* p,datetype x)
{assert(p);if (p->capacity == p->top){int newCapacity = p->capacity == 0 ? 4 : 2 * p->capacity;datetype* tmp = (datetype*)realloc(p->a, newCapacity * sizeof(datetype));if (tmp == NULL){perror("realloc");exit(-1);}p->a = tmp;p->capacity = newCapacity;}p->a[p->top] = x;p->top++;
}

同理,对指针p进行断言,判断栈顶是否达到最大容量处,如果没有到达直接将数据插入到top处,并且top自加,如果到了最大容量,我们就对顺序表进行扩容,首先判断容量是否为0,为0时将容量扩到4个数据的字节数,否则容量乘2。

此处的压栈与顺序表的尾插相同。

(4)出栈

void stackPop(stack* p)
{assert(p);assert(!stackEmpty(p));p->top--;
}

 同理对指针进行断言,还需要注意的时需要判断顺序表是否为NULL,如果为空,解引用后程序会崩溃,所以我们选择粗暴的方式进行断言,然后对栈顶减1,不用去处理本来的数据。

(5)判空

bool stackEmpty(stack* p)
{assert(p);return p->top==0;
}

此处我们只想要判断栈顶处是否为0,如果为0则说明顺序表为空,否则顺序表不为空,我们使用了bool类型,C语言中并没有布尔类型,所以我们要引头文件<stdbool.h>。

(6)求栈顶元素

datetype stackTop(stack* p)
{assert(p);assert(!stackEmpty(p));return p->a[p->top-1];
}

断言p以及断言顺序表不为空,返回栈顶的值即可。

(7)求数据个数 

int stackSize(stack* p)
{assert(p);return p->top;
}

(8)销毁栈

void stackDestroy(stack* p)
{assert(p);free(p->a);p->a = NULL;p->capacity = 0;p->top = 0;
}

我们使用malloc,calloc,realloc申请的空间,我们都必须使用free进行销毁。


源码 

stack.h

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
#include<stdbool.h>
#include<stdlib.h>typedef int datetype;typedef struct Stack
{datetype* a;int capacity;int top;
}stack;
//初始化
void stackInit(stack* p);
//销毁
void stackDestroy(stack* p);
//入栈
void stackPush(stack* p, datetype x);
//出栈
void stackPop(stack* p);
//取栈顶数据
datetype stackTop(stack* p);
//数据个数
int stackSize(stack* p);
//判断是否为空
bool stackEmpty(stack* p);

stack.c 

#define _CRT_SECURE_NO_WARNINGS 1
#include"stack.h"
void stackInit(stack* p)
{assert(p);p->a = NULL;p->capacity = 0;p->top = 0;
}
void stackPush(stack* p,datetype x)
{assert(p);if (p->capacity == p->top){int newCapacity = p->capacity == 0 ? 4 : 2 * p->capacity;datetype* tmp = (datetype*)realloc(p->a, newCapacity * sizeof(datetype));if (tmp == NULL){perror("realloc");exit(-1);}p->a = tmp;p->capacity = newCapacity;}p->a[p->top] = x;p->top++;
}void stackPop(stack* p)
{assert(p);assert(!stackEmpty(p));p->top--;
}void stackDestroy(stack* p)
{assert(p);free(p->a);p->a = NULL;p->capacity = 0;p->top = 0;
}datetype stackTop(stack* p)
{assert(p);assert(!stackEmpty(p));return p->a[p->top-1];
}bool stackEmpty(stack* p)
{assert(p);return p->top==0;
}
int stackSize(stack* p)
{assert(p);return p->top;
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"stack.h"
void test()
{stack st;stackInit(&st);stackPush(&st, 1);stackPush(&st, 2);stackPush(&st, 3);stackPush(&st, 4);printf("%d ", stackTop(&st));stackPop(&st);printf("%d ", stackTop(&st));stackPop(&st);stackPush(&st, 5);stackPush(&st, 6);//int ret = stackTop(&st);//printf("%d", ret);while (!stackEmpty(&st)){printf("%d ",stackTop(&st));stackPop(&st);}stackDestroy(&st);}int main()
{test();return 0;
}

通过测试,我们发现无论什么时候出栈,出几个数据,都符合栈的特点,先进后出,后进先出。


总结 

今天我通过顺序表的结构来实现了栈,向展示并讲解了栈的概念、结构与各接口的实现过程与作用原理,当然也可以通过链表的方式来实现,希望大家可以多多尝试。

相关文章:

【数据结构初阶】手把手带你实现栈

前言 在进入数据结构初阶的学习之后&#xff0c;我们学习了顺序表和链表&#xff0c;当然栈也是一种特殊的数据结构&#xff0c;他的特点是后进先出。 栈的概念及结构 栈&#xff08;stack&#xff09;又名堆栈&#xff0c;它是一种运算受限的线性表。限定仅在表尾进行插入和删…...

liunx 端口号开放和关闭

1.先查看防火墙是否开启的状态&#xff0c;以及开放端口的情况&#xff1a; systemctl status firewalld.service(查看防火墙开启还是关闭) sudo firewall-cmd --list-all(可以查看端口开放情况) 2.使用以下命令来开启或者关闭虚拟机的防火墙 systemctl stop firewalld.ser…...

【oracle】问题分析常用查询语句

1、查看当前的数据库连接数 select count(*) from v$process ; --当前的数据库连接数2、数据库允许的最大连接数 select value from v$parameter where name processes; --数据库允许的最大连接数3、查看当前有哪些用户正在使用数据 select osuser, a.username, cpu_time/ex…...

将vue-devtools打包成edge插件

文章目录一、从github拉vue-devtools源码二、用npm安装yarn三、使用yarn安装并编译源码四、将vue-devtools打包成edge插件五、离线安装edge插件一、从github拉vue-devtools源码 目前最新的版本是v6.5.0&#xff0c;地址&#xff1a;https://github.com/vuejs/devtools 二、用n…...

SpringBoot常见面试题汇总(超详细回答)

1.什么是SpringBoot&#xff1f;Spring Boot 是一个基于 Spring 框架的开源框架&#xff0c;用于快速创建独立的、生产级别的、可运行的 Spring 应用程序。它采用了约定优于配置的理念&#xff0c;使开发者可以不需要手动配置大量的 Spring 配置文件&#xff0c;而快速搭建出符…...

上海亚商投顾:沪指窄幅震荡 ChatGPT概念再度走高

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。市场情绪沪指今日窄幅震荡&#xff0c;创业板指低开低走&#xff0c;午后跌幅扩大至1%&#xff0c;宁德时代一度跌近4%。6G概…...

【C语言进阶:指针的进阶】函数指针

本章重点内容&#xff1a; 字符指针指针数组数组指针数组传参和指针传参函数指针函数指针数组指向函数指针数组的指针回调函数指针和数组面试题的解析⚡函数指针 函数指针&#xff1a;指向函数的指针。 通过之前的学习我们知道数组指针中存放的是数组的地址&#xff0c;那么函…...

Sqoop 使用详解

Sqoop 概述Sqoop 是Apache 旗下的一款开源工具&#xff0c;用于Hadoop与关系型数据库之间传送数据&#xff0c;其核心功能有两个&#xff1a;导入数据和导出数据。导入数据是指将MySQL、Oracle等关系型数据库导入Hadoop的HDFS、Hive、HBase等数据存储系统&#xff1b;导出数据是…...

基于MATLAB开发AUTOSAR软件应用层Code mapping专题-part 1 code mapping总体介绍与Function标签页介绍

Hello,大家好,这篇文章开始我们进入一个新的专题,code mapping,即讲解AUTOSAR的元素和哪些模型元素是对应,这也是很多初学的朋友很疑惑的点,最近也有不少粉丝和朋友咨询我,说看了之前的文章基本了解了AUTOSAR有哪些元素()在数据字典的专题里我们逐个讲解过),但是就是…...

第十四节 包、权限修饰符、final、常量

包 1.同一个包下的类&#xff0c;相互可以直接访问。 2.不同包下的类要导包后才能访问。 AIT回车键导包。 权限修饰符 什么是权限修饰符? ●权限修饰符:是用来控制一个成员能够被访问的范围。 ●可以修饰成员变量&#xff0c;方法&#xff0c;构造器&#xff0c;内部类&…...

C++类和对象:初始化列表、static成员和友元

目录 一. 初始化列表 1.1 对象实例化时成员变量的创建及初始化 1.2 初始化列表 1.3 使用初始化列表和在函数体内初始化成员变量的效率比较 1.4 成员变量的初始化顺序 1.5 explicit关键字 二. static成员 2.1 static属性的成员变量 2.2 static属性的成员函数 三. 友元 …...

Windows 11 安装 Docker Desktop

Windows 环境安装 WSL2 WSL 简介 WSL 全称是 Windows Subsystem for Linux &#xff0c;适用于 Linux 的 Windows 子系统&#xff0c;可让开发人员按原样运行 GNU/Linux 环境&#xff0c;包括大多数命令行工具、实用工具和应用程序&#xff0c;且不会产生传统虚拟机或双启动设…...

设计模式-第6章(工厂模式)

工厂模式简单工厂实现工厂模式实现简单工厂 VS 工厂方法商场收银程序再再升级&#xff08;简单工厂策略装饰工厂方法&#xff09;工厂方法模式总结简单工厂实现 在简单工厂类中&#xff0c;通过不同的运算符&#xff0c;创建具体的运算类。 public class OperationFactory {pu…...

【JAVA】线程和进程

&#x1f3c6;今日学习目标&#xff1a;线程和进程 &#x1f603;创作者&#xff1a;颜颜yan_ ✨个人主页&#xff1a;颜颜yan_的个人主页 ⏰本期期数&#xff1a;第三期 &#x1f389;专栏系列&#xff1a;JAVA 线程和进程前言一、进程与线程1.进程2.线程二、线程的创建2.1 继…...

移动app安全测试工具好物分享

移动互联网时代&#xff0c;我们的生活和工作深受移动app的影响。随着移动app的广泛应用&#xff0c;安全问题成为人们最关注的话题之一。移动app安全除了和软件开发密不可分之外&#xff0c;软件测试的作用也是不容忽视的。移动app安全测试是指测试人员利用各种测试手段验证Ap…...

原生微信小程序引入npm和安装Vant Weapp

目录一、引入npm安装Vant Weapp1、引入npm2、安装Vant Weapp3、修改 app.json4、修改 project.config.json二、构建npm一、引入npm安装Vant Weapp 环境&#xff1a;Windows10 开发工具&#xff1a;微信开发者工具 本地环境&#xff1a;已安装过node.js 1、引入npm cmd进入到你…...

ChatGPT文章自动发布WordPress

WordPress可以用ChatGPT发文章吗&#xff1f;答案是肯定的&#xff0c;ChatGPT官方有提供api接口&#xff0c;多以目前有很多的SEO工具具有自动文章生成自动发布的功能&#xff0c;使用SEO工具&#xff0c;我们可以通过疑问词和关键词进行文章生成&#xff0c;并定时发布到我们…...

vue项目使用watch监听器监听数据变化

vue项目使用watch监听器监听数据变化 1.概述 在开发项目中&#xff0c;有些场景是当用户点击某个按钮后改变某个属性的值&#xff0c;这个值改变时需要触发事件做一些事情。属性值什么时候改变是没法提前判断的&#xff0c;因此需要有个监听的角色&#xff0c;当监听到值改变…...

动态规划(背包问题)

动态规划 文章目录动态规划一、背包问题一、01背包二、完全背包问题三、多重背包问题四、分组背包问题一、背包问题 一、01背包 有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。 第 i 件物品的体积是 vi&#xff0c;价值是 wi。 求解将哪些物品装入背包&#xf…...

04741自考计算机网络原理最详细汇总

04741自考计算机网络原理知识点总结 引言 第一章 计算机网络概述 1.计算机网络基本概念与网络结构 1.1 计算机网络的概念; 1.2 计算机网络结构 1.3 数据交换技术 1.4 计算机网络性能 1.5 计算机网络体系结构 1.6 计算机网络与因特网发展简史 第二章 网络应用 2.1 网络应用体系…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)

说明&#xff1a; 想象一下&#xff0c;你正在用eNSP搭建一个虚拟的网络世界&#xff0c;里面有虚拟的路由器、交换机、电脑&#xff08;PC&#xff09;等等。这些设备都在你的电脑里面“运行”&#xff0c;它们之间可以互相通信&#xff0c;就像一个封闭的小王国。 但是&#…...

【Python】 -- 趣味代码 - 小恐龙游戏

文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

C++:std::is_convertible

C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】

微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来&#xff0c;Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

【生成模型】视频生成论文调研

工作清单 上游应用方向&#xff1a;控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

C# 表达式和运算符(求值顺序)

求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如&#xff0c;已知表达式3*52&#xff0c;依照子表达式的求值顺序&#xff0c;有两种可能的结果&#xff0c;如图9-3所示。 如果乘法先执行&#xff0c;结果是17。如果5…...