搜索
查看
编辑修改
首页
UNITY
NODEJS
PYTHON
AI
GIT
PHP
GO
CEF3
JAVA
HTML
CSS
搜索
黑客灵魂
这个屌丝很懒,什么也没留下!
关注作者
热门标签
jquery
HTML
CSS
PHP
ASP
PYTHON
GO
AI
C
C++
C#
PHOTOSHOP
UNITY
iOS
android
vue
xml
爬虫
SEO
LINUX
WINDOWS
JAVA
MFC
CEF3
CAD
NODEJS
GIT
Pyppeteer
article
热门文章
1
1 Introduction to Oracle Clusterware Oracle集群软件介绍_单机库clusterware not configuration
2
Node.js安装及环境配置(超详细!保姆级!!)_nodejs安装及环境配置
3
数据库实验五_查询用户的订单信息,列出订单id
4
【代码实践】运行kafka出现ModuleNotFoundError: No module named ‘kafka.vendor.six.moves‘_modulenotfounderror: no module named 'kafka.vendor
5
凝思linux系统显卡设置,TaiShan服务器安装凝思操作系统Linx6.0.90并设置独立显卡WX2100输出...
6
完善Eureka监控信息
7
python中random的使用_python的random调用
8
在ROS2运行urdf_tutorial例程_xacro urdf ros2
9
植物大战僵尸杂交版 v2.3 Mac版首发
10
Sqlserver双机热备文档(无域)
当前位置:
article
> 正文
栈(上)之顺序栈_顺序栈易错点
作者:黑客灵魂 | 2024-07-29 21:28:02
赞
踩
顺序栈易错点
一、栈的定义
定义:栈(stack):栈是限定仅在表的一端进行插入或删除操作的线性表。
我们把允许插入和删除操作的一端称为栈顶(top),另一端称为栈底(bottom)。不含任何数据元素的栈称为空栈。栈又称为“后进先出(Last In First Out,简称LIFO)的线性表”,简称为LIFO结构。
栈的插入操作,称为进栈/入栈/压栈。
栈的删除操作,称为出栈/弹栈。
不过要注意的是,最先进栈的元素不代表最后出栈。栈对线性表的插入删除位置做了限制,但并没有对出栈和入栈的时间做限制。也就是说,在不是所有元素都入栈的情况下,事先入栈的元素也可以在任意时间出栈,只要保证每次出栈的元素都是栈顶元素就可以。
示例:有3个元素:1、2、3按顺序依次入栈,则我们可能得到以下出栈结果:
⒈1、2、3进,3、2、1出。得到结果为321
⒉1进、1出、2进、2出、3进、3出。得到结果为123
⒊1进、2进、2出、1出、3进、3出。得到结果为213
⒋1进、1出、2进、3进、3出、2出。得到结果为132
⒌1进、2进、2出、3进、3出、1出。得到结果为231
思考:能否得到结果为312的出栈序列?
答案:不可能,若3先出栈,则意味着1和2已入栈,此时2的出栈一定在1之前。
练习:已知一个栈的入栈顺序是a,b,c,d,e则不可能得到的出栈顺序是:
A、abcde
B、edcba
C、dceab
D、decba
二、栈的顺序存储结构及实现
1、顺序栈的结构定义
typedef int data_t;
typedef struct
{
data_t data[MAXSIZE];
int top;//栈顶元素位置
}SqStack;
当top=-1时,该栈为空栈。当top=MAXSIZE-1时,该栈为满栈。
2、进栈操作Push
//代码见附录
3、出栈操作Pop
//代码见附录
对于进栈和出栈操作来说,二者都没有用到循环语句,因此时间复杂度为O(1)。
4、清空栈操作
清空一个栈的操作可以用以下方法实现:不断弹栈,直至栈内没有元素为止。
但是这样做实际上是没有必要的。若要清空一个栈,则意味着该栈内的元素已经“无用”了,这时不用再每个元素进行弹栈操作,而直接将栈顶的位置拉下至栈底即可,即:
top=-1;
这样,当新的元素再次压栈时,会覆盖掉原始的“无用”数据。
//代码见附录
三、栈的链式存储结构及实现
对于顺序栈来说,主要的缺点就是栈的大小已经固定,若有超过栈长的元素个数,则此时栈会发生“溢出”。这时我们可以采用链式栈的存储结构,这样就不用再考虑栈的空间是否足够大的问题。
1、链栈的结构定义
栈的链式存储结构,简称为链栈。
思考:对于栈的链式存储结构来说,栈顶指针是在链表头结点位置更好,还是在链表尾节点位置更好?
答:头结点位置更好
链表有头指针,而栈的主要操作也是在栈顶进行,那么我们就可以将二者合一,将单链表的头指针作为栈顶指针,即栈的链式存储结构的栈顶指针为单链表的头指针。
typedef struct StackNode
{
data_t data;
struct StackNode *next;
}LinkStack;
2、判定链式栈是否为空
对于链栈来说,基本不存在栈满的情况,除非内存中已没有可用空间。因此不考虑判定链式栈满的操作。
对于链栈来说,栈空的情况实际上就是判断top==NULL的情况。
//代码见附录
3、进栈操作Push
//代码见附录
4、出栈操作Pop
//代码见附录
对于进栈和出栈操作来说,二者都没有用到循环语句,因此时间复杂度为O(1)。
5、清空栈操作
//代码见附录
对比顺序栈与链栈,我们发现它们在时间复杂度上是一样的,均为O(1)。对于空间性能,顺序栈需要事先确定长度,可能会存在内存空间浪费问题。但它的优势是存取时定位方便。而且链栈要求每个元素都有指针域,这同时也增加了内存开销,但对于栈的长度无限制。
综上所述,如果栈的使用过程中元素变化不可预料,有时数据量少有时却很大,则我们推荐使用链栈。反之,如果数据变化在可控范围内,则我们推荐使用顺序栈。
四、栈的应用
1、递归
递归:函数在自身的函数体内直接或间接地调用自身。
示例:递归法求斐波那契数列
int Fbi(int i)
{
if(i<2)
return i==0?0:1;
return Fbi(i-1)+Fbi(i-2);
}
int main()
{
int i;
for(i=0;i<40;i++)
printf("%d\t",Fbi(i));
printf("\n");
return 0;
}
要实现递归,必要的两个条件是递归出口和递归逻辑。在示例程序中,if(i<2)就是递归出口,而Fbi(i-1)+Fbi(i-2)就是递归逻辑。
//斐波那契数列的非递归解法略
对比递归代码和非递归(迭代)代码,我们可以看出递归和迭代的区别:迭代使用循环结构,而递归使用分支结构。
在某些程序中,递归能使得程序结构简洁清晰,容易理解。但是大量的调用递归函数会建立许多该函数的副本,需要大量的内存存储空间。而迭代法则无需大量的存储空间。
要想实现递归,我们需要明白递归的过程本质上是函数返回顺序是其调用顺序的逆序,即:先行调用的函数会在后面获得返回值。这种先行存储数据,并在之后逆序恢复得到数据的过程,显然很符合栈这种数据结构。因此,编译器使用栈来实现函数的递归。
在调用阶段,对于每层递归,函数的局部变量、参数、返回地址都被压入栈中,再去调用下次递归。在返回阶段,依次弹出位于栈顶的函数,获得计算结果。这也是为什么需要“递归出口”的原因,递归出口可以看做是从压栈到弹栈的状态转变因素。
2、后缀(逆波兰)表示法
对于数学运算来说,确定运算符的优先级是十分重要的,直接决定了该算式是否计算正确。在实际生活中,我们书写的算式都是中缀表达式,即运算符(此处特指算数运算符)在操作数中间。例如:
9+(3-1)*3+10/2
我们把这种平时使用的四则运算表达式的写法称为中缀表达式。但是对于计算机而言,中缀表达式并不方便。计算机计算都是从左到右顺序计算,在该算式中,*在+之后,但是却要先于+进行运算,而加入括号后,运算则会变得更加复杂。
对于四则运算,20世纪50年代,波兰逻辑学家Jan Lukasiewicz发明了一种不需要括号的表达式方法,称为后缀表示法,也称为逆波兰(Reverse Polish Notation,简称RPN)表示法。
对于上文的算式,使用后缀表示法为:
9 3 1 - 3 * + 10 2 / +
即运算符在两个操作数之后出现。
那么对于后缀表达法来说,计算机是怎样计算的呢?
后缀表达式的算法规则:从左到右遍历表达式,若遇到数字则进栈,遇到运算符则弹出栈顶两个元素进行运算,计算结果再次压栈,最后计算得到的结果就是最终结果。
我们以9 3 1 - 3 * + 10 2 / +进行讲解
⒈初始化一个空栈,此栈用于对要计算的操作数的进出及存储。
⒉9、3、1都是数字,因此依次入栈
⒊接下来是-,是符号,弹出栈顶两个元素作为操作数,注意先弹出的元素在符号右侧,后弹出的元素在符号左侧,即3 - 1,得到计算结果2,将2压栈。
⒋数字3进栈
⒌后面是*,栈顶两个元素弹栈进行运算 2 * 3,得到结果6,再压入栈
⒍后面是+,栈顶两个元素弹栈进行运算 9 + 6,得到结果15,再压入栈
⒎数字10和2进栈
⒏后面是/,栈顶两个元素弹栈进行运算 10 / 2,得到结果5,再压入栈
⒐最后一个符号是+,栈顶两个元素弹栈进行运算 15 + 5,得到结果20
⒑最终结果是20,栈变为空,结束运算。
那么,如何把中缀表达式转化为后缀表达式呢?
中缀表达式转化为后缀表达式的规则:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号则判断其与栈顶符号的优先级,是右括号或优先级低于或等于栈顶符号的则栈顶元素依次出栈并输出,直至遇到一个比其优先级低的运算符为止,并将当前符号进栈,一直到最终输出后缀表达式为止。
我们以9+(3-1)*3+10/2------>9 3 1 - 3 * + 10 2 / +为例进行讲解
1.初始化一个空栈,用于对符号进出栈使用。
2.第一个数字是9,输出9。后面的符号+入栈。
3.第三个字符是(,依然是符号,因其是左括号还未配对,故进栈。
4.第四个字符是数字3,输出,此时表达式为9 3,接着符号-进栈。
5.接下来是数字1,输出,此时表达式为9 3 1,后面是符号),此时我们需要把(之前的所有元素都出栈,直至输出(为止。此时总的表达式是9 3 1 -。
6.紧接着是符号*,因为此时的栈顶符号是+,优先级低于*,因此不输出,*进栈。紧接着是数字3,输出,总表达式为9 3 1 – 3.
7.之后是符号+,此时栈顶元素是*,比+优先级高,因此栈中元素出栈并输出(因为没有比+更低优先级的符号,所以全部出栈),总输出表达式为9 3 1 – 3 * +。然后将这个符号+进栈。
8.紧接着输出数字10,总表达式为9 3 1 – 3 * + 10。之后是符号/,所以/进栈。
9.最后一个数字为2,此时总表达式为9 3 1 – 3 * + 10 2。
10.因已到最后,所以将栈中符号全部出栈。最终获得的后缀表达式为9 3 1 – 3 * + 10 2 / +。
所以,对于计算机来说,输入中缀表达式,获得计算结果,最重要的有两步:
⒈将中缀表达式转化为后缀表达式
⒉计算后缀表达式得到计算结果
而这两步的整个过程都使用到了栈这种数据结构。
顺序栈代码
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 20
#define OK 1
#define ERROR 0
typedef int data_t;
typedef struct
{
data_t data[MAXSIZE];
int top;//栈顶元素所在的数组下标位置
}SqStack;
int PushStack(SqStack *s,data_t e)//压栈
{
if(s->top==MAXSIZE-1)
{
printf("Stack is Full\n");
return ERROR;
}
s->top++;
s->data[s->top]=e;
return OK;
}
int PopStack(SqStack *s,data_t *e)//弹栈
{
if(s->top==-1)
{
printf("Stack is Empty\n");
return ERROR;
}
*e=s->data[s->top];
s->top--;
return OK;
}
SqStack* CreateEmptyStack()//创建栈
{
SqStack *stack = (SqStack*)malloc(sizeof(SqStack));
if(stack==NULL)
{
printf("CreateEmptyStack Error\n");
exit(0);
}
stack->top=-1;
return stack;
}
int EmptyStack(SqStack *s)//判断栈是否是空栈
{
return -1==s->top?OK:ERROR;
}
int FullStack(SqStack *s)//判断栈是否是满栈
{
return MAXSIZE-1==s->top?OK:ERROR;
}
int ClearStack(SqStack *s)//清空栈内元素
{
s->top=-1;
return OK;
}
int main()
{
/*
SqStack *stack = CreateEmptyStack();
data_t data;
PushStack(stack,20);
PushStack(stack,30);
PopStack(stack,&data);
printf("pop:%d\n",data);
PopStack(stack,&data);
printf("pop:%d\n",data);
PopStack(stack,&data);
printf("pop:%d\n",data);
if(EmptyStack(stack)==OK)
printf("Stack is Empty!\n");
if(FullStack(stack)==OK)
printf("Stack is Full!\n");
*/
return 0;
}
声明:
本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:
https://www.wpsshop.cn/w/黑客灵魂/article/detail/900684
推荐阅读
article
Java
、
数据库
等
面试题
大全_
java
数据库
面试题
...
3. 笔试题之
Java
基础部分基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
赞
踩
article
Python
:
MNIST
手写
数据
集识别 +
手写
板
程序
最详细
,
直接放心
,
大胆地抄!跑不通找
我
,
我
...
利用
Python
语言编写和调试一个识别
手写
数字图像的三层深度前馈网络
,
包括
数据
预处理
,
网络模型构建
,
模型参数初始化和正向...
赞
踩
article
数据库
主键
、
外键
、
超键
、最左前缀
原则
_
主键
是否最
左匹配
原则
...
首先看看各种键的定义:
超键
(super key):在关系中能唯一标识元组的属性集称为关系模式的
超键
候选键(candida...
赞
踩
article
ChatGPT
:
ChatOpenAI
是什么?_
langchain
-
openai
的
chatopena...
ChatGPT
:
ChatOpenAI
是什么?_
langchain
-
openai
的
chat
openai
参数langcha...
赞
踩
article
Linux
下
安装
支持
h264
的
opencv
_手动
安装
libxopen
h264
...
h264
+
opencv
写在前面
安装
x264
安装
opencv
有可能出现的问题及解决方案:E: Unable to loca...
赞
踩
article
机器
学习
之
决策树
算法
详解干货_
决策树
结果
中的
图形
解释怎么写...
讲在前面:上一篇我们讲述了《机器
学习
实战》的K-近邻
算法
,刚好最近
学习
了第三章的
决策树
,既然开了前一章的头,那么我久继续...
赞
踩
article
DNS
和
HTTP
的抓
包
过程
分析
_
dns
抓
包
...
DNS
(Domain Name System,域名系统)是互联网的一项核心服务,它作为可以将域名和IP地址相互映射的一个...
赞
踩
article
文生图王者登场:
Stable
Diffusion
3
Medium
正式开源_
stable
-diffu...
今年2月,Stability.ai发布了
Stable
Diffusion
3预览版,在多主题提示、图像质量和拼写能力方面...
赞
踩
article
protobuf
安装
简单实例
linux
_
linux
系统
安装
protoc
教程...
下载
安装
包官网下载:https://github.com/google/
protobuf
https://github.c...
赞
踩
article
JTAG
/
JLINK
/OPENOCD/GDB_
jlink
jtag
...
小狼@http://blog.csdn.net/xiaolangyangyang_
jlink
jtag
jlink
jta...
赞
踩
article
双碳背景下
的
智算
中心
供电系统
架构
优化分析_
智算
中心
供电系统
ppt
...
另外,随着
智算
中心
的
到来,需要使用
的
油机容量越来越大,是否需要进一步提升单台油机
的
功率,从而降低油机占地面积,仍然是业内...
赞
踩
article
ESP32
开发
(1)----
Espressif
-
IDE
开发
环境
配置_
esp32
开发
环境
...
最近买了得到一块
ESP32
-WROOM-32的
开发
板,没有原理图,但板子走线比较简单,看着板子上的布线大致猜一猜连接,然...
赞
踩
article
mysql
安装 starting the
server
失败_
error
while setting ...
只有在任务处于完成状态(RanToCompletion、Faulted 或 Canceled)时才能释放它。只有在任务处...
赞
踩
article
对AI核心概念还
一头雾水
?这里有
你
需要
的
清晰解释:
RAG
、
Prompt
、CoT、
ReAct
等_pro...
在高考中,这就像是一个智能助手,在
你
答题时提供建议和帮助。典型代表是GitHub Copilot,它在
你
写代码时提供建议...
赞
踩
article
FPGA读写操作
SRAM
_
CY7C1051DV33
...
总结下,就是读写时间不能小于10nS,也就是最高频率100M,所以我们程序设计按100M时钟速率进行设计。注意,读写时,...
赞
踩
article
基于
jsp
+
mysql
的
JSP
医院
在线挂号
管理系统
...
运行环境: 最好是java jdk 1.8,我在这个平台上运行的。其他版本理论上也可以。 IDE环境:基于
jsp
+mys...
赞
踩
article
关于最新版本
protobuf
在
Windows
环境下
编译
失败的
解决办法
_
protobuf
window...
Windows
环境下
protobuf
编译
失败
_
protobuf
windows
protobuf
windows
...
赞
踩
article
列式
存储
是
什么?⾏
数
⽐较⼤
的
情况
,
⽐如说上亿
,
那么
列式
存储
是
怎么做
的
?
列式
存储
是
为了解决什么问题?
_
...
其空间效率也
是
很明显
的
。特别
是
针对动辄按T计算
的
数
据量来说
,
在分布式环境中能进⾏压缩处理能节。列⽅式所带来
的
重要好处之⼀...
赞
踩
article
【初阶
数据结构
】——
时间
复杂度
和
空间
复杂度
详解(C
描述
)_
数组
的
时间
复杂度
...
认识什么是
数据结构
和算法,详解
时间
复杂度
,
空间
复杂度
及例题练习_
数组
的
时间
复杂度
数组
的
时间
复杂度
...
赞
踩
article
.
gitignore
忽略
规则
的
匹配
语法_
python
的
gitignore
忽略
多个
,
正则
匹配
...
1、举例说明,掌握这些基本够用了#注释 .
gitignore
的
注释*.txt
忽略
所有 .txt 后缀
的
文件!s...
赞
踩
相关标签
java
python
深度学习
人工智能
神经网络
机器学习
chatgpt
ChatOpenAI
linux
opencv
h264
http
网络协议
网络
stable diffusion
SiliconCloud
硅基流动
SiliconFlow
p2p
fpga开发
架构
单片机
嵌入式硬件
mysql