3.2栈的应用举例3.2.5-表达式求值ppt课件

合集下载

栈及其应用PPT课件

栈及其应用PPT课件
.
特别的,不含任何元素的栈称为空栈。
二、栈的实现 1.栈的顺序存储结构
我们称用顺序结构存储的栈为顺序栈(array-based stack),即:利用连续的存储单元依次记录 栈的所有元素。一般来说,使用一维数组B存储栈的所有元素,变量top记录栈的大小,将s[1]叫作 为栈底,s[top]为栈顶。顺序栈Stack定义如下: TYPE Stack =record
一、栈的定义 从上面的例子,我们可以看出,栈(Stack)是一种特殊的线性表,它的特殊之
处在说,栈的操作是按后进 先出的顺序处理数据,因此栈又称后进先出表(Lastn First Out,LIFO)。
对于一个栈来说,我们习惯上称它的可操作端为栈顶 (Top),另一端为栈底 (Bottom)。设栈S=(a1,a2,···,an),a1端为栈底,an端为栈顶,则有: 1.插入一个元素an+1后,栈更新为S=(a1, a2,...,an,an+1) 2.从栈中删除一个元素后,栈更新为S=(a1,a2,,...,an-1)
S=D1 op1 D2 op2 D3 op3 ..Di opi... Dn-1 opn-1 Dn,这里Di为操作数,opi 为运算符,i=l, 2,...,n-l,由此,我们得到如下算法:
(1)对S进行扫描,从opi中找一个最高优先级别的运算符进行操作 并将Di-1=Di-1 opi-1 Di。删除opi-1和Di.
.
【例4】利用栈实现算术表达式求值 编写一个包含有“+”、“-”、“,”、“/”、“(”、“)”等运算符的表达式,计 算出该表达式的数值。
例如,3*(5-2)+7=3*3+7=9+7=16。
[分析] 对于给定的表达式计算,有一个运算符优先计算的问题,即“先算括号内,再算

栈和队列

栈和队列
设计思路:用栈暂存左括号
应用3 :表达式求值
设计思路:用栈暂存运算符
应用4:汉诺仪(Hanoi)塔
设计思路:用栈实现递归调用
例 表达式求值
1)问题的提出 假若我们想在计算机上设计一个小计算器(程序), 其功能为:从键盘上输入一个算术表达式(由运算符操 作数构成的字符串),在屏目上显示输出表达式的求值结 果。 显然这个小计算器程序应该对你键入的表达式进行求 值。在该程序中如何对键入的表达式求值呢?又如,高 级语言中都有表达式,例赋值语句:变量=表达式;该 语句的执行过程为:先求出表达式的值, 然后将其值赋 给赋值号左边的变量。这个表达式的值是如何求出的?
我们看到:进行运算的算符i是当前扫描过的运算 符中优先级最高者,同时,也是到当前最后被保存的运 算符,由此可见,可以利用两个栈分别保存扫描过程中 遇到的操作数和运算符。
6 算法思想:
设定两栈:操作符栈 OPTR ,操作数栈 OPND 栈初始化:设操作数栈 OPND 为空;操作符栈 OPTR 的栈底 元素为表达式起始符 ‘#’; 依次读入字符:是操作数则入OPND栈,是操作符则要判断: if 操作符 < 栈顶元素,则退栈、计算,结果压入OPND栈; 操作符 = 栈顶元素且不为‘#’,脱括号(弹出左括号); 操作符 > 栈顶元素,压入OPTR栈。
问:堆栈是什么?它与一般线性表有什么不同?
答:堆栈是一种特殊的线性表,它只能在表的一端 (即栈顶)进行插入和删除运算。 与一般线性表的区别:仅在于运算规则不同。
一般线性表 逻辑结构:一对一 存储结构:顺序表、链表 运算规则:随机存取 堆栈 逻辑结构:一对一 存储结构:顺序栈、链栈 运算规则:后进先出(LIFO)
数据结构课程的内容
受限的线 性表

C++实例(表达式求值(栈的应用))

C++实例(表达式求值(栈的应用))

表达式求值: 设计⼀个程序实现输⼊⼀个表达式如3*(3+4),以”#”结尾,求出其值。

分析: 先分析⼀下四则运算的规则: 1. 先乘除后加减; 2. 从左到右计算; 3. 先括号内后括号外; 于是我们要把运算符的优先级确定清楚。

这⾥我只⽤这⼏个运算符:+-*/(), 可以知道+-的优先级低于*/,⽽对于(),当第⼀次遇到’(‘时,’(‘后⾯的就优先计算,直到遇到’)’为⽌,可以先把’(’的优先级定为⽐其它⼏个都⾼,然后遇到’)’时把⾥⾯的先算出来,再算括号外⾯的,具体实现在代码中会表现得很清楚。

考试2⼤提⽰这个程序还是⽤栈来实现,具体代码如下。

代码: #include #include using namespace std; const int STACK_INIT_SIZE=100; //The maximize length of stack template class Stack //A class of stack { public: Stack() //Constructor function { base = new int[STACK_INIT_SIZE]; if (!base) { cerr< exit(-1); } top=base; stacksize=STACK_INIT_SIZE; } ~Stack() //Destructor function { if (base) delete[] base; } T GetTop() { if (top==base) { cerr< exit(-1); } return *(top-1); } void Push(T e) { if (top-base>=stacksize) { base=new int[STACK_INIT_SIZE]; if(!base) { cerr< exit(-1); } top=base+STACK_INIT_SIZE; stacksize+=STACK_INIT_SIZE; } *top++=e; } void Pop(T& e) { if (top==base) { cerr< exit(-1); } e=*--top; } private: int *base; int *top; int stacksize; }; string op("+-*/()#"); //The set of operator bool In(char c,string op) //Judge the character whether belong to the set of operator { string::iterator iter=op.begin(); for (;iter!=op.end();++iter) if (*iter==c) return true; return false; } char Precede(char top,char c) //Confirm the precedence of operator { int grade_top=0,grade_c=0; switch (top) { case '#':grade_top=0;break; case ')':grade_top=1;break; case '+':grade_top=2;break; case '-':grade_top=2;break; case '*':grade_top=3;break; case '/':grade_top=3;break; case '(':grade_top=4;break; } switch (c) { case '#':grade_c=0;break; case ')':grade_c=1;break; case '+':grade_c=2;break; case '-':grade_c=2;break; case '*':grade_c=3;break; case '/':grade_c=3;break; case '(':grade_c=4;break; } if (grade_top>=grade_c) { if (top=='('&&c!=')') return ' else if (top=='('&&c==')') return '='; return '>'; } else if (top=='#'&&c=='#') return '='; else return ' } int Operate(int a,char theta,int b) //Calculate { if (theta=='+') return a+b; else if (theta=='-') return a-b; else if (theta=='*') return a*b; else if (theta=='/') return a/b; return 0; } int EvaluateExpression(Stack& OPTR,Stack& OPND) { int a=0,b=0,n=0; char x; char theta; string c; cin>>c; OPTR.Push('#'); while (c[0]!='#'||OPTR.GetTop()!='#') { if (!In(c[0],op)){ n=atoi(&c[0]); OPND.Push(n); cin>>c; } else switch (Precede(OPTR.GetTop(),c[0])) { case ' OPTR.Push(c[0]); cin>>c; break; case '=': OPTR.Pop(x); cin>>c; break; case '>': OPTR.Pop(theta); OPND.Pop(b); OPND.Pop(a); OPND.Push(Operate(a,theta,b)); break; } } return OPND.GetTop(); } int main() { Stack OPTR; Stack OPND; cout< cout< return 0; }。

数据结构 课件 第3章 栈

数据结构 课件 第3章 栈
实用数据结构基础
第3章 栈
第 3 章 栈

识点
栈的定义和特点 栈的基本运算和算法 栈的典型应用


后缀表达式的算法 数制的换算 利用本章的基本知识设计相关的应用问题


掌握栈的特点 掌握栈的基本运算 熟悉栈的各种实际应用 能设计栈应用的典型算法 了解栈的运算时间复杂度分析
第3章 目录

2.顺序栈运算的基本算法 (1)置空栈 首先建立栈空间,然后初始化栈顶指针。 SeqStack *Snull( ) { SeqStack *s; s=new (SeqStack);
// 在C语言中用s=malloc(sizeof(SeqStack)) ;
s->top= –1; return s; }
3-1 栈的定义与运算 3-2 栈的存储和实现 3-3 栈的应用举例 小 结 验证性实验3: 栈子系统 自主设计实验3:后缀表达式求值 单元练习3
3-1 栈的定义和运算
3-1-1 栈(Stack)的定义
1. 栈的定义 栈是限制在表尾进行插入和删除的线性表。 进栈 出栈
an …… a3 a2 a1
图3-1栈的 示意图
3-3.
3-3-1 数制转换
栈的应用举例
数值进位制的换算是计算机实现计算和处理的 基本问题。比如将十进制数N转换为j进制的数,其 解决的方法很多,其中一个常用的算法是除j取余法。 将十进制数每次除以j,所得的余数依次入栈,然后 按“后进先出”的次序出栈便得到转换的结果。 其算法原理是: N =(N / j)* j + N % j
由于栈的操作只能在栈顶进行的,所以用链表的头部做
栈顶是最合适的。链栈结构如图3-4所示。

大学数据结构课件--第3章 栈和队列

大学数据结构课件--第3章 栈和队列
top top 栈空 F E D C B A
栈满 top-base=stacksize
top
F
E
D C B
top top top top top top base
入栈PUSH(s,x):s[top++]=x; top 出栈 POP(s,x):x=s[--top]; top
base
4
A
3.1 栈
例1:一个栈的输入序列为1,2,3,若在入栈的过程中 允许出栈,则可能得到的出栈序列是什么? 答: 可以通过穷举所有可能性来求解:
3.2 栈的应用举例
二、表达式求值
“算符优先法”
一个表达式由操作数、运算符和界限符组成。 # 例如:3*(7-2*3) (1)要正确求值,首先了解算术四则运算的规则 a.从左算到右 b.先乘除后加减 c.先括号内,后括号外 所以,3*(7-2*3)=3*(7-6)=3*1=3
9
3.2 栈的应用举例
InitStack(S); while (!QueueEmpty(Q))
{DeQueue(Q,d);push(S,d);}
while (!StackEmpty(S)) {pop(S,d);EnQueue(Q,d);} }
第3章 栈和队列
教学要求:
1、掌握栈和队列的定义、特性,并能正确应用它们解决实 际问题;
用一组地址连续的存储单元依次存放从队头到队尾的元素, 设指针front和rear分别指示队头元素和队尾元素的位置。
Q.rear 5 4 Q.rear 3 2 3 2 5 4 Q.rear 3 3 5 4 5 4
F E D C
C B A
Q.front
2 1 0
C B
Q.front 2 1 0

数据结构-栈基本运算的实现及其应用

数据结构-栈基本运算的实现及其应用

数据结构-栈基本运算的实现及其应用下载提示:该文档是本店铺精心编制而成的,希望大家下载后,能够帮助大家解决实际问题。

文档下载后可定制修改,请根据实际需要进行调整和使用,谢谢!本店铺为大家提供各种类型的实用资料,如教育随笔、日记赏析、句子摘抄、古诗大全、经典美文、话题作文、工作总结、词语解析、文案摘录、其他资料等等,想了解不同资料格式和写法,敬请关注!Download tips: This document is carefully compiled by this editor. I hope that after you download it, it can help you solve practical problems. The document can be customized and modified after downloading, please adjust and use it according to actual needs, thank you! In addition, this shop provides you with various types of practical materials, such as educational essays, diary appreciation, sentence excerpts, ancient poems, classic articles, topic composition, work summary, word parsing, copy excerpts, other materials and so on, want to know different data formats and writing methods, please pay attention!数据结构栈基本运算的实现及其应用在计算机科学和编程中,数据结构是非常重要的概念。

数据结构第3章栈

数据结构第3章栈
Elemtype pop(sqstack *s) { /*若栈s不为空,则删除栈顶元素*/ Elemtype x; if(s->top<0) return NULL; /*栈空*/ x=s->stack[s->top]; s->top--; return x; }
13
(4)取栈顶元素操作
Elemtype gettop(sqstack *s) { /*若栈s不为空,则返回栈顶元素*/ If(s->top<0) return NULL; /*栈空*/ return (s->stack[s->top]); }

29
算术表达式求值
在计算机中,任何一个表达式都是由: 操作数(operand)、运算符(operator)和 界限符(delimiter)组成的。 其中操作数可以是常数,也可以是变量或常量的 标识符;运算符可以是算术运算体符、关系运算符和 逻辑符;界限符为左右括号和标识表达式结束的结束 符。
30
6
存储结构
栈是一种特殊的线性表,有两种存储方式: 顺序存储结构存储
链式存储结构存储。


7
顺序栈的数组表示
与第二章讨论的一般的顺序存储结构的线性表 一样,利用一组地址连续的存储单元依次存放自 栈底到栈顶的数据元素,这种形式的栈也称为顺 序栈。 使用一维数组来作为栈的顺序存储空间。 设指针top指向栈顶元素的当前位置,以数组 小下标的一端作为栈底。 top=0时为空栈,元素进栈时指针top不断地 加1,当top等于数组的最大下标值时则栈满。
5)假如读出的运算符的优先级不大于运算符栈栈顶运算符
的优先级,则从操作数栈连续退出两个操作数,从运算符栈中 退出一个运算符,然后作相应的运算,并将运算结果压入操作 数栈。此时读出的运算符下次重新考虑(即不读入下一个符号 )。

第3章 栈和队列

第3章 栈和队列

例五、 表达式求值 例五、
限于二元运算符的表达式定义:
操作数) 运算符 运算符) 操作数 操作数) 表达式 ::= (操作数 + (运算符 + (操作数 操作数 操作数 ::= 简单变量 | 表达式 简单变量 :: = 标识符 | 无符号整数
表达式的三种标识方法: 表达式的三种标识方法: 设 Exp = S1 + OP + S2 则称 OP + S1 + S2 S1 + OP + S2 S1 + S2 + OP 为前缀表示法 前缀表示法 为中缀表示法 中缀表示法 为后缀表示法 后缀表示法
例如:(1348)10 = (2504)8 ,其 例如: 运算过程如下:
计 算 顺 序
N N div 8 N mod 8 1348 168 4 168 21 0 21 2 5 2 0 2
输 出 顺 序
void conversion () { InitStack(S); scanf ("%d",&N); while (N) { Push(S, N % 8); N = N/8; } while (!StackEmpty(S)) { Pop(S,e); printf ( "%d", e ); } } // conversion
栈和队列是两种常用的数据类型
3.1 栈的类型定义 3.2 栈的应用举例 3.3 栈类型的实现 3.4 队列的类型定义 3.5 队列类型的实现
3.1 栈的类型定义
ADT Stack { 数据对象: 数据对象 D={ ai | ai ∈ElemSet, i=1,2,...,n, n≥0 } 数据关系: 数据关系 R1={ <ai-1, ai >| ai-1, ai∈D, i=2,...,n } 约定an 端为栈顶,a1 端为栈底。 基本操作: 基本操作: } ADT Stack

数据结构 3.1栈和队列(顺序及链栈定义和应用)

数据结构 3.1栈和队列(顺序及链栈定义和应用)

假设从终端接受了这样两行字符: whli##ilr#e(s#*s) outcha@putchar(*s=#++);
则实际有效的是下列两行: while (*s) putchar(*s++);
例4:迷宫求解
通常用 “回溯 试探方 法”求 解
##########
# Q # $ $ $ #
#
# #$ $ $ # #
3.1 栈的类型定义
实例引进 考虑问题:一个死胡同,宽度只能够一辆车进 出,现有三辆汽车依次进入胡同停车,后A车 要离开,如何处理? 用计算机模拟以上问题
小花车
小明家 小花家 能能家 点点家 强强家
小花车
点点车 强强车
基本概念
栈(STACK) ——一种限定性的 数据结构,限定只能在表的一端 进行插入和删除的线性表。
# $ $ # #
#
## ##
##
# #
##
# # #
#
## # ## # # #
#
Q #
##########
求迷宫路径算法的基本思想
若当前位置“可通”,则纳入路径,继续( 向东)前进; 若当前位置“不可通”,则后退,换方向 继续探索; 若四周“均无通路”,则将当前位置从路 径中删除出去。
一 顺序栈
顺序栈存储的特点 顺序栈各个基本操作顺序实现 完整的顺序栈c语言程序 模拟停车场
一 顺序栈
存储特点
利用一组地址连续的存储单元依次存放 自栈底到栈顶的数据元素
c语言中可用数组来实现顺序栈
设置栈顶指针Top
elem[arrmax]
a1 a2 a3 a4
Top
top的值
elem[arrmax]

数据结构(C语言版CHAP3

数据结构(C语言版CHAP3

S.top
n+1 n n-1 i-1 i-2
0
e an ai ai-1 a1
STA作图示
S.top
S.top n n-1 i-1 i-2 S.base 0
an ai ai-1
n+1 n n-1 i-1 i-2
e an
ai ai-1 a1
STACK_INIT_SIZE
3.1 栈
二 栈的基本操作 1) 初始化操作InitStack((&S) 功能:构造一个空栈S; 2) 销毁栈操作DestroyStack(&S) 功能:销毁一个已存在的栈; 3) 置空栈操作ClearStack(&S) 功能:将栈S置为空栈; 4) 取栈顶元素操作GetTop(S, &e) 功能:取栈顶元素,并用e 返回; 5)进栈操作Push(&S, e) 功能:元素e进栈; 6)退栈操作Pop(&S, &e) 功能:栈顶元素退栈,并用e返回; 7)判空操作StackEmpty(S) 功能:若栈S为空,则返回True,否则返回False; 第 9 页
S.top
n n-1
an
i-1 i-2
1 0
ai ai-1
a2 a1
STACK_INIT_SIZE
S.base
S.stacksize
第 13 页
3.1 栈
当栈用顺序结构存储时, 栈的基本操作如建空栈、 进栈、出栈等操作如何实现?
第 14 页
3.1 栈
二 顺序栈基本操作的算法 1)初始化操作InitStack_Sq((SqStack &S)
a1
STACK_INIT_SIZE
S.base S.stacksize

栈的应用——表达式求值

栈的应用——表达式求值

栈的应⽤——表达式求值 表达式求值是程序设计语⾔编译中的⼀个基本问题,它的实现就是对“栈”的典型应⽤。

本⽂针对表达式求值使⽤的是最简单直观的算法“算符优先法”。

本⽂给出两种⽅式来实现表达式求值,⽅式⼀直接利⽤中缀表达式求值,需要⽤到两个栈,操作数栈和操作符栈。

⾸先置操作数栈为空栈,操作符栈仅有“#”⼀个元素。

依次读⼊表达式中的每个字符,若是操作数则进操作数栈,若是操作符则和操作符栈的栈顶运算符⽐较优先权作相应操作,直⾄整个表达式求值完毕。

⽅式⼆⾸先把中缀表达式转换为后缀表达式并存储起来,然后利⽤读出的后缀表达式完成求值,其本质上是⽅式⼀的分解过程。

表达式求值的代码如下:#include <iostream>#include "stack"#include "map"using namespace std;/* 只能求⼀位整数的加减乘除混合运算 */map<char, pair<int, int>> priority; // 存放各个操作符的栈内栈外优先级,first是栈内,second是栈外char infix[50]; // 存放初始的中缀表达式char postfix[50]; // 存放转化的后缀表达式int result;void MakePriority() // 构造运算符优先级表{priority.insert(make_pair('#', make_pair(0, 0))); // isp(#)=0, icp(#)=0priority.insert(make_pair('\n', make_pair(0, 0))); // isp(\n)=0, icp(\n)=0 表达式结尾的'#'⽤'\n'代替,这样可以省略表达式末尾的结束符'#'priority.insert(make_pair('(', make_pair(1, 6))); // isp(()=1, icp(()=6priority.insert(make_pair('*', make_pair(5, 4))); // isp(*)=5, icp(*)=4priority.insert(make_pair('/', make_pair(5, 4))); // isp(/)=5, icp(/)=4priority.insert(make_pair('%', make_pair(5, 4))); // isp(%)=5, icp(%)=4priority.insert(make_pair('+', make_pair(3, 2))); // isp(+)=3, icp(+)=2priority.insert(make_pair('-', make_pair(3, 2))); // isp(-)=3, icp(-)=2priority.insert(make_pair(')', make_pair(6, 1))); // isp())=6, icp())=1}void InfixToPostfix() // 把中缀表达式转换为后缀表达式{int i = 0;stack<char> optrStack; // 操作符栈char optr; // optr为栈顶的操作符optrStack.push('#');while (!optrStack.empty()){if (isdigit(infix[i])) // 是操作数则直接输出(追加到postfix结尾){postfix[strlen(postfix)] = infix[i];postfix[strlen(postfix) + 1] = '\0';i++; // 读⼊中缀表达式的下⼀个字符}else// 是操作符, ⽐较优先级{optr = optrStack.top(); // 取出栈顶操作符if (priority[infix[i]].second > priority[optr].first) // icp(infix[i]) > isp(optr),infix[i]⼊栈{optrStack.push(infix[i]);i++;}else if (priority[infix[i]].second < priority[optr].first)// icp(infix[i]) < isp(optr),optr退栈并输出{postfix[strlen(postfix)] = optr;postfix[strlen(postfix) + 1] = '\0';optrStack.pop();}else// icp(infix[i]) = isp(optr),退栈但不输出,若退出的是'(',则继续读⼊下⼀个字符{optrStack.pop();if (optr == '(')i++;}}}}void CalculateByPostfix() // 通过后缀表达式求值{int i = 0;stack<int> opndStack; // 操作数栈int left, right; // 左右操作数int value; // 中间结果int newOpnd;while (postfix[i] != '#' && i < strlen(postfix)){switch (postfix[i]){case'+':right = opndStack.top(); // 从操作数栈中取出两个操作数opndStack.pop();left = opndStack.top();opndStack.pop();value = left + right;opndStack.push(value); // 中间结果⼊栈break;case'-':right = opndStack.top();opndStack.pop();left = opndStack.top();opndStack.pop();value = left - right;opndStack.push(value);break;case'*':right = opndStack.top();opndStack.pop();left = opndStack.top();opndStack.pop();value = left * right;opndStack.push(value);break;case'/':right = opndStack.top();opndStack.pop();left = opndStack.top();opndStack.pop();if (right == 0){cerr << "Divide by 0!" << endl;}else{value = left / right;opndStack.push(value);}break;default:newOpnd = (int)(postfix[i] - 48); // 操作数直接⼊栈opndStack.push(newOpnd);break;}i++;}result = opndStack.top();}void CalculateByInfix() // 直接利⽤中缀表达式求值{int i = 0;stack<char> optrStack; // 操作符栈stack<int> opndStack; // 操作数栈char optr; // optr为操作符栈顶的操作符int left, right, value; // 左右操作数以及中间结果optrStack.push('#');optr = optrStack.top();while (!optrStack.empty()) // 直到操作符栈为空{if (isdigit(infix[i])) // 是操作数, 进操作数栈{value = (int)(infix[i] - 48);opndStack.push(value);i++;}else// 是操作符, ⽐较优先级{optr = optrStack.top(); // 取出操作符栈顶的操作符if (priority[infix[i]].second > priority[optr].first) // icp(infix[i]) > isp(optr),infix[i]⼊栈 {optrStack.push(infix[i]);i++;}else if (priority[infix[i]].second < priority[optr].first) // icp(infix[i]) < isp(optr),optr退栈并输出{optrStack.pop();right = opndStack.top(); // 从操作数栈中取出两个操作数opndStack.pop();left = opndStack.top();opndStack.pop();switch (optr){case'+':value = left + right;opndStack.push(value); // 中间结果⼊栈break;case'-':value = left - right;opndStack.push(value); // 中间结果⼊栈break;case'*':value = left * right;opndStack.push(value); // 中间结果⼊栈break;case'/':if (right == 0){cerr << "Divide by 0!" << endl;}else{value = left / right;opndStack.push(value);}break;default:break;}}else{optrStack.pop();if (optr == '(')i++;}}}result = opndStack.top();}int main(){MakePriority(); // 构造运算符优先级表cout << "请输⼊中缀表达式:";cin >> infix;cout << "直接利⽤中缀表达式求值为:";CalculateByInfix();cout << result << endl;cout << "转化为后缀表达式:";InfixToPostfix();for (int i = 0;i < strlen(postfix);i++){cout << postfix[i];}cout << endl;cout << "利⽤后缀表达式求值为:";CalculateByPostfix();cout << result << endl;return0;} 为了⽅便起见,本⽂只是简单的设计了⼀个针对⼀位整数的四则运算进⾏求值的算法,对于处理多位整数的四则运算,需要对本⽂接受输⼊的数据类型进⾏“升阶”,把字符数组换成字符串数组,将⼀个整数的多位数字存⼊⼀个字符串进⾏处理。

表达式求值(数据结构)(2023版)

表达式求值(数据结构)(2023版)

表达式求值(数据结构) 表达式求值(数据结构)1.引言1.1 目的1.2 背景1.3 范围2.表达式类型2.1 算术表达式2.1.1 运算符2.1.2 运算数2.2 逻辑表达式2.2.1 逻辑运算符2.2.2 逻辑运算数2.3 字符串表达式2.3.1 字符串连接运算符2.3.2 字符串操作函数3.表达式求值算法3.1 递归下降分析法3.2 栈表达式求值法3.2.1 中缀表达式转后缀表达式3.2.2 后缀表达式求值4.数据结构4.1 操作数栈4.2 运算符栈4.3 后缀表达式栈5.算法实现步骤5.1 输入表达式5.2 初始化栈5.3 处理表达式字符串5.4 根据算法选择相应的方法求值5.5 输出结果6.实例演示6.1 算术表达式求值示例6.2 逻辑表达式求值示例6.3 字符串表达式求值示例7.测试与验证7.1 正常表达式测试7.2 异常表达式测试7.3 性能测试8.总结与展望8.1 本文主要工作8.2 结果评估8.3 存在问题8.4 后续工作附件:附件1、算术表达式求值示例代码附件2、逻辑表达式求值示例代码附件3、字符串表达式求值示例代码法律名词及注释:1.递归下降分析法: 一种基于上下文无关文法进行递归分析的方法,用于处理表达式求值等问题。

2.栈表达式求值法: 使用栈数据结构进行表达式求值的方法。

3.中缀表达式: 常见的数学表达式写法,运算符位于运算数之间。

4.后缀表达式: 也称为逆波兰表达式,运算符位于运算数之后。

5.操作数栈: 用于存储表达式中的操作数的栈。

6.运算符栈: 用于存储表达式中的运算符的栈。

7.后缀表达式栈: 用于存储后缀表达式的栈。

栈及其应用

栈及其应用

• 思考题
– 如果要把后缀表达式转成中缀表达式,怎么做? – 如果利用上面的算法的框架?
构造算符优先关系队列表
+
+ * / ( ) @ > > > > < > <
> > > > < > <
*
< < > > < > <
/
< < > > < > <
(
< < < < < <
)
> > > > = >
@
> > > >
– 如果是数字(最小的子表达式),压栈 – 如果是运算符(和前面的子表达式一起,组成一个较大的子表达 式),从栈中弹出相应的分量,并计算结果。将结果压栈。
• 例如:3 5 + 2 *
– – – – 首先3,5入栈 然后处理+,3、5出栈,得到结果8(3 5 +),再入栈 2入栈 处理*,8,2出栈,得到结果(3 5 + 2 *)16,再入栈,完成。
栈的应用2:等价表达式
• 明明进了中学之后,学到了代数表达式。有一天, 他碰到一个很麻烦的选择题。这个题目的题干中 首先给出了一个代数表达式,然后列出了若干选 项,每个选项也是一个代数表达式,题目的要求 是判断选项中哪些代数表达式是和题干中的表达 式等价的。
• 这个题目手算很麻烦,因为明明对计算机编程很 感兴趣,所以他想是不是可以用计算机来解决这 个问题。假设你是明明,能完成这个任务吗?
需要注意的方面
• 这里还有一个小问题,注意到表达式中可以连续的出现幂 运算以及乘法运算。比如99^10^10^10^10…,如果直接用普 通的整型计算会溢出。我们可以选一个大素数,每次进行 一次运算,就对这个素数取一次余。而我们比较结果的时 候就是比较两个表达式的结果对这个大素数取余的值是不 是相同。 • 算法流程是: 随机取20个a值。 将每个值代入每个表达式,计算表达式对于某大素数取余 的结果。 如果20个值均相同则认为两个式子恒等,否则不恒等。 输出结果。

新编讲义对应的章 (5)

新编讲义对应的章 (5)
另一种存储方式为顺序存储
Q.front
Q.rear
头结点 队头
Q.front
Q.rear
∧ 空队列
∧ 队尾
链队列空: Q->front = Q->rear
Q.front
Q.rear
Q.fornt Q.rear
Q.front Q.rear
Q.front Q.rear
∧ 插入x (P62)
x∧
x
y∧
删除x (P62)
x
y∧
x进队列
开始
出队列
New(S)
S↑.data ← x S↑.next ← Λ
(Q↑.R)↑.next ← S
Q↑.R ← S 结束
开始
是 Q↑.F = Q↑.R
否 H←Q↑.F P←H↑.next
H↑.next ← P↑.next
队列已 结束 空,下溢
Q↑.R = P 是
Q↑.R ← H
否 Top←Top + 1
E(Top)←x 结束
是 上溢
出栈
开始 Top = 0
否 y←E(Top)
是 下溢
Top←Top - 1 结束
链栈
用动态方式来存储栈可节省空间 采用链表存储的栈为链栈

top
入栈和出栈就是表头结点的插入和删除操作
链栈为空: S->top=null
? 有链栈为满的情况出现么?
需要一个辅助桩y完成
Void hanoi( int n, char x, char y, char z)
{ if ( n == 1 )
Move(x,1,z)
Else{
hanoi( n-1, x, z, y); //将1到n-1的盘移到y, z为辅助桩

c语言运算符和表达式ppt课件

c语言运算符和表达式ppt课件
3,再赋给a。
例如: a+=3 等价于 a=a+3 x*=y+8 等价于 x=x*(y+8) x%=3 等价于 x=x%3
最新课件
26
是个整体
复合赋值运算表达式: 变量 双目运算符=表达式
注意:如果=右边是包含若干项的表达式,则相
当于它有括号。 步骤:
如: ① x %= y+3
1)左边变量的当前值与右边整个表达 式进行相应运算。
❖如果成立,则结果为逻辑值“真”,用整 数 “1”来表示;如:5>=5
❖如果不成立,则结果为逻辑值假”,用整 数“0”来表示。如:5<5
最新课件
29
§3.3 逻辑表达式
❖C语言提供的6种关系运算符:
运算符 名称
例子
>
大于
a>b
<
小于
a<b
==
等于
a==b
>=
大于等于 a>=b
<=
小于等于 a<=b
② 运算符操作的数据的个数。不同的运算符操 作的数据的个数不一定相同;根据运算符连 接运算对象的个数,一般分为单目运算符 (如++、--)、双目运算符(如* / %)和 三目运算符(如?:)。
最新课件
6
③ 运算符在整个运算符系统中的优先级。优 先级是指在运算对象的左右都有运算符时 运算的先后次序。运算对象先做优先级高 的运算。如:*/比+-优先级高。
❖表达式使用时应注意表达式的值及类型。 a. 不同类型的运算符所表示的表达式类型也是 不同的。表达式一般有算术表达式、赋值表达 式、关系表达式、逻辑表达式、逗号表达式、 条件表达式等表达式。 b. 表达式虽然有各种类型,但它总是有确定的 值的,根据运算符的优先级和结合性进行计算。
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

-
*/
(
)
#
+
>><<<>>
-
>><<<>>
*
>>>><>>
/
>>>><>>
(
<<<<<≒
)
>>>>
>>
#
<
<<<<
=
Precede: 判定运算符栈的栈顶运算符θ 1与读入的运算符θ 2之间
的优先关系的函数.
2
Operate: 进行二元运算aθ b的函数.
算术表达式求值过程(算法3.4)
OPND栈
3 3 3 37 37 372 35 35 15
输入字符
主要操作
3 * ( 7 - 2 ) # Push(OPND,’3’)
* ( 7 - 2 ) # Push(OPTR,’*’)
( 7 - 2 ) # Push(OPTR,’(’)
7 - 2 ) # Push(OPND,’7’)
- 2 ) # Push(OPTR,’-’)
OperandType EvaluateExpression()
{InitStack(OPTR); Push(OPTR, ‘#’);
InitStack(OPND); c = getchar();
While(c!=’#’ || GetTop(OPTR)!=’#’){ If(!In(c,OP)){ Push(OPND,c); c = getchar();} // 不是运算符则进栈
void hanoi(int n, char a, char b, char c)
{if (n==1) move(a,1,c);
else{ hanoi(n-1,a,c,b);

move(a,n,c);

hanoi(n-1,b,a,c);
} 6
}
3.4 队列
3.4.1抽象数据类型队列的定义
• 初始条件: 队列Q已经存在且非空。 • 操作结果: 用e返回队列Q中队头元素的值。10
队列的基本操作(之三)
2 ) # Push(OPND,’2’)
) # Operate(‘7’,’-‘,’2’)
) # POP(OPTR)
# Operate(‘3’,’*’,’5’)
# Return(GetTop(OPND))
4
hanoi塔问题
例:汉诺塔问题: 将a柱子上的盘移到 c柱,用 b柱放临时盘 要求:一次只能移动一个盘,大盘不可放于小盘上。
3.2 栈的应用举例 3.2.5 表达式求值
算符优先法:
4+2*3-10/5 = 4+6-10/5 = 10-10/5 =10-2 = 8 操作数(operand): 进OPND栈 操作符(operator): 进OPTR栈 界限符(delimiter):
1
算符间的优先关系:
θ1 θ2 +
队列(Queue): 先进先出(First In First Out)
• (缩写为FIFO)的线性表。 • 仅在队尾进行插入和队头进行删除操作的线性表。
队头(front): 线性表的表头端,即可删除端。
队尾(rear): 线性表的表尾端,即可插入端。
队头
对尾
a1 a2 a3 ...... an-1 an
else

switch(Precede(GetTop(OPTR),c)){

case ‘<’: // 栈顶元素优先权低

Push(OPTR,c); c = getchar();
break;

case ‘≒’: // 脱括号并接受下一个字符

Pop(OPTR,x); c = getchar();
break;


基本操作:
• InitQueue(&Q);
DestroyQueue (& Q);
• ClearQueue (& Q); QueueEmpty(Q);
• QueueLength(Q) ; GetHead(Q,&e);
• EnQueue (& Q,e); DeQueue (& Q,&e);
• QueueTraverse(Q ,visit ()) 8
出队列(Dequeque)
入队列(Enqueue) 7
队列的抽象数据类型
ADT Queue {

数据对象: (i=1,2,…,n,
D= n≥0)}
{ai
|
ai 属 于 Elemset,

数据关系: D,(i=2,3,…,n)}
R约1 定=an为{ 队<尾ai-,1a,a1i为>队|a头i-1。,ai

case ‘>’: // 退栈并将运算结果入栈

Pop(OPTR,theta); Pop(OPND,b); Pop(OPND,a);

Push(OPND,Operate(a,theta,b));
break;

default: printf(“Expression error!”); return(ERROR);
a
b
c
5
hanoi塔的递归算法
定义函数:movetower(n,a,c,b) n个盘a->c,b放临时盘
分三步:
movetower(n-1,a,b,c) 将n-1个盘从a->b, c放临时盘
movedisk(a,n,c)
将第n个盘从a->c
movetower(n-1,b,c,a) 将n-1个盘从b->c,a放临时盘

} // switch
} // while
return GetTop(OPND);
3
} // EvaluateExpression
对 算 术 表 达 式 3*(7-2) 求 值 .
步骤 1 2 3 4 5 6 7 8 9 10
OPTR栈 # # #* #*( #*( #*(#*(#*( #* #
9
队列的基本操作(之二)
QueueEmpty(Q)
• 初始条件: 队列Q已经存在。 • 操作结果: 若队列Q为空队列,则返回TURE;
否则返回FALSE。
QueueLength(Q)
• 初始条件: 队列Q已经存在。 • 操作结果: 返回队列Q中的数据e)
}ADT Queue
队列的基本操作(之一)
InitQueue (&Q)
• 操作结果:构造一个空的队列Q。
DestroyQueue (&Q)
• 初始条件: 队列Q已经存在。 • 操作结果: 销毁队列Q。
ClearQueue (&Q)
• 初始条件: 队列Q已经存在。 • 操作结果: 将队列Q重置为空队列。
相关文档
最新文档