搜索
查看
编辑修改
首页
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
hadoop环境搭建———Hadoop安装教程_伪分布式配置_CentOS6.4/Hadoop2.6.0【转载搬运】_厦门大学大数据实验室hadoop
2
华为OD面试流程
3
【iOS 开发】Xcode9 自动签名更新设备列表
4
sqlmap基本使用方式(非常详细)零基础入门到精通,收藏这一篇就够了_sqlmap使用教程(1)
5
机器人“围堵”大模型,AI赋能千行百业
6
Javascript前端面试基础(八)
7
idea 上传项目到gitlab(git)_idea上传项目到gitlab
8
docker安装onlyoffice_docker安装最新版本的onlyoffice
9
Datawhale AI 夏令营 学习笔记——机器学习竞赛——Task1
10
实验七 访问控制列表ACL_计算机网络实验7acl访问控制
当前位置:
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
SDR
实战(四)-
AD
9361
使用手册
(一)_
9361
锁相环
配置
...
本文详细介绍了
AD
9361
芯片的初始化过程,包括校准步骤,以及PLL、DCXO和射频/基带PLL的设置方法,着重于参考时...
赞
踩
article
用户
研究
:深度解析
用户
画像
_
用户
画像
分析模型
...
“
用户
画像
作为一种设计工具,可以很好得帮助设计师跳出“为自己设计”的惯性思维,聚焦目标
用户
,发现核心价值,赋能产品,在互...
赞
踩
article
点云
工具
CloudCompare
使用操作大全...
open:打开save:保存Global Shift settings:设置最大绝对坐标,最大实体对角线Primitiv...
赞
踩
article
开源
的
管理系统
...
http://www.jeecg.org/_
开源
工作周报
管理系统
开源
工作周报
管理系统
h...
赞
踩
article
如何
下载
B
站
视频
?5种
方法
教你无水印保存_b
站
视频
无水印
下载
...
B
站
作为国内知名的弹幕
视频
网
站
,拥有大量的优质
视频
资源。有时候我们想要将这些
视频
下载
下来,以便在无网络的情况下观看或者当...
赞
踩
article
【
2
0
2
1 年
MathorCup
高校数学建模
挑战赛
—赛道A
二手车
估价
问题
】
2
问题
一
数据
预处理...
目录
Baseline
代码和
数据
下载1 导入包
2
特征
工程
2
.1 缺失值处理
2
.
2
提取时间
特征
2
.3 匿名
特征
13的
特征
...
赞
踩
article
【机器学习】深度学习赋能:基于
LSTM
的智能
日志
异常
检测
_
lstm
异常
检测
...
使用
LSTM
网络进行
日志
序列
异常
检测
是一种有效的方法。通过合理的数据预处理、模型构建和评估,可以实现高效、准确的
异常
...
赞
踩
article
android
:
exported
使用
_
android
exported
的
使用
...
exported
主要用于表示是否允许其他应用调用当前组件:true: 当前提供者可以被其它应用
使用
。false:当前提供...
赞
踩
article
在
Java
程序
中怎么
保证
多线程
的
运行
安全?_在
java
程序
中怎么
保证
多线程
的
运行
安全?...
这种方式需要注意锁
的
粒度,使得锁住
的
代码块尽可能
的
短,以避免影响
程序
性能。3. 使用Lock对象:Lock是JDK提供
的
...
赞
踩
article
【数据库】
MySQL
基本操作(基操~)_
enter
password
: ****** welcome...
一、登陆
mysql
命令:
mysql
-uroot -pEnter
password
:Welcome
to
the
MyS...
赞
踩
article
Sklearn
中
Pipeline
的用法介绍 (使用
Pipeline
s简化
Python
机器学习代码)_...
介绍如何使用
Pipeline
封装数据处理和数据建模的工作流,简化
Python
代码,优化机器学习的流程。_
sklearn
...
赞
踩
article
Java
线程
安全的实现
方法
_
java
保证
一个
方法
线程
安全...
1.互斥同步 互斥同步(Mutual Exclusion&Synchronization)是常见的一种并发正确性保障手段...
赞
踩
article
Android
:
export
ed 属性详解_
android
export
默认值
...
没有任何的filter意味着这个Activity只有在详细的描述了他的class name后才能被唤醒 .这意味着这个A...
赞
踩
article
抢
土狗
机器人
——无
代码
基础
可以
使用
_
土狗
打新
机器人
...
抢
土狗
机器人
,带页面的。
_
土狗
打新
机器人
土狗
打新
机器人
上次分享了一个抢
土狗
的
机器人
,感...
赞
踩
article
Spark
实时
(一):
StructuredStreaming
介绍
...
Spark
Streaming与Structured Streaming相比较,
Spark
Streaming是
Spark
最...
赞
踩
article
UniSwap
使用
Web3j
生成原生币兑换代币。
_
web3j
swapexacttokensfo...
val function =when(methodName){ "swapEthForExactTokens" -> ...
赞
踩
article
知识
分享
系列五:
大
模型
与
AIGC
_
aigc
大
模型
...
大
语言
模型
首先需要通过
大
量文本进行无监督学习,借助海量文本数据,
模型
能更多了解单词与上下文之间的关系,从而更好地理解文本...
赞
踩
article
【
Python
数据结构
与算法】线性结构小结
_
python
顺序
栈
的
时间
复杂度
和空间
复杂度
(1)
_
顺序...
stack
的
基本操作包括push,pop,isEmpty。
_
顺序
栈
的
空间
复杂度
顺序
栈
的
空间
复杂度
...
赞
踩
article
python
用
input
输入元组_
python
–
Keras
LSTM
上的
batch
_
input
_...
我有以下特征向量,每个样本包含一个特征,总共有32个样本:X = [[0.1],[0.12],[0.3] …… [0.1...
赞
踩
article
TensorRT
INT8
量化
原理和实现_tensorrt
int8
量化
...
模型
量化
= 模型 +
量化
,两个词组成。在计算机视觉(深度学习)中,模型特指卷积神经网络,用于提取图像/视频特征。
量化
...
赞
踩
相关标签
笔记
p2p
网络协议
网络
photoshop
ui
运维
音视频
视频
python
数据挖掘
数据分析
lstm
人工智能
日志分析
机器学习
exported
app调用
java
开发语言
经验分享
sklearn
android
大数据