任何一个表达式都是由操作数、运算符、界限符组成的。这里讨论简单的加、减、乘、除四种运算符。我们在此把运算符和界限符统称运算符,将它们构成的集合命名为OP。
根据加减乘除的运算规则,在每一步运算中,设先出现的操作符为c1,在这个操作符之后出现的那一个字符为c2,下表定义了两个操作符之间的优先关系。(>表示c1优先权高于c2,=表示c1优先权等于c2,<表示c1的优先权小于c2。)
运算符间的优先关系(c1为左侧,c2为上侧)
c1 ,c2 | + | - | * | / | ( | ) | # |
---|---|---|---|---|---|---|---|
+ | > | > | < | < | < | > | > |
- | > | > | < | < | < | > | > |
* | > | > | > | > | < | > | > |
/ | > | > | > | > | < | > | > |
( | < | < | < | < | < | = | |
) | > | > | > | > | > | > | |
# | < | < | < | < | < | = |
为了将中缀表达式转化成后缀表达式,我们需要先设立一个OPTR工作栈来寄存运算符,初始化为空栈;用一个字符串s来寄存现有的转化一部分的表达式,初始化为空串。读入的表达式的末尾用’#‘表示。
具体步骤:
1.初始化OPTR为空栈,并将字符‘#’存入栈中作为栈底元素。
2.读入第一个字符ch,如果没有读到表达式的末尾’#‘或OPTR的栈顶元素不为’#‘时,则循环执行以下操作:
(1)ch若是操作数,则直接加入s,读取下一个ch。
(2)ch若是运算符,则比较OPTR的栈顶元素和ch的优先性,进行如下操作:
a.若是栈顶元素的优先性小于ch,则将ch压入OPTR栈,读取下一个ch。
b.若是栈顶元素的优先性大于ch,则弹出OPTR的栈顶元素,并将其加入字符串s。
c.若等于,则OPTR的栈顶元素是‘(’并且读入的ch是‘)’,这时相当于括号匹配成功,应直接弹出OPTR的栈顶元素‘(’,然后继续读入下一元素ch。
3.循环完成后,s即为转化后的后缀表达式。
以下为中缀表达式a/b+(c*d-e*f)/g转化成后缀表达式的表格:
步骤 | OPTR栈 | 字符串s | 读入字符 | 主要操作 |
---|---|---|---|---|
1 | # | a/b+(c*d-e*f)/g# | 'a'加入s | |
2 | # | a | /b+(c*d-e*f)/g# | push(OPTR,'/') |
3 | #/ | a | b+(c*d-e*f)/g# | 'b'加入s |
4 | #/ | ab | +(c*d-e*f)/g# | pop(OPTR,'/'),/加入s |
5 | # | ab/ | +(c*d-e*f)/g# | push(OPTR,'+') |
6 | #+ | ab/ | (c*d-e*f)/g# | push(OPTR,'(') |
7 | #+( | ab/ | c*d-e*f)/g# | 'c'加入s |
8 | #+( | ab/c | *d-e*f)/g# | push(OPTR,'*') |
9 | #+(* |
ab/c | d-e*f)/g# | 'd'加入s |
10 | #+(* | ab/cd | -e*f)/g# | pop(OPTR,'*'),*加入s |
11 | #+( | ab/cd* | -e*f)/g# | push(OPTR,'-') |
12 | #+(- | ab/cd* | e*f)/g# | 'e'加入s |
13 | #+(- | ab/cd*e | *f)/g# | push(OPTR,'*') |
14 | #+(-* | ab/cd*e | f)/g# | 'f'加入s |
15 | #+(-* | ab/cd*ef | )/g# | pop(OPTR,'*'),*加入s |
16 | #+(- | ab/cd*ef* | )/g# | pop(OPTR,'-'),-加入s |
17 | #+( | ab/cd*ef*- | )/g# | pop(OPTR,'(') |
18 | #+ | ab/cd*ef*- | /g# | push(OPTR,'/') |
19 | #+/ | ab/cd*ef*- | g# | 'g'加入s |
20 | #+/ | ab/cd*ef*-g | # | pop(OPTR,'/'),/加入s |
21 | #+ | ab/cd*ef*-g/ | # | pop(OPTR,'+'),+加入s |
22 | # | ab/cd*ef*-g/+ | # | return s |
具体代码如下(使用c++):
sqstack的类如下:
#pragma once
#define __SQ_STACK_H__
// ANSI C++标准库头文件
#include // 标准串操作
#include // 标准流操作
using namespace std;
#define DEFAULT_SIZE 100
// 顺序栈模板类
template
class SqStack
{
protected:
// 顺序栈的数据成员:
int top; // 栈顶指针
int maxSize; // 栈的最大容量
ElemType* data; // 元素存储空间
public:
// 顺序栈的方法声明及重载编译系统默认方法声明:
SqStack(int size = DEFAULT_SIZE); // 构造函数
virtual ~SqStack(); // 析构函数
int getLength() const; // 求栈的长度
bool isEmpty() const; // 判断栈是否为空
void clear(); // 将栈清空
void traverse(void (*Visit)(const ElemType&)) const; // 遍历栈
int push(const ElemType e); // 入栈
int getTop(ElemType& e) const; // 取顶元素
int pop(ElemType& e); // 出栈
SqStack(const SqStack& s); // 复制构造函数
SqStack& operator =(const SqStack& s); // 赋值语句重载
int gettop() { return top; }
};
template
SqStack::SqStack(int size) {
top = -1; //栈顶指针初始化为-1
maxSize = size;
data = new ElemType[size];
}
template
int SqStack::getLength() const {
return top + 1;
}
template
bool SqStack::isEmpty() const {
if (top == -1) return true;
else return false;
}
template
void SqStack::clear() {
delete data;
data = NULL;
top = -1;
}
template
void SqStack::traverse(void (*Visit)(const ElemType&)) const { //遍历
for (int i = 0; i <= top; i++) {
Visit(data[i]); //遍历表中每一个元素
}
}
template
int SqStack::getTop(ElemType& e) const {
if (top == -1) {
cout << "此栈为空,无法取栈顶元素!" << endl;
return 0;
}
else {
e = data[top]; //取栈顶元素
return 1;
}
}
template
int SqStack::push(const ElemType e) {
if (top == maxSize - 1) {
cout << "栈已满,无法入栈!" << endl;
return 0;
}
else {
top++;
data[top] = e;
}
}
template
int SqStack::pop(ElemType& e) {
if (top == -1) {
cout << "此栈为空,无法出栈!" << endl;
return 0;
}
else {
e = data[top];
top--;
return 1;
}
}
template
SqStack::SqStack(const SqStack& s) {
maxSize = s.maxSize;
top = s.top;
for (int i = 0; i <= s.top; i++) {
data[i] = s.data[i];
}
}
template
SqStack::~SqStack() { }
template
SqStack& SqStack::operator=(const SqStack& s) {
maxSize = s.maxSize;
top = s.top;
for (int i = 0; i <= s.top; i++) {
data[i] = s.data[i];
}
}
转化的函数:
#include
#include "sqstack.h""
#define DEFAULT_SIZE 100
using namespace std;
char precede(char c1, char c2);
void conversion();
void calculate();
char precede(char c1, char c2) { //比较c1和c2的优先性,返回‘<',‘>'或‘=’。
switch (c1) {
case '+':if (c2 == '+' || c2 == '-' || c2 == ')' || c2 == '#') return '>';
else return'<';
break;
case '-':if (c2 == '+' || c2 == '-' || c2 == ')' || c2 == '#') return '>';
else return'<';
break;
case '*':if (c2 == '(') return '<';
else return'>';
break;
case '/':if (c2 == '(') return '<';
else return'>';
break;
case '(':if (c2 == ')') return '=';
else if (c2 != '#') return'<';
break;
case ')':if (c2 != '(') return '>';
break;
case '#':if (c2 != ')' && c2 != '#') return '<';
else if (c2 == '#') return'=';
break;
}
}
void conversion() { //将中缀表达式转化成后缀表达式
SqStack OPTR; //先初始化一个字符栈
OPTR.push('#');
cout << "请输入一个中缀表达式:";
char c[100];
int k = 0;
while (k < 100 && (c[k] = getchar()) != '=') { //输入表达式
k++;
}
c[k] = '#';
c[k+1] = '\0';
int i = 0; //用i来表示ch的位置
char s[100];
int j = 0; //用j来表示s中下一步添加字符的位置
char ch = c[i]; //初始化ch为表达式的第一个字符
while (ch != '#' || OPTR.gettop() != 0) {
if (ch != '+' && ch != '-' && ch != '*' && ch != '/' && ch != '(' && ch != ')' && ch != '#') { //如果ch是操作数,直接加入s
s[j] = ch;
j++;
ch = c[++i];
}
else {
char e;
OPTR.getTop(e);
char pre = precede(e, ch);
if (pre == '<') {
OPTR.push(ch);
ch = c[++i];
}
else if (pre == '>') {
OPTR.pop(s[j]);
j++;
}
else if (pre == '=') {
char p;
OPTR.pop(p);
ch = c[++i];
}
}
}
s[j++] = '\0';
printf("%s", s);
}
int main() {
conversion();
return 0;
}
运行截图如下:
在计算后缀表达式的时候,可以设置一个int类型的栈,然后依次读取输入的表达式的每一个字符,如果遇到操作数,则直接将其转化为int类型然后进栈;如果遇到运算符,则从栈中取出两个数进行运算,再将运算结果入栈,代码如下。(sqstack同上):
void calculate() {
cout << "请输入想计算的后缀表达式:";
char s[100];
cin >> s;
SqStack stack; //初始化一个栈
int i = 0;
while (s[i] != '\0') {
if (s[i] != '+' && s[i] != '-' && s[i] != '*' && s[i] != '/') { //如果是操作数,则进栈
int a = s[i] - '0';
stack.push(a);
}
else { //如果是操作符,则取出栈顶两个元素进行计算,并将结果入栈
int b, a;
stack.pop(b);
stack.pop(a);
if (s[i] == '+') stack.push(a + b);
else if (s[i] == '-') stack.push(a - b);
else if (s[i] == '*') stack.push(a * b);
else stack.push(a / b);
}
i++;
}
int a;
stack.getTop(a);
cout << "计算结果为:" << a << endl;
}
运行截图如下: