数据结构(括号匹配与表达式计算)

news2024/9/29 11:41:19

目录

括号配对

括号匹配算法

表达式计算

后缀式的计算

中缀式转后缀式


括号配对

 编译器做语法检查的任务之一是检查符号是否配对,最简单的符号匹配问题是括号是否匹配,如开括号( 及{ 后面必须依次跟随相应的闭括号 }及 )。

 如下段程序中的括号、引号是否匹配。

int main()
{   int a[20], i;
    for (i=0; i<20; i++)
    {   a[i]=3*(19-i)/5*(12-6);
        cout<<a[i]<<'/t';
     }
     return 0;
}

括号匹配算法

1.首先创建一个字符栈。
2.从源程序中读入字符。
         如果读入的是开括号,将其进栈
         如果读入的是闭括号但栈是空的,说明少开括号,报错并结束

          如果读入的是闭括号但栈不空,将栈中的开括号出栈。如果出栈的开括号和读入的闭             括号不是同种类型(如一个为小括号,一个为中括号),说明不匹配,报错并结束

3.继续从文件中读入下一个符号,非结束符则转向2),否则转向4)。
4.如果栈非空,说明开括号多了,报错并结束;
5.否则括号配对成功,结束。

核心而简单的算术表达式中括号匹配检测程序:(此处引入了链式栈)

#include <iostream>
#include "linkStack.h"
using namespace std;
 int main()
{   char str[20];
    linkStack<char> s;  //建立一个字符栈
    char ch;
    int i;

    cout<<"Input the string: ";
    cin.getline(str, 20, '\n');
    cout<<"str: "<<str<<endl;
    i=0;    ch=str[i++];
    while (ch!='\0')
    {   switch(ch)
        {  case '(':      s.push(ch);    break;
            case ')':     if (s.isEmpty())
                             {    //读入一个闭括号,栈却空,找不到匹配的开括号
                                   cout<<"An opening bracket '(' is expected!\n";
                                   return 1;
                             }
                   else      s.pop();
                    break;
        }
        ch=str[i++];
    }
     if (!s.isEmpty()) //式子读入结束,发现栈中还有多余的开括号
       	cout<<"A closing bracket ')' is expected!\n";
     return 0;
}

(为简化,假设只有小括号)

表达式计算

算术表达式是编程语言中一个最基本的组成元素,由操作数、运算符及括号构成。

以下分析中,为了简化,限定操作数为一位整数;运算符为加、减、乘、除四种二元运算符;括号仅含有小括号,如:5*(7-2*3)+8/2。

算术表达式中运算符出现在两个操作数之间,这种形式称为中缀式,运算符在前称为前缀式或波兰式,运算符在后称后缀式或逆波兰式

中缀式有利于人的理解,但不便于计算机处理;

前缀式不便于人理解,但可去掉括号;

后缀式不便于人理解,可去掉括号,更便于计算机计算。

在编译时,编译器首先要把中缀式转换成后缀式。

表达式计算涉及到两个方面的工作:

中缀式转换为后缀式
后缀式计算

如,表达式5*(7-2*3)+8/2转换为后缀式为: 5 7 2 3*-*8 2/+。

手工转换时,先计算的先转换。

可以看出:

从左至右,操作数保持原来的相对位置,操作符是先计算的先出现。

后缀式经过一次从左到右的扫描即可计算出结果。

后缀式的计算

如,表达式5*(7-2*3)+8/2转换为后缀式为: 5 7 2 3*-*8 2/+。

手工转换时,先计算的先转换。

在后缀式中可以看出:

从左至右,操作数保持原来的相对位置,操作符是先计算的先出现。

 计算后缀式:

1.声明一个操作数栈,依次读入后缀式中的字符。
2.若读到的是操作数,将其进栈;
3.若读到的是运算符,将栈顶的两个操作数出栈。后弹出的操作数为被操作数,先弹出的       为操作数。将出栈的两个操作数完成运算符所规定的运算后将结果进栈。
4.继续读入后缀式中的字符,如上处理,最后直到后缀式中所有字符读入完毕。
5.当完成以上操作后,栈中只剩一个操作数,弹出该操作数,它就是表达式的计算结果。

计算后缀式: 以5 7 2 3*-*8 2/+为例(逐步进行分析)

 

 计算后缀式算法实现

int calcPost(char *sufStr)
{   int op1, op2, op;   int tmp, i;   linkStack<int> s;
     i=0;
    while (sufStr[i]!='\0')
    {   if ((sufStr[i]>='0')&&(sufStr[i]<='9')) //数字转为整数后进栈
        {  tmp = sufStr[i] - '0';
            s.push(tmp);
        }
        else
        {     op2 = s.top(); s.pop(); //栈顶整数出栈      op1 = s.top(); s.pop();
            switch (sufStr[i])
            {  case '*': op = op1*op2; break; //如果是运算符为'*',则做*运算
                case '/': op = op1/op2; break;
                case '+': op = op1+op2; break;
                case '-': op = op1-op2; break;      
            };
            s.push(op); //每一步计算结果进栈
        }    i++;
    } 
    op = s.top(); s.pop();
    return op;        }

 从算法中可以看出,对后缀式字符串从左到右一次扫描即可计算完毕。

中缀式转后缀式

表达式5*(7-2*3)+8/2转换为后缀式为: 5 7 2 3*-*8 2/+。

手工转换时,先计算的先转换,即按照计算的优先级来。

观察后缀式,可以看出:

从左至右,操作数保持原来的相对位置,操作符是先计算的先出现。

中缀式转后缀式算法分析:

Ø对一个中缀表达式,从左至右顺序读入各操作数、运算符。
Ø当读入的是操作数时,直接输出 (如:输出到屏幕或追加到保存后缀式的字符串中);
Ø当读入的是操作符时,当读入的运算符优先级高时,因不知是否后续读入的操作符优先级更高,只能将本次读入的运算符暂存,继续读入中缀式。当读入的运算符优先级低时,才可能计算刚才暂存的运算符(即输出);在暂存机构中,越是后面存入的操作符,优先级越高,越先出来进行计算,这种结构就是,处于栈顶的运算符的优先级最高。
Ø相同运算符,先进栈的优先级高于后进栈的。
Ø表达式中的括号也可以看作是一种操作符,其中开括号具有两面性:即将进入栈的开括号,优先级最高;已经在栈顶的开括号,优先级最低。括号在后缀式中是要消失的,消失靠闭括号。当读入一个闭括号时,计算之前进栈的运算符,直到遇到一个开括号,然后开闭括号双双消失即可。

 中缀式转后缀式算法:

 对一个中缀表达式,从左至右顺序读入各操作数、运算符。

Ø当读入的是操作数时,直接输出 。
Ø当读入的符号是开括号,直接进栈。
Ø当读入的符号是闭括号,反复进行栈顶元素出栈、输出,直到弹栈的是开括号。
Ø当读入的是操作符时,如果栈顶操作符的优先级更高,反复弹栈、输出直到栈顶元素优先级低于读入操作符的优先级,读入操作符压栈;如果栈顶操作符的优先级低,读入的运算符进栈。

 中缀式转后缀式算法示例:5*(7-2*3)+8/2转换为 5 7 2 3*-*8 2/+

设立一个用于保存运算符的堆栈,先将一个底垫’#’压栈,设其优先级为最低。

void inToSufForm(char *inStr, char *sufStr)
{  linkStack<char> s; //用字符栈         int i,j;   char topCh;
    
    s.push('#'); //铺垫一个底垫               i=0;j=0
    while (inStr[i]!='\0')
    {      if ((inStr[i]>='0')&&(inStr[i]<='9'))
            sufStr[j++]=inStr[i++];
           else {   switch (inStr[i])
            {   case '(':   s.push('('); break; //优先级最高,直接入栈
                 case ')':   //弹栈,弹出元素进入后缀式,直到弹出一个左括号
                         topCh = s.top(); s.pop();
                         while (topCh!='(')
                         {   sufStr[j++] = topCh;
                             topCh = s.top(); s.pop();
                         }//')'字符不入栈
                         break;
                case '*':
                case '/':   topCh = s.top();
                               while ((topCh=='*')||(topCh=='/'))
                                //*、/为左结合,故后来者优先级低
                               {  s.pop();
                                   sufStr[j++] = topCh;
                                   topCh = s.top();
                               }
                               s.push(inStr[i]);  break;
                case '+':
                case '-':   topCh = s.top();
                               while ((topCh!='(')&&(topCh!='#'))
                                //只有左括号和底垫优先级比+、-低
                               {   s.pop();   sufStr[j++] = topCh;   topCh = s.top();                 
                               }
                                s.push(inStr[i]);
                                break;
            }//switch
            i++;
        }//else
    }//while
	//将栈中还没有弹出的操作符弹空
    	topCh = s.top();
    	while (topCh!='#')
    	{   sufStr[j++] = topCh;
        	     s.pop();
        	      topCh = s.top();
    	}
     sufStr[j]='\0'; //后缀字符串加结束符'\0'
}

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

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

相关文章

谷歌竞价账户效果不好的原因?

很多外贸企业喜欢用谷歌竞价来推广自己的网站&#xff0c;提升自己的竞争力。是一种能很快看到效果的宣传方式。但是很多公司在谷歌竞价上投入了大量的资金&#xff0c;却收效甚微。为什么&#xff1f;下面我们来看看如何解决我们在google竞价推广中会遇到的一些问题。很多人在…

Linux的文件权限理解

目录 前言 1、用户、用户组、其他人 1.1用户、用户组、其他人之间的概念理解 1.2Linux系统中有用户身份与用户组记录的文件 2、Linux文件权限概念 第一列 第二列 第三列 第四列 第五列 第六列 第七列 Linux文件权限的重要性 3、Linux的目录与文件的权限意义 权限…

计算机图形学 第5章 二维变换与裁剪到Cohen-Sutherland直线裁剪算法

目录学习目标前驱知识规范化齐次坐标二维几何变换矩阵物体变换与坐标变换二维几何变换二维图形基本几何变换矩阵平移变换矩阵比例变换矩阵旋转变换矩阵反射变换矩阵错切变换矩阵二维仿射变换二维复合变换相对于任意方向的二维几何变换二维图形裁剪世界坐标系2.用户坐标系观察坐…

VSCode中设置Python语言自动格式化的方案

安装Python扩展 在VSCode的扩展&#xff08;Externsions&#xff09;中使用下面命令检索Python扩展 category:debuggers Python 打开一个Python文件&#xff0c;可以在VSCode的右下角看到运行环境。 安装PEP8 python3.10 -m pip install -U autopep8 安装Flake8 python3.10 …

上百个数字经济新场景 低代码完美搭建 实现项目落地

数字经济 自人类社会进入信息时代以来&#xff0c;数字技术的快速发展和广泛应用衍生出数字经济(Digital Economy)。与农耕时代的农业经济&#xff0c;以及工业时代的工业经济大有不同&#xff0c;数字经济是一种新的经济、新的动能&#xff0c;新的业态&#xff0c;其引发了社…

MicroBlaze系列教程(3):AXI_TIMER的使用

文章目录 @[toc]AXI_TIMER简介常用函数使用示例参考资料工程下载本文是Xilinx MicroBlaze系列教程的第3篇文章。 AXI_TIMER简介 AXI_TIMER支持两路可编程32位计数器,可以配置为中断、捕获、PWM模式,两个32位计数器可以级联为一个64位计数器。 IP核支持的最高频率: 常用…

nacos 服务发现获取列表源码分析

nacos 服务发现获取列表源码是注册中心最重要的技术点之一&#xff0c;其获取服务列表理论上是在首次接口调用时获取&#xff0c;有时候配置饥饿加载&#xff0c;即服务启动时就获取服务列表&#xff1a;今天我们从一个入口解析获取配置列表; 一、客户端源码 1、自动装配&…

推荐系统之推荐缓存服务

5.6 推荐缓存服务 学习目标 目标 无应用 无 5.6.1 待推荐结果的redis缓存 目的&#xff1a;对待推荐结果进行二级缓存&#xff0c;多级缓存减少数据库读取压力步骤&#xff1a; 1、获取redis结果&#xff0c;进行判断 如果redis有&#xff0c;读取需要推荐的文章数量放回&am…

(深度学习快速入门)第四章第一节:基础图像处理知识

文章目录一&#xff1a;位图和矢量图二&#xff1a;图像分辨率三&#xff1a;颜色模式&#xff08;1&#xff09;RGB&#xff08;2&#xff09;HSB&#xff08;2&#xff09;灰度图四&#xff1a;通道五&#xff1a;亮度、对比度和饱和度六&#xff1a;图像平滑和锐化&#xff…

D3股权穿透图

前言&#xff1a;最近做了一个项目&#xff0c;主要就是实现各种类似企查查的各种图谱&#xff0c;欢迎交流。后期将完成的谱图全部链接上&#xff0c;目前已大致实现了&#xff1a; 【企业关系图谱】、【企业构成图谱】、【股权穿透图】、【股权结构图】、【关联方认定图】 准…

【蓝桥杯基础题】2018年省赛—日志统计

&#x1f451;专栏内容&#xff1a;蓝桥杯刷题⛪个人主页&#xff1a;子夜的星的主页&#x1f495;座右铭&#xff1a;前路未远&#xff0c;步履不停 目录一、题目描述1.问题描述2.输入格式3.输出格式4.一个例子二、题目分析1、暴力法2、双指针三、代码汇总1、暴力代码汇总2、双…

【Mysql第一期 数据库概述】

文章目录1. 为什么要使用数据库2. 数据库与数据库管理系统2.1 数据库的相关概念2.2 数据库特点2.3SQL优点3.常见的数据库介绍1.Oracle2.SQL Server3.MySQL4.Access5.DB26.PostgreSQL7.SQLite8.informix4. MySQL介绍4.1Mysql重大历史事件4.2 关于MySQL 8.04.3 Why choose MySQL?…

linux内核读文件代码分析

linux下“一切皆文件”,所有设备都可以被抽象成文件,用户态可以通过open、read、write、llseek等api操作一个文件,通过系统调用进入内核态,最终访问到pagecache/磁盘上的数据,然后返回给用户态。 kernel version:v6.2-rc4 社区master主干 用户态应用程序调用read接口,通…

【转载】车载传感器与云端数据交换标准SensorIS的理解与使用

原文 https://zhuanlan.zhihu.com/p/386277784 1、什么是SensorIS?SensorIS全称是Sensor Interface Specification&#xff0c;翻译为中文就是传感器接口规范&#xff0c;是由来自全球汽车行业的主机厂、地图和数据提供商、传感器制造商和电信运营商共同组成的开放团体发布的一…

JavaEE day10 初识SpringMVC

JSON简介 JSON &#xff1a;JavaScript Object Notation JS对象表示法 是轻量级的文本数据交换格式&#xff0c;但是JSON仍然独立于语言和平台。其解析器和库支持许多不同的编程语言。目前非常多的动态编程语言&#xff08;java&#xff0c;PHP&#xff09;都支持JSON。JSON…

禅道好用吗?优缺点及类似10大项目管理系统介绍

类似禅道的十大项目管理软件&#xff1a;1、一站式研发项目管理软件PingCode&#xff1b;2、通用型项目协作工具Worktile&#xff1b;3、开源项目管理软件Redmine&#xff1b;4、免费项目管理软件Trello&#xff1b;5、无代码项目管理软件Monday&#xff1b;6、IT项目追踪管理工…

面试宝典-数据库基础

数据库基础前言一、数据库1.1 sql练习题1.2 sql语句执行顺序1.3 sql语句编写前言 本文主要记录B站视频视频链接的内容&#xff0c;做到知识梳理和总结的作用&#xff0c;项目git地址。 一、数据库 1.1 sql练习题 user表数据: idusername1张三2李四3王五4小刘 user_role表数…

CrackQL:一款功能强大的图形化密码爆破和模糊测试工具

关于CrackQL CrackQL是一款功能强大的图形化密码爆破和模糊测试工具&#xff0c;在该工具的帮助下&#xff0c;广大研究人员可以针对密码安全和应用程序安全进行渗透测试。 除此之外&#xff0c;CrackQL同时也是一款通用的GraphQL渗透测试工具&#xff0c;它可以控制速率限制…

垃圾分类智能分析系统 yolov7

垃圾分类智能分析系统应用pythonyolov7网络模型深度学习识别技术&#xff0c;自动识别违规投放行为并现场进行语音提示实时预警。如垃圾满溢抓拍预警、人脸识别、工服识别、厨余垃圾混投未破袋识别预警、垃圾落地识别预警、人来扔垃圾语音提醒等。我们选择当下YOLO最新的卷积神…

数组去重的七种方法

数组去重的七种方法1. 双重for循环2. forindexOf3.es6 set4.filter5.includes6.创建一个新的object7.new Map()1. 双重for循环 第1种是定义一个新的空数组&#xff0c;再执行嵌套双循环&#xff0c;监测空数组中如果没有的元素&#xff0c;push进空数组中。这个方法考察了conti…