表达式求值除了用文法实现之外(文法实现表达式求值看这里),还可以直接用栈,将中缀表达式转化为后缀表达式。然后再用求表达式的值就轻而易举了。
下面贴程序源码:(可能有点长:)
main.cpp
#include"stack.cpp"
#include"stack.h"
#include<iostream>
using namespace std;
/*
* 该函数有两个功能
* 1. 输入中缀表达式
* 2. 将中缀表达式转化为后缀表达式
* 形参为两个指针分别指向两个数组(一个储存数字,一个储存运算符)
* 返回值是数字和运算符的总个数(若转化出错,返回-1)
*/
int change(double *Darra,char *Carra)
{
int num = 0; //记录式子中数字和运算符总数
char ch; //暂时存储,输入字符
double dou; //暂时存储,输入数字
Stack<char> mychar; //存储运算符
bool wchar = false; //是否有非法字符
cout<<"请输入表达式(为了方便可以带空格),并以'='号结束:\n"<<endl;
while( cin>>ch, '='!=ch )
{
switch(ch)
{
case '0': case '5':
case '1': case '6':
case '2': case '7':
case '3': case '8':
case '4': case '9':
num++;
cin.putback(ch); //如果是数字,扔回去,用double型数据装
cin>>dou;
cout<<dou<<ends; //后缀表达式部分输出
Darra[num] = dou;
break;
case '+':
case '-':
case '*':
case '/':
while( (!mychar.Isempty()) && //栈非空
(mychar.Top()!='(') && //栈顶元素不是空括号
( (mychar.Top()=='*') || (mychar.Top()=='/') || (ch == '+') || (ch == '-') ) )
//栈顶运算符优先级不低于输入的运算符
//满足以上三个条件,将栈中元素全部弹出
{
num++;
cout<<mychar.Top()<<ends; //后缀表达式部分输出
Carra[num] = mychar.Top();
mychar.Pop();
}
mychar.Push(ch); //若不满足,则将出入运算符压入栈中
break;
case '(':
/*
* 尝试解决省略*的运算不成功
if('\0' == Carra[num] && num != 0)
{
num++;
cout<<'*'<<ends;
Carra[num] = '*';
}
*/
mychar.Push('('); //遇到开括号压入栈
break;
case ')':
if(mychar.Isempty()) //判断括号是否匹配
{
cout<<"\n\n有多余的')'..."<<endl;
return -1;
}
while(!mychar.Isempty()) //遇到闭括号,将栈中元素弹出
{
if('(' == mychar.Top()) //直至遇到开括号
{
mychar.Pop();
break;
}
else //如果栈为空,任然没有开括号,则执行弹出操作时,会出现错误,退出系统
{
num++;
cout<<mychar.Top()<<ends; //后缀表达式部分输出
Carra[num] = mychar.Top();
mychar.Pop();
}
}
break;
case ' ':
break;
default: //检测非法字符
wchar = true;
}
}
while(!mychar.Isempty()) //将栈中剩余运算符输出
{
if('(' == mychar.Top()) //括号不匹配
{
cout<<"\n\n有多余的'('..."<<endl;
return -1;
}
num++;
cout<<mychar.Top()<<ends; //后缀表达式部分输出
Carra[num] = mychar.Top();
mychar.Pop();
}
if(0 == num) //没有任何表达式输入
{
cout<<"\n\n您没有输入任何表达式..."<<endl;
return -1;
}
if(wchar)
{
cout<<"(字串中有非法字符)";
}
cout<<endl<<"\n以上为中缀表达式和相应的后缀表达式,";
return num;
}
/*
* 运算函数,将储存在数组中的符号和数字(后缀表达式)取出,计算成结果返回
* 形参: 储存有后缀表达式的两个数组首地址(此处若用栈,则后缀表达式从栈中输出时,其顺序完全反相),后缀表达式的长度
* 返回值: 后缀表达式的计算结果
*/
double Compute(char *Carra,double *Darra, int num)
{
int i = 1; //取后缀表达式的辅助变量
double d1,d2; //暂存栈中弹出的两个变量
Stack<double> Res; //运算栈,储存数字
while( i <= num )
{
if(Carra[i] == '\0') //如果i处是无效运算符,说明后缀表达式中,i处对应的应该是数字
{
Res.Push(Darra[i]); //数字入栈
}
else //如果是运算符
{
d1 = Res.Top();
Res.Pop();
d2 = Res.Top();
Res.Pop(); //从栈顶弹出两个数据进行计算
switch(Carra[i])
{
case '+':
Res.Push(d1+d2); //计算后压回栈
break;
case '-':
Res.Push(d2-d1);
break;
case '*':
Res.Push(d1*d2);
break;
case '/':
if(0 == d1)
{
cout<<"请注意分母不能为零..."<<endl;
system("pause");
exit(0);
}
Res.Push(d2/d1);
break;
default:
cout<<"(Compute)运算符匹配出错了..."<<endl;
exit(0);
}
}
i++;
}
return Res.Top(); //弹出栈中最后一个数字(计算结果)
}
int main()
{
int i;
double Darra[S_size]; //装入数据
char Carra[S_size]; //装入运算符
for(i=0; i<S_size; i++) //将储存运算符的数组做一个标记,以明确该下标所对应的是数字还是运算符
Carra[i] = '\0'; //若检测到Carra[i] = '\0',则说明Carra[i]中没有存入运算符,而Darra[i]中存储了一个数字
cout<<"************************* 一个简单表达式计算程序 *************************"<<endl;
cout<<" ——by HQ"<<endl;
cout<<"注意:请写全表达式,不要省略'*',写负数时请写成 '0 - x'的形式.\n"<<endl;
if( ( i = change(Darra,Carra) )== -1 ) //判断转换是否成功
{
cout<<"\n转换失败..."<<endl;
system("pause");
exit(0);
}
else
{
cout<<"其计算结果为:\n"<<endl;
cout<<Compute(Carra,Darra,i)<<endl; //计算并输出结果
}
system("pause");
return 0;
}
stack.cpp
/*
* 模板类(栈)的实现
*/
#ifndef Stack_cpp
#define Stack_cpp
#include"Stack.h"
template<class T>
Stack<T>::Stack()
{
top = -1;
}
template<class T>
bool Stack<T>::Isempty() // If the stack is empty, return true; otherwise return false.
{
if(-1 == top)
{
return true;
}
else
{
return false;
}
}
template<class T>
void Stack<T>::Pop() // Pop an element from the top of the stack
{
if(top == -1)
{
cout<<"弹出栈出错..."<<endl;
exit(0);
}
top--;
}
template<class T>
void Stack<T>::Push(T ele) // Push this element into the stack.
{
if(top > S_size)
{
cout<<"栈溢出..."<<endl;
exit(0);
}
top++;
elem[top] = ele;
}
template<class T>
T Stack<T>::Top() // Return the top element of the stack.
{
if(-1 == top)
{
cout<<"已至栈底..."<<endl;
//exit(0);
}
return elem[top];
}
template<class T>
int Stack<T>::Size() //Return the number of the elements in the stack.
{
return top;
}
template<class T> // clear all the elements in the stack
void Stack<T>::clear()
{
top = -1;
}
#endif
stack.h
/*
* 模板类(栈)
*/
#ifndef Stack_h
#define Stack_h
#define S_size 50 //the size of the stack
template<class T>
class Stack
{
public:
Stack();
void Pop(); // Pop an element from the top of the stack
void Push(T elem); // Push this element into the stack.
T Top(); // Return the top element of the stack.
bool Isempty(); // If the stack is empty, return true; otherwise return false.
int Size(); // Return the number of the elements in the stack.
void clear(); // clear all the elements in the stack
private:
T elem[S_size];
int top;
};
#endif
运行结果: