逆波兰表达式解决四则运算
&& 逆波兰表达式又叫做后缀表达式,它将复杂表达式转换为可以依靠简单的操作得到计算结果的表达式,解决了四则运算中括号改变运算符优先级的问题。
四则运算的表达式一般都是中缀表达式如 1+2*(3-4)+5,即操作符在两个操作数之间。四则运算需要两个步骤,一是把中缀表达式转为后缀表达式,二是由后缀表达生成结果
中缀表达式转为后缀表达式算法描述:
(1)首先有个包含中缀表达式元素列表sourceList,然后创建一个符号列表destList保存最终后缀表达式,创建一个操作符堆栈opStack
(2)从sourceList取出一个元素A
(3a)如是数字则加入到destList中
(3b)如果元素A是运算符,将操作符A与操作符堆栈opStack栈顶的运算符的优先关系相比较。如果,优先关系高于opStack栈顶的运算符,则将该运算符压入操作符堆栈opStack。倘若不是(低于或等于)的话,则将运算符栈opStack栈顶的运算符从栈中弹出保存到destList,重复此步骤,直到作符A压入操作符堆栈opStack。
(3c)若元素A是左括号&(&,则压入操作符堆栈opStack
(3d)若元素B是右括号&)&,则操作符堆栈opStack弹出操作符并加入到destList中,直到弹出左括号&(&。
(5)从步骤2重复上述操作,所有元素处理完毕后将操作符堆栈opStack弹出操作符并加入到destList中,这样中缀式表示的简单算术表达式转化为逆波兰表示的简单算术表达式。
中缀表达式如 1+2*(3-4)+5,构造元素列表1,+,2,*,(,3,-,4,),5,构造一个空最终后缀表达式destList,一个操作符堆栈opStack
1、取出“1”,destList【1】,opStack【】
2、取出“+”,destList【1】,opStack【+】
3、取出“2”,destList【1,2】,opStack【+】
4、取出“*”,destList【1,2】,opStack【+,*】
5、取出“(”,destList【1,2】,opStack【+,*,(】
6、取出“3”,destList【1,2,3】,opStack【+,*,(】
7、取出“-”,destList【1,2,3】,opStack【+,*,(,-】
8、取出“4”,destList【1,2,3,4】,opStack【+,*,(,-】
9、取出“)”,destList【1,2,3,4,-】,opStack【+,*】& //操作符堆栈opStack弹出操作符并加入到destList中,直到弹出左括号&(&
10、取出“+”,destList【1,2,3,4,-,*,+】,opStack【+】 //加号优先级不大于【+,*】
11、取出“5”,destList【1,2,3,4,-,*,+,5】,opStack【+】
12、处理完毕,destList【1,2,3,4,-,*,+,5,+】,opStack【】
后缀表达式到计算结果算法描述:
遍历储存后缀表达式的列表,将元素依次进栈,当遇到操作符时,连续出栈两个元素,进行运算,再将结果进栈,最后栈内留下的元素就是计算结果
后缀表达式destList【1,2,3,4,-,*,+,5,+】,结果堆栈resultStatck【】
输入--&:结果
[1,2,3,4]--&:resultStatck【1,2,3,4】
[-]--&:resultStatck【1,2,3-4】
[ * ]--&:resultStatck【1,2*(3-4)】
[+]--&:resultStatck【1+2*(3-4)】
[5]--&:resultStatck【1+2*(3-4),5】
[+]--&:resultStatck【1+2*(3-4)+5】
系统分类:&>>&数据结构练习题 004 栈 逆波兰表达式的计算_C++,C语言_ThinkSAAS
数据结构练习题 004 栈 逆波兰表达式的计算
数据结构练习题 004 栈 逆波兰表达式的计算
数据结构练习题 004 栈 表达式的计算——逆波兰用联合表达栈元素,是懒,不想写2次栈的实现代码。以空间换时间。
ExprStack.h
#ifndef EXPRSTACK_H
#define EXPRSTACK_H
#define DEFAULTSTACKSIZE
#define STACKINCREMENT
typedef union element_type_tag
} ELEMENTTYPE;
typedef struct stack_operator_tag
ELEMENTTYPE *
} STACKEXPR;
STACKEXPR *CreateStack(void);
void DestroyStack(STACKEXPR *p);
int PushElement(STACKEXPR *p, ELEMENTTYPE d);
int PopElement(STACKEXPR *p, ELEMENTTYPE *d);
int GetTopElement(STACKEXPR *p, ELEMENTTYPE *d);
ExprStack.c
#include &stdlib.h&
#include "ExprStack.h"
* 创建空栈
* 参数:无
* 返回值:栈指针
STACKEXPR *CreateStack(void)
STACKEXPR *p;
p = (STACKEXPR *)malloc(sizeof(STACKEXPR));
if(p == NULL)
return NULL;
p-&base = (ELEMENTTYPE *)malloc(sizeof(ELEMENTTYPE)*DEFAULTSTACKSIZE);
if(p-&base == NULL)
return NULL;
p-&top = 0;
p-&size = DEFAULTSTACKSIZE;
* 参数:p 栈指针
* 返回值:无
* 细节:释放栈内数据内存和栈内存
void DestroyStack(STACKEXPR *p)
if(p-&base)
free(p-&base);
* 参数:p 栈指针,d 入栈数据
* 返回值:成功返回 1,失败返回 0
* 细节:若栈满,则先增容。压数据入栈
int PushElement(STACKEXPR *p, ELEMENTTYPE d)
if(p == NULL || p-&base == NULL)
//栈满则增容
if(p-&top &= p-&size)
p-&base = (ELEMENTTYPE *)realloc(p-&base,
sizeof(ELEMENTTYPE)*(p-&size + DEFAULTSTACKSIZE));
if(p-&base == NULL)
p-&size += DEFAULTSTACKSIZE;
*(p-&base + p-&top) =
* 参数:p 栈指针,d 存放出栈数据的地址
* 返回值:成功返回 1,失败返回 0
int PopElement(STACKEXPR *p, ELEMENTTYPE *d)
if(p == NULL || p-&base == NULL || d == NULL || p-&top &= 0)
*d = *(p-&base + p-&top);
* 取栈顶元素值
* 参数:p 栈指针,d 存放栈顶数据的地址
* 返回值:成功返回 1,失败返回 0
int GetTopElement(STACKEXPR *p, ELEMENTTYPE *d)
if(p == NULL || p-&base == NULL || d == NULL || p-&top &= 0)
*d = *(p-&base + p-&top - 1);
ExprString.h
#ifndef EXPRSTRING_H
#define EXPRSTRING_H
int Infix2suffix(char *t, char *s);
int CalSuffix(char *s, double *r);
ExprString.c
#include &stdlib.h&
#include &string.h&
#include "ExprStack.h"
#include "ExprString.h"
int GetOptrLvl(char c);
int GetType(char c);
int Operate(double a, char c, double b, double *r);
* 判断字符类型
* 参数:c 字符
* 返回值:空格 5,左括号 4,右括号 3,运算符 2,数 1,其他 0
int GetType(char c)
if(c == & &)
else if(c == &(&)
else if(c == &)&)
else if(c == &+& || c == &-& || c == &*& || c == &/&)
else if((c &= &0& && c &= &9&) || c == &.&)
* 取得运算符等级
* 参数:c 字符
* 返回值:乘除 5,加减 3,左括号 1,其他 0
int GetOptrLvl(char c)
* 计算结果
* 参数:a b 操作数,c 操作符,r 计算结果
* 返回值:有效计算返回 1,无效计算返回 0
int Operate(double a, char c, double b, double *r)
if(b != 0)
//这里没有 break ,顺着 default 返回 0
* 中缀表达式转后缀表达式
* 参数:t 目标后缀表达式,s 源中缀表达式
* 返回值:成功 1,失败 0
* 细节:t 必须空间充足,后缀表达式各元素间以 空格 分割
int Infix2suffix(char *t, char *s)
STACKEXPR *p;
ELEMENTTYPE
int len, i,
if(!t || !s || (len = strlen(s)) & 1 || !(p = CreateStack()))
for(i=0; i& i++)
switch(GetType(s[i]))
//右括号:栈顶出栈,直至匹配到左括号
while(PopElement(p, &c) && c.optr != &(&)
*t++ = & &;
//操作符:+ - * /
//本操作符等级不高于栈顶操作符,出栈
while(GetTopElement(p, &c) && GetOptrLvl(s[i])&=GetOptrLvl(c.optr))
PopElement(p, &c);
*t++ = & &;
//这里没有 break,顺着直接进栈
//左括号:直接进栈
c.optr = s[i];
if(PushElement(p, c) == 0) goto ERROR;
//数字:直接进后缀表达式
*t++ = s[i++];
} while(GetType(s[i]) == 1);
// i 加多了一次,回退 1
*t++ = & &;
//空格:忽略
//非法字符
goto ERROR;
//栈内剩余操作符全部出栈
while(PopElement(p, &c))
if(c.optr == &(&) goto ERROR;
*t++ = & &;
DestroyStack(p);
DestroyStack(p);
* 计算后缀表达式的值
* 参数:s 后缀表达式, r 存放结果
* 返回值:成功 1,失败 0
int CalSuffix(char *s, double *r)
STACKEXPR *p;
ELEMENTTYPE
double a, b,
char t[256] = "";
int len, i,
if(!r || !s || (len = strlen(s)) & 1 || !(p = CreateStack()))
for(i=0; i& i++)
switch(GetType(s[i]))
//数字直接进栈
t[j++] = s[i++];
} while(GetType(s[i]) == 1);
t[j] = &