(浙大陈越版)数据结构 第二章 线性结构 2.2 堆栈

news2024/12/22 23:33:37

目录

2.2.1 什么是堆栈

堆栈

什么是堆栈

例子:计算机如何进行表达式求值?如:5+6/2-3*4

后缀表达式

堆栈的抽象数据类型描述

2.2.2 堆栈的顺序存储实现

例子:用一个数组实现两个堆栈,要求能最大利用数组空间,只要有空间就能实现入栈

2.2.3 堆栈的链式存储实现

2.2.4 堆栈应用:表达式求值

中缀表达式如何转换为后缀表达式

其他用途

2.2.1 什么是堆栈

堆栈

概念:一种线性结构,也是特殊的线性表

用途:表达式求值、递归、函数调用等实际上是使用堆栈实现的

什么是堆栈

例子:计算机如何进行表达式求值?如:5+6/2-3*4

如果没有优先级顺序,从左向右计算即可。表达式求值需要的是运算符和运算符前后的两个算子。而通常情况下运算符之后的数字并不一定是算子,而是需要运算的表达式。然而如果已知两个算子,那么接下来的计算就比较简单了。我们就引入了后缀表达式。

后缀表达式

概念:运算符号在运算数之后。

处理逻辑:遇到运算数先放着,遇到运算符就把最近存放的两个数拿来和运算符做运算。

我们通常使用的表达式是中缀表达式,即a+b*c-d/e,运算符号位于两个运算数中间。

与之等价的后缀表达式是:abc*+de/-(等价的前缀表达式:-+a*bc/de)

后缀表达式的这种处理逻辑,再抽象一下就是:一种能够存储运算数,并且先存储的后处理(后存储的先处理),像一口井一样的存储结构,我们称其为:堆栈

堆栈的抽象数据类型描述

堆栈(Stack):具有一定操作约束的线性表——只能在一端(称为栈顶,top)做插入和删除操作

  • 插入数据:入栈(Push)
  • 删除数据:出栈(Pop)
  • 处理顺序:后入先出(Last In First Out——LIFO)
  • 数据对象集:0~N个元素的有穷线性表
  • 操作集:长度为MaxSize的堆栈S(S属于Stack),堆栈元素item(item属于ElementType)
  1. Stack CreateStack(int MaxSize)           生成一个空堆栈,最大长度为MaxSize 
  2. int IsFull(Stack S,int MaxSize)              判断堆栈是否已满
  3. void Push(Stack S,ElementType item) 将元素item压入堆栈
  4. int IsEmpty(Stack S)                             判断堆栈是否为空
  5. ElementType Pop(Stack S)                  删除并返回栈顶元素

2.2.2 堆栈的顺序存储实现

栈的顺序存储结构实现一般使用一个结构体——包含一个一维数组和一个记录站定元素位置的变量组成。(和线性表比较像,像啊,很像啊,但是还记得吗?线性表的int元素是为了记录表长,这一点稍微不一样)

#define MaxSize //定义存储元素最大值
typedef struct SNode *Stack;
struct SNode{
    ElementType Data[MaxSize];
    int Top;
};
//1.入栈
void Push(Stack PrtS,ElementType item)
{
    //用数组存储,当top指向max-1时说明已满
    if( PrtS->Top == MaxSize-1 ){
        printf("堆栈已满");
        return;
    }else{
        //top位置增加,然后将元素放入
        PrtS->Data[++(PrtS->Top)] = item;
        return;
    }
}
//2.出栈
ElementType Pop(Stack PtrS)
{
    //若指向-1,说明栈空
    if(PtrS->Top == -1){
        printf("堆栈空");
        return ERROR;
    }else{
        //1.返回下标为Top的值
        //2.将Top值-1
        return(PtrS->Data[(PtrS->Top)--]);
    }
}

例子:用一个数组实现两个堆栈,要求能最大利用数组空间,只要有空间就能实现入栈

如何做?一个数组,两头都作为栈顶,左边要插入元素就将栈底向右,删除元素就删除先从最左元素开始。右边同理。

那么如何进行其他的操作集?比如如何判断堆栈已满?

两个栈肯定是需要两个栈顶的,而当两个栈顶相遇的时候,就说明栈已满。

对于栈空的判断,左栈顶设为Top1,右栈顶设为Top2。那么S.Top1=-1时左栈空。S.Top2=MaxSize(栈顶=MaxSize-1时说明右栈有一个元素)时右栈空。

这样的堆栈Push操作如下:

void Push(Struct DStack *PtrS,ElementType item, int Tag){
//Tag用于区别两个堆栈,分别取1和2
    //两个栈相遇,说明相减等于1
    if(PtrS->Top2 - PtrS->Top1 == 1){
        printf("堆栈已满");
    }
    if(Tag == 1){
        //插入栈1,放到top1后
        PtrS->Data[++(PtrS->Top1)] = item;
    }else{
        //插入栈2,放到top2前
        PtrS->Data[--(PtrS->Top2)] = item;
    }
}
ElementType Pop(Struct DStack *PtrS, int Tag){
    
    //删除栈1元素
    if(Tag == 1){
        //判断栈1是否空
        if(PtrS->Top1 == -1){
            printf("堆栈1空");
            return NULL;
        }else{
            //top1向左挪
            return PtrS->Data[(PtrS->Top1)--];
        }
    
    //删除栈2元素
    }else{
        if(PtrS->Top2 == MaxSize){
            printf("堆栈2空");
            return NULL;
        }else{
            //top2向左挪
            return PtrS->Data[(PtrS->Top2)++];
        }
}

2.2.3 堆栈的链式存储实现

堆栈的链式存储结构通常用单链表来实现,称为链栈。插入和删除操作只能在链栈的栈顶进行。

栈顶指针Top位于链表头。因为链表尾删除操作没法完成,找不到上一个节点的位置(链表的局限性)

typedef struct SNode *Stack;
struct SNode{
    ElementType Data;
    struct SNode *Next;
};

//1.初始化堆栈
Stack CreateStack()
{
    Stack S;

    //申请节点
    S = (Stack)malloc(sizeof(struct SNode));
    S->Next = NULL;
    return S;
}

int IsEmpty(Stack S)
{
    //若为空返回1,非空返回0
    return (S->Next == NULL);
}
//2.Push,相当于向链表中第一个元素前插入元素
void Push(ElementType item, Stack S){
    struct SNode *TempCell;
    TempCell = (struct SNode *)malloc(sizeof(struct SNode));
    TempCell -> Element = item;
    TempCell -> Next = S->Next;
    S->Next = TempCell;
}
//3.Pop,需要判断是否为空,相当于删除头结点后的第一个结点
ElementType Pop(Stack S){
    struct SNode *FirstCell;
    ElementType TopElem;
    if(IsEmpty(S)){
        printf("堆栈空");
        return NULL;
    }else{
        FirstCell = S->Next;//暂存,为了释放
        S->Next = FirstCell->Next;
        TopElem = FirstCell->Element;
        free(FirstCell);
        return TopElem;
    }
}

2.2.4 堆栈应用:表达式求值

前文提到,可以使用堆栈来实现后缀表达式求值的基本过程。那么如何用堆栈求中缀表达式呢?

简单来说,直接将中缀表达式转换为后缀表达式,再求值。但是如何将中缀转换为后缀?

eg:2+9/3-5(中缀) ->  293/+5-(后缀)规律:

  1. 运算数的相对顺序没变
  2. 运算符号相对顺序改变。优先级高的放前面。

以一个例子引入:a*(b+c)/d如何转化为后缀?

  1. 从左向右扫描, 分别存运算数和运算符号,
  2. 运算数先压入a,符号压入*,遇到括号,括号优先级更高,于是压入栈内
  3. 运算数压入b,符号压入+,加号优先级要高于括号,压入栈内
  4. 运算数压入c,符号压入右括号。
  5. 此时括号全部处理完毕,括号有关的都出栈,此时出栈为:)b+c(,得到b+c的值。
  6. 后面还有除号,优先级也比较高,但是相同优先级运算顺序是从左往右,此时栈内都出栈:得(b+c)*a
  7. 运算数压入d,符号压入/,运算,得((b+c)*a)/d

入栈顺序写出来即可得到后缀表达式:abc+*d/

中缀表达式如何转换为后缀表达式

 

其他用途

  • 函数调用和递归实现(函数栈)
  • 深度优先搜索
  • 回溯算法
  • ...

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

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

相关文章

路径之谜(DFS)-2016年蓝桥杯国赛

路径之谜-2016年国赛 1、题目描述2、解题思路3、代码实现1、题目描述 小明冒充 X 星球的骑士,进入了一个奇怪的城堡。 城堡里边什么都没有,只有方形石头铺成的地面。 假设城堡地面是 nn* 个方格。如下图所示。 按习俗,骑士要从西北角走到东南角。可以横向或纵向移动,但不能…

【Java虚拟机】JVM常见诊断命令和调试工具

1.JVM常用命令行参数jps和jinfo实操 准备测试代码 /*** author lixiang* date 2023/5/4 20:53*/ public class JVMTest {public static void main(String[] args) throws InterruptedException {Thread.sleep(1000000);} }(1)命令jps:全称 …

【exgcd】牛客练习赛 D-青蛙兔子的约会

D-青蛙兔子的约会_牛客练习赛111 (nowcoder.com) 题意: 思路: 感觉和那个青蛙的约会比较像 就是列了个方程: a*xb*yn 考虑用exgcd解方程 然后看x在[L,R]有没有解 做法就是先把x的最小整数解求出来,然后考虑它的通解 xx0b/…

2023年五一数学建模 B 题过程与结果

文章目录 第一问第二问数据时序分析Auto-ARIMA第二问求解解的情况A->Q:D-> AQ-V总快递数 第三问第四问遗传算法求解 第五问SARIMA 模型拟合季节性规律 第一问 见 2023 年 五一杯 B 题过程 代码(第一问) 第二问 第二问考虑是一个时序预测问题&a…

图像生成论文阅读:Latent Diffusion算法笔记

标题:High-Resolution Image Synthesis with Latent Diffusion Models 会议:CVPR2022 论文地址:https://ieeexplore.ieee.org/document/9878449/ 官方代码:https://github.com/CompVis/latent-diffusion 作者单位:慕尼…

数字乡村建设与示范项目可行性研究报告(word可编辑)

本资料来源公开网络,仅供个人学习,请勿商用,如有侵权请联系删除 5.1 “三平台”:建设支撑农业发展农村治理惠民服务的三大应用平 台 5.3.1 建设智慧农业综合服务平台 夯实数字农业基础,推进重要农产品全产业链大数据…

redis服务搭建,C++实现redis客户端,redis远程可视化工具

目录 redis简介redis服务搭建redis常用命令C实现redis客户端redis远程可视化工具:Another Redis DeskTop Manager redis简介 官方网址:https://redis.io/ 开源地址:https://github.com/redis 中文文档:http://www.redis.cn/documentation.ht…

造轮子系列】面试官问:你能手写Vuex吗(一)?

大厂面试题分享 面试题库 前后端面试题库 (面试必备) 推荐:★★★★★ 地址:前端面试题库 web前端面试题库 VS java后端面试题库大全 Vuex 是 Vue.js 的状态管理模式,它主要解决了组件之间共享状态时的问题。在本文…

网络原理之传输层

网络原理,进一步了解网络是如何工作的~~ 按照网络协议这几个层次来展开分为五点: 应用层(重点介绍)传输层(重点介绍)网络层(跳过)数据链路层(跳过)物理层&a…

JavaScript,

JS-引入方式JS-基础语法 书写语法变量数据类型&#xff0c;运算符&#xff0c;控制语句 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"…

Abstract Expressionist

古董地图画集 10大最有名的抽象艺术家 抽象表现主义是现代许多不同艺术思想和表达流派中最奇特的艺术运动之一。这场运动开始从社会变革中涌现出来&#xff0c;恰逢第二次世界大战的最后几周和几个月。 这一次&#xff0c;来自世界各地的人们开始欢迎在经历了多年有史以来最致…

【JavaWeb 用户认证】Cookie、Session、Token、JWT、Interceptor、SpringBoot、Spring Security

Token基本了解&#xff1a;【详细阐述Token的来源】公钥私钥基本了解&#xff1a;【理解公钥】 文章目录 一、Cookie 经典介绍以及使用案例二、Session 经典介绍以及拦截登录案例三、Token MySQL 的基本介绍及其基本使用四、JWT 基本介绍及其基本讲解五、SpringBoot 使用拦截器…

使用PyQt5设计一款简单的计算器

目录 一、环境配置&#xff1a; 二、代码实现 三、主程序 四、总结 本文使用PyQt5设计一款简单的计算器&#xff0c;可以通过界面交互实现加减乘除的功能&#xff0c;希望能够给初学者一些帮助。主要涉及的知识点有类的定义与初始化、类的成员函数、pyqt5的信号与槽函数等。…

LeetCode 牛客单链表OJ题目思路分享

目录 反转链表合并两个有序链表链表分割 反转链表 链接: link 题目描述&#xff1a; 题目思路&#xff1a; 方法1&#xff1a;改变链表链接的方向 方法1思路&#xff1a; 这力我们需要三个指针n1 n2 n3方便我们进行迭代 初始化n1指向NULL&#xff0c;n2指向第一个节点&…

云原生时代崛起的编程语言Go常用标准库实战

文章目录 基础标准库简述字符串-string底层结构函数长度格式化输出 模版-templatetext/templatehtml/template 正则表达式-regexp编码-encodingBase64JSONXML 时间-time网络-netURLHTTP客户端和服务端 加密IO操作读写文件环境变量命令行 数据库排序-sort测试和基准测试 基础标准…

OpenLDAP安装报错

tip:基于centos7&#xff0c;OpenLDAP使用2.4.44版本 只要有succeeded就可以。error可以忽略 配置base.ldif文件&#xff0c;下面的空行是必须的。 dn: dcts,dccom o: ts com dc: ts objectClass: top objectClass: dcObject objectclass: organizationdn: cnManager,dcts,d…

leveldb自定义env

leveldb自定义env 未完待续。。。 由于项目需求&#xff0c;需要自定义LevelDB的env&#xff0c;也就是以块接口实现env中各个文件接口&#xff0c;在网上没找到类似的代码&#xff0c;就打算自己参照util/env_posix.cc实现一个简单的demo&#xff0c;等到功能实现差不多的时候…

ADRV9002官方例程开发过程中遇到的问题

开发环境&#xff1a;Vivado2021.2 HDL版本&#xff1a;hdl_2021_r2 GitHub - analogdevicesinc/hdl at hdl_2021_r2 no-OS版本&#xff1a;no_OS-2021_R2 GitHub - analogdevicesinc/no-OS at 2021_R2 &#xff08;PS&#xff1a;也可以用Vivado2019.1开发&#xff0c…

【漏洞复现】Joomla未授权访问漏洞(CVE-2023-23752)

文章目录 前言声明一、漏洞简介二、影响版本三、环境搭建四、漏洞分析五、漏洞复现六、修复建议前言 Joomla是一套全球知名的内容管理系统(CMS),其使用PHP语言加上MySQL数据库所开发,可以在Linux、Windows、MacOSX等各种不同的平台上运行。 声明 本篇文章仅用于漏洞复现与…

华为OD机试真题-密码强度等级【2023】【JAVA】

一、题目描述 密码按如下规则进行计分&#xff0c;并根据不同的得分为密码进行安全等级划分。 1、密码长度&#xff1a; 5 分: 小于等于4 个字符 10 分: 5 到7 字符 25 分: 大于等于8 个字符 2、字母&#xff1a; 0 分: 没有字母 10 分: 密码里的字母全都是小&#xff08;…