【数据结构】栈

1.58.33

    • 栈的概念及基本结构
    • 栈的存储
    • 栈的基本操作
      • 栈的置空初始化---StackInit()
      • 栈的初始化2.0---给栈开辟一点空间StackInit1()
      • 栈的销毁---StackDestory()
      • 入栈----StackPush()
      • 出栈----StackPop()
      • 获取栈中元素的数量---StackSize()
      • 判断栈是否为空---StackEmpty()
      • 获取栈顶元素---StackTop
      • 栈元素的遍历
    • 程序的运行
      • 头文件---stack.h
      • 源文件编写函数---stack.c
      • 源文件编写--在主函数中运行 test.c
      • 运行结果
  • 栈的应用---括号的匹配
    • 题目---Leetcode20.有效的括号
    • 举例认识---有效的括号
    • 找出规律

栈的概念及基本结构

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

栈的存储

栈的存储方式有两种:顺序栈链栈,即栈的顺序存储和链式存储。

采用顺序存储的栈称为顺序栈,它利用一组地址连续的存储单元存放自栈底到栈顶的元素,同时附设一个指针(top)指示当前栈顶的位置。

对于栈数据结构,采用顺序栈更方便进行压栈尤其是出栈,所以本次主要说明利用顺序栈来实现栈的基本操作。

同时这里,利用一组地址连续的存储单元进行存放,同顺序表的存储一样,分为静态存储动态存储

在静态存储中,即利用宏定义给定一个顺序表的大小,对于后续操作,尤其是入栈,如果入若干次栈,而由于顺序表的内存空间有限,那么就会直接报错而无法进行后续操作。

在动态存储中,就比较灵活了,正好可以解决这个问题。在动态存储中,我们利用定义的指针在堆上开辟一块内存空间,若空间大小不够,我们可以进行扩容操作。但同时我们动态存储时,也要注意,在栈操作最后要注意堆上内存空间的释放。

typedef int datatype;
typedef struct Stack
{datatype *a;int top;int capacity;
}Stack;

可以形象地来理解以下:

栈的基本操作

栈的置空初始化—StackInit()

void StackInit(Stack *ps)
{assert(ps);ps->a=NULL;ps->top=0;ps->capacity=0;
}

这里用到了assert函数,下面几乎每个函数也都会用到。在这里简单说明一下这个函数。
assert函数即断言函数,“断言”在语文中的意思是“断定”、“十分肯定地说”,在编程中是指对某种假设条件进行检测,如果条件成立就不进行任何操作,如果条件不成立就捕捉到这种错误,并打印出错误信息,终止程序执行
所在头文件:<assert.h>
函数原型:void assert (int expression);
参数:expression即要检测的表达式
返回值:无返回值

如果expression的结果为 0(条件不成立),那么断言失败,表明程序出错,assert() 会向标准输出设备(一般是显示器)打印一条错误信息,并调用 abort() 函数终止程序的执行。
assert()函数相比于return ,更加直接‘暴力“,如果条件不成立,那么程序就将终止。
如果expression的结果为非 0(条件成立),那么断言成功,表明程序正确,assert() 不进行任何操作。

在这里,我们对传入的指针进行断言,如果为空指针,那么程序终止退出程序,若不为空指针,那么不进行任何的操作,程序继续往下执行。

栈的初始化2.0—给栈开辟一点空间StackInit1()

void StackInit1(Stack *ps)
{assert(ps);ps->a=(datatype *)malloc(sizeof(Stack)*4);//开辟4个空间ps->capacity=4;
}

栈的销毁—StackDestory()

因为malloc函数是在堆上开辟的内存空间,而对于堆上的内存空间比较灵活,系统不会自动释放,而需要我们手动释放,所以在一个函数中既然开辟了栈,那就一定要记得最后销毁。

void StackDestory()
{assert(ps);free(p->a);ps->a=NULL;ps->top=ps->capacity=0;
}

入栈----StackPush()

void StackPush(Stack *ps,datatype x)
{assert(ps);//判断栈的空间是否已满if(ps->top==ps->capacity){//扩容为原容量的2倍datatype *tmp=(datatype *)relloc(ps->a,sizeof(Stack)*capacity*2);ps->capacity=ps->capacity*2;}ps->a[ps->top]=x;ps->top++;
}

出栈----StackPop()

void StackPop(Stack *ps)
{assert(ps);//判断当前栈是否为空,若空则无法出栈,退出程序assert(ps->top >0);ps->top--;
}

获取栈中元素的数量—StackSize()

int StackSize(Stack *ps)
{assert(ps);return ps->top;
}

判断栈是否为空—StackEmpty()

bool StackEmpty()
{assert(ps);//若ps->top==0,为真,则返回True;若ps->top!=0,为假,则返回Falsereturn ps->top == 0;
}

获取栈顶元素—StackTop

datatype StackTop(Stack *ps)
{assert(ps);//判断栈是否为空assert(ps->top>0);return ps->a[ps->top - 1];    
}

栈元素的遍历

栈结构的特点是,后进先出,即后进的元素先进行遍历。所以我们就需要出栈,也就是逐渐删除栈顶元素进行遍历。
首先,我们先在测试函数中创立一个栈:

void TestStack()
{Stack s;StackInit(&s);StackInit1(&s);StackPush(&s,1);StackPush(&s,2);StackPush(&s,3);StackPush(&s,4);StackPush(&s,4);StackDestory(&s);
}

然后,我们一次删除栈顶元素,进行栈的遍历:

void TestStack()
{Stack s;StackInit(&s);StackInit1(&s);StackPush(&s,1);StackPush(&s,2);StackPush(&s,3);StackPush(&s,4);StackPush(&s,4);while(ps->top){printf("%d",StackTop(&s));StackPop();}printf("\n");StackDestory(&s);
}

程序的运行

头文件—stack.h

#pragma once
#define _CER_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>   //malloc函数
#include <assert.h>    //assert函数
#include <stdbool.h>   //bool类型typedef int datatype;
typedef struct Stack
{datatype* a;int top;int capacity;
}Stack;void StackInit(Stack* ps); //置空
void StackInit1(Stack* ps);  //初始化
void StackDestory(Stack* ps);   //销毁
void StackPush(Stack* ps, datatype x); //入栈
void StackPop(Stack* ps);//出栈
int StackSize(Stack* ps); //获取栈中元素的多少
bool StackEmpty(Stack* ps); //判断是否栈空
datatype StackTop(Stack* ps);//获取栈顶元素

源文件编写函数—stack.c

#include "stack.h"//栈置空
void StackInit(Stack* ps)
{assert(ps);ps->a = NULL;ps->top = 0;ps->capacity = 0;
}//栈初始化
void StackInit1(Stack* ps)
{assert(ps);ps->a = (datatype*)malloc(sizeof(Stack) * 4);//开辟4个空间ps->capacity = 4;
}//栈的销毁
void StackDestory(Stack *ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->top = ps->capacity = 0;
}//入栈
void StackPush(Stack* ps, datatype x)
{assert(ps);//判断栈的空间是否已满if (ps->top == ps->capacity){//扩容为原容量的2倍datatype* tmp = (datatype*)realloc(ps->a, sizeof(Stack) * ps->capacity * 2);ps->capacity = ps->capacity * 2;}ps->a[ps->top] = x;ps->top++;
}//出栈
void StackPop(Stack* ps)
{assert(ps);//判断当前栈是否为空,若空则无法出栈,退出程序assert(ps->top > 0);ps->top--;
}//获取栈中元素的数量
int StackSize(Stack* ps)
{assert(ps);return ps->top;
}//判断栈是否为空
bool StackEmpty(Stack *ps)
{assert(ps);//若ps->top==0,为真,则返回True;若ps->top!=0,为假,则返回Falsereturn ps->top == 0;
}//获取栈顶元素
datatype StackTop(Stack* ps)
{assert(ps);//判断栈是否为空assert(ps->top > 0);return ps->a[ps->top - 1];
}

源文件编写–在主函数中运行 test.c


#include "stack.h"
//测试函数的编写---栈元素的遍历
void TestStack()
{Stack s;StackInit(&s);StackInit1(&s);StackPush(&s, 1);StackPush(&s, 2);StackPush(&s, 3);StackPush(&s, 4);StackPush(&s, 5);while (( & s)->top){printf("%d", StackTop(&s));StackPop(&s);}printf("\n");StackDestory(&s);
}
//主函数
int main()
{TestStack();return 0;
}

运行结果

栈的应用—括号的匹配

题目—Leetcode20.有效的括号



举例认识—有效的括号

以下面这个例子为例:

我们自左往右进行扫描字符串:
一旦所扫描的是左括号,我们先自动略过,等待匹配
一旦出现右括号,我们会和离它最近的并且未被匹配的左括号进行匹配。如果匹配完成,我们就不需要再考虑这个左括号了。
扫描过程如下:

找出规律

我们会发现先出现的左括号后匹配
因此,进行模式识别,先进后出 ,运用栈结构。
所以,我们可以把左括号加入栈,匹配的过程就是出栈的过程。

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

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

相关文章

自动化测试系列 —— UI自动化测试

UI 测试是一种测试类型&#xff0c;也称为用户界面测试&#xff0c;通过该测试&#xff0c;我们检查应用程序的界面是否工作正常或是否存在任何妨碍用户行为且不符合书面规格的 BUG。了解用户将如何在用户和网站之间进行交互以执行 UI 测试至关重要&#xff0c;通过执行 UI 测试…

值得学习的演示文稿制作范例

1,在第一张幻灯片前插入1张新幻灯片,设置幻灯片大小为“全屏显示(16:9) ”;为整个演示文稿应用“离子会议室”主题,放映方式为“观众自行浏览”;除了标1题幻灯片外其它每张幻灯片中的页脚插入“晶泰来水晶吊坠”七个字。 2,第一张幻灯片的版式设置为“标题幻灯片”,主标题为“…

音视频技术在手机上的应用与挑战

// 编者按&#xff1a;随着手机相机功能日益强大&#xff0c;4k&#xff0c;8k&#xff0c;各类特色短视频的拍摄&#xff0c;编辑、播放需求日益增长&#xff0c;短视频应用的火爆也对当前的手机音视频技术提出了更高的要求&#xff0c;如何更好地提高用户体验成为了行业共同…

蓝桥杯 大小写转换

islower/isupper函数 islower和issupper是C标准库中的字符分类函数&#xff0c;用于检查一个字符是否为小写字母或大写字母 需要头文件< cctype>,也可用万能头包含 函数的返回值为bool类型 char ch1A; char ch2b; //使用islower函数判断字符是否为小写字母 if(islower(…

SpringMVC 进阶

SpringMVC 进阶 一、拦截器 SpringMVC 中 Interceptor 拦截器的主要作⽤是拦截⽤⼾的请求并进⾏相应的处理。⽐如通过它来进⾏权限验证&#xff0c;或者是来判断⽤⼾是否登陆等操作。对于 SpringMVC 拦截器的定义⽅式有两种&#xff1a; 实现接⼝&#xff1a;org.springfram…

如何在3DMax中使用超过16个材质ID通道?

3DMAX效果通道扩展插件EffectsChannelEx教程 3DMax的材质ID通道允许我们生成渲染元素&#xff0c;这些元素可用于在合成或其他软件中产生处理或特殊效果。如对渲染或动画进行颜色校正。你可以在Photoshop中为你的静态3D渲染图像做这件事。或者使用After Effects、Blackmagic Fu…

竞赛选题 目标检测-行人车辆检测流量计数

文章目录 前言1\. 目标检测概况1.1 什么是目标检测&#xff1f;1.2 发展阶段 2\. 行人检测2.1 行人检测简介2.2 行人检测技术难点2.3 行人检测实现效果2.4 关键代码-训练过程 最后 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 行人车辆目标检测计数系统 …

JAVA小游戏 “拼图”

第一步是创建项目 项目名自拟 第二部创建个包名 来规范class 然后是创建类 创建一个代码类 和一个运行类 代码如下&#xff1a; package heima;import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import jav…

企业微信机器人定时发送图文信息,后续无需人工操作

企业微信群机器人是企业微信的内置功能&#xff0c;可以理解为是一个群提醒通知工具&#xff0c;接收数据并自动发送信息到企业微信群中。 数环通实现打通定时器和企业微信机器人的对接&#xff0c;定时执行自动化流程&#xff0c;无需人工干预&#xff0c;实现工作流程自动化&…

【EI会议征稿】2024年电气技术与自动化工程国际学术会议 (ETAE 2024)

2024年电气技术与自动化工程国际学术会议 (ETAE 2024) 2024 International Conference on Electrical Technology and Automation Engineering 2024年电气技术与自动化工程国际学术会议 (ETAE 2024) 将于2024年3月8-10日在中国杭州召开。电气工程及其自动化和人们的日常生活…

电磁场与电磁波part5--均匀平面波在无界空间的传播

目录 1、相位速度 2、波阻抗 3、理想介质中均匀平面波的传播特点 4、色散现象 5、导电媒质中均匀平面波的传播特点 6、趋肤效应 7、电磁波的极化 1、相位速度 电磁波的等相位面在空间中的移动速度&#xff08;相速&#xff09; 在自由空间&#xff08;自由空间的光速&a…

SpringBoot——入门及原理

SpringBoot用来简化Spring应用开发&#xff0c;约定大于配置&#xff0c;去繁从简&#xff0c;是由Pivotal团队提供的全新框架。其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置&#xff08;有特殊需求可以添加自己的配置覆盖默认配…

linux上交叉编译qt库

linux上交叉编译qt库 Qt程序从X86平台Linux移植到ARM平台Linux需要做什么 1.在ubuntu上使用qt的源码交叉编译出Qt库 2.将编译好的库拷贝到开发板上并设置相应的环境变量&#xff08;库路径啥的&#xff09; 前两步一劳永逸&#xff0c;做一次就行 3.X86上写好程序代码&…

浅谈多回路电表在荷兰光伏系统配电项目中的应用

1.背景信息 Background&#xff1a; 随着全球化石能源&#xff08;石油&#xff0c;煤炭&#xff09;越来越接近枯竭&#xff0c;污染日趋严重&#xff0c;气候日益变暖等问题&#xff0c;全球多个国家和地区相继出台了法规政策&#xff0c;推动了光伏产业的发展。但是现有的光…

UE5 - ArchvizExplorer - 数字孪生城市模板 - 功能修改

数字孪生项目&#xff0c;大多是双屏互动&#xff0c;而非下方菜单点击&#xff0c;所以要做一番改造 参考&#xff1a;https://blog.csdn.net/qq_17523181/article/details/133853099 1. 去掉提示框 打开BP_MasterMenu_Widget&#xff0c;进入EventGraph&#xff0c;断开Open…

给折腿的罗技G512键盘换键帽

文章目录 1\. 引言2\. 操作2.1. 用打火机烤2.2. 用钳子拔出来2.2.1. 拔出成功2.2.2. 放大细看2.3. 更换键帽 1. 引言 G512的轴采用的是塑料连接&#xff0c;特别容易腿折在里面&#xff0c;换着的时候&#xff0c;得先把这个卡在里面的塑料腿拿出来才行 放大效果图 2. 操作 可…

Spring Boot中使用Redis进行大数据缓存

Spring Boot中使用Redis进行大数据缓存 在Spring Boot中使用Redis进行大数据缓存是一种常见的做法&#xff0c;因为Redis是一种高性能的内存数据库&#xff0c;适用于缓存大量数据。以下是说明和示例代码&#xff0c;演示如何在Spring Boot项目中使用Redis进行大数据缓存。 步…

龙讯旷腾PWmat发PRL:多k点计算的NAMD方法应用于小型超胞与在等效的大型超胞中进行的单个Γ点模拟之间的一致性

文章信息 作者信息&#xff1a;郑帆&#xff0c;汪林望 通信单位&#xff1a;上海科技大学 中国科学院半导体所 背景导读 固态材料中的超快载流子动力学在能源材料、光电子学、传感器和量子材料等领域起着关键作用。随着超快实验技术在固态系统中载流子动力学研究中的快速发…

纯CSS动态渐变文本特效

如图所示&#xff0c;这是一个炫酷的文本渐变效果&#xff0c;如同冰岛的极光一般。本次的文章让我们逐步分解代码&#xff0c;了解其实现原理。 基于以上动图效果可以分析以下是本次动效实现的主要几点&#xff1a; 文本中有多个颜色的动画每个颜色显示的半径不同&#xff0…

MCU内存基础知识

文章目录 一、存储器分类二、C语言内存分区内存区三、STM32启动文件分析四、应用分析 一、存储器分类 RAM&#xff08;Random Access Memory) &#xff1a;掉电之后就丢失数据&#xff0c;读写速度块 ROM (Read Only Memory) &#xff1a;掉电之后仍然可以保持数据 单片机的RA…