表达式求值、表达式转二叉树

1、后序表达式求值:

后续表达式(逆波兰式)的特点:没有括号。

求值方法:

从前向后扫,

遇到操作数压栈;

遇到操作符,从栈中取出2个操作数运算,结果压栈。

最终栈中所剩的数为结果。

2、中序表达式求值
我们先来定义运算符的优先级:
(
+,-
*,/,%
从上到下依次升高
准备2个栈,一个专门存放运算符,另一个专门存放操作数。
1.遇到),那么退栈计算到(为止.结果压栈。
2.遇到运算数.那么压栈。
3.如果当前运算符优先级低于栈顶运算符.那么计算栈顶运算符并将结果压栈.
4.否则压栈.

计算带括号和浮点数的表达式:

#include<iostream>
#include<stack>
#include<string>
#include<cctype>
using namespace std;    

typedef string::size_type it;    

char Compare(char op,char ch)    //优先级比较
{
    if((op=='#'&&ch=='#')||(op=='('&&ch==')')) return '=';
    if(ch=='#') return '<';
    if(op=='#') return '>';
    if(op=='(') return '>';
    if(ch==')') return '<';
    if(ch=='(') return '>';
    if(ch=='*'||ch=='/')
    if(op=='+'||op=='-') return '>';
    else return '<';
    if(ch=='+'||ch=='-') return '<';
}    

void modify(string& s)   //优化表达式
{
    string s1="()+-*/";
    for(it i=0;i<s.size();++i)
    {
        if(isspace(s[i])) s.erase(i,1);
        if(!isdigit(s[i])&&s[i]!='.'&&s1.find(s[i])==string::npos) s.erase(i,1);
        if(s[i]=='('&&s[i+1]=='-') s.insert(i+1,"0");
        if(i==0&&s[i]=='-') s.insert(i,"0");
    }
}    

bool check(const string & s)    //检验输入表达式
{
    string s1="()+-*/";
    string s2="+-*/";
    stack<char> ch;
    bool valid=true;
    for(it i=0;i<s.size();++i)
    {
        if(i==0 && s1.find(s[i],1)!=string::npos) return false;
        switch(s[i])
        {
        case '(':
            if(s1.find(s[i+1],1)!=string::npos) return false; break;
        case ')':
            if(s2.find(s[i-1])!=string::npos) return false; break;
        case '+':
        case '-':
        case '*':
        case '/':
            if(s2.find(s[i+1])!=string::npos) return false; break;
        }
        if (s[i]=='(') ch.push(s[i]);
        if (s[i]==')')
            if (ch.empty())
            {
                valid=false;
                break;
            }
            else
            {
                char b=ch.top(); ch.pop();
                if (b=='(') valid=true;
                else valid=false;
            }
    }
    if (!ch.empty()) valid=false;
    return valid;
}    

void Calculate(stack<double>& num,stack<char>& ops,const string & s)
{
    string s1="()+-*/#";
    it i=0;
    while(i<s.size())
    {
        it j=s.find_first_of(s1,i);
        if(j!=string::npos)
        {
            if(j!=i)
            {
                string s2=s.substr(i,j-i);
                double n=atof(s2.c_str());
                num.push(n);
            }
            char ch=s[j];
            char op=ops.top();
            if(Compare(op,ch)=='>') ops.push(ch);
            else if(Compare(op,ch)=='=') ops.pop();
            else
            {
                while(1)
                {
                    char c=ops.top();
                    if(Compare(c,ch)=='>') { ops.push(ch); break; }
                    else if(Compare(c,ch)=='=') { ops.pop(); break; }
                    else
                    {
                        char optr=ops.top();
                        ops.pop();
                        double n1=num.top();
                        num.pop();
                        double n2=num.top();
                        num.pop();
                        double value;
                        if(optr=='+') value=n2+n1;
                        if(optr=='-') value=n2-n1;
                        if(optr=='*') value=n2*n1;
                        if(optr=='/')
                        {
                            double E=0.00001;
                            if( n1>-E && n1<E )
                            {
                                cout<<"Can't evaluate the expression !";
                                exit(1);
                            }
                            else value=n2/n1;
                        }
                        num.push(value);
                    }
                }
            }
        }
        i=j+1;  //更新i的值
    }
}
int main()
{
    stack <double> num;
    stack <char> ops;
    ops.push('#');
    string s;  

    cout<<"Input the string:"<<endl;
    getline(cin,s);
    modify(s);
    while(!check(s))
    {
        cout<<"The string is not valid. Input it again! "<<endl;
        getline(cin,s);
        modify(s);
    }
    cout<<s<<endl;
    s=s+"#";    

    Calculate(num,ops,s);
    cout<<"The result is "<<num.top();    

    return 0;
}   

将中序表达式转换成后序表达式(逆波兰表达式)的算法:
(1)初始化一个空的运算符栈
(2)在没有到达中缀表达式的结尾及没有发生错误的时候,执行以下步骤:
 1.获取表达式中的一个标记(常数、变量、算术运算符,左括号,右括号)。
 2.如果标记是:
   i.  一个左括号,将其压入栈中
   ii. 一个右括号,连续弹出并显示栈中的元素,直到遇到一个左括号,不要显示这个左括号。(如果直到栈为空还没遇到一个左括号,则是一个错误)
   iii.一个运算符,如果栈为空,或者标记具有比栈顶元素更高的优先级,则将其压入栈中。否则出并显示栈顶的元素,接着继续比较标记和新的栈顶元素。(运算符比左括号的优先级高)
   iv 一个操作数,显示它
(3)当到达中缀表达式的结尾时,弹出并显示栈中的元素直到栈为空为止。

参考代码:

//将表达式转化为逆波兰表达式
string RPN(const string& exp)
{
    char token,toptoken;
    stack<char> oper;
    string RPNexp;
    int length=exp.length();
    for(int i=0;i<length;++i)
    {
        token=exp[i];
        switch(token)
        {
        case' ': break;
        case'(':
            oper.push(token);
            break;
        case')':
            while(1)
            {
                assert(!oper.empty());
                toptoken=oper.top(); oper.pop();
                if(toptoken=='(') break;
                RPNexp+=toptoken;
            }
            break;
        case'+':
        case'-':
        case'*':
        case'/':
            while(1)
            {
                if(oper.empty()||oper.top()=='('||
                    (token=='*'||token=='/')&&(oper.top()=='+'||oper.top()=='-'))
                {
                    oper.push(token);
                    break;
                }
                else
                {
                    toptoken=oper.top();
                    oper.pop();
                    RPNexp+=toptoken;
                }
            }
            break;
        default:RPNexp+=token;
        }
    }
    while(1)
    {
        if(oper.empty()) break;
        toptoken=oper.top();
        oper.pop();
        if(toptoken!='(')
            RPNexp+=toptoken;
        else
        {
            cout<<"***Error in infix expression!***\n";
            break;
        }
    }
    return RPNexp;
}    

//计算逆波兰表达式的值
int calculate(const string& exp)
{
    string s="+-*/";
    stack<int> num;
    int num1,num2,value;
    int length=exp.length();
    for(int i=0;i<length;++i)
    {
        if(s.find(exp[i])==string::npos) num.push(exp[i]-48);
        else
        {
            if(num.size()<2)
            {
                cout<<"Error in infix expression!\n";
                exit(0);
            }
            num1=num.top(); num.pop();
            num2=num.top(); num.pop();
            if(exp[i]=='+') value=num2+num1;
            if(exp[i]=='-') value=num2-num1;
            if(exp[i]=='*') value=num2*num1;
            if(exp[i]=='/')
            {
                if(num1==0)
                {
                    cout<<"Can't evaluate the expression !";
                    exit(1);
                }
                else value=num2/num1;
            }
            num.push(value);
        }
    }
    return num.top();
}    

字符串表达式转化为二叉树:

//表达式转二叉树的源代码
#include<iostream>
#include<stack>
#include<string>
using namespace std;  

class Node
{
public:
    char oper;//操作数或运算符
    Node *left;//左子树
    Node *right;//右子树
    Node():left(NULL),right(NULL),oper(0){}
    Node(char op):left(NULL),right(NULL),oper(op){}
};  

//判断是否为运算符
bool isOper(char op)
{
    char oper[]={'(',')','+','-','*','/'};
    for(int i=0;i<strlen(oper);i++)
    {
        if(op==oper[i])
            return true;
    }
    return false;
}  

//求运算符的优先级
int getOperPri(char op)
{
    switch(op)
    {
        case '(':
        return 1; break;
        case '+':
        case '-':
        return 2; break;
        case '*':
        case '/':
        return 3; break;
        default:
        return 0;
    }
}  

//销毁二叉树
void freeTree(Node*& p)
{
    if(p->left != NULL)
        freeTree(p->left);
    if(p->right != NULL)
        freeTree(p->right);
    delete(p);
}  

//递归先序遍历
void preOrderTraverse(Node *p)
{
   if(p!=NULL)
   {
       cout<<p->oper;
       preOrderTraverse(p->left);
       preOrderTraverse(p->right);
   }
}  

//中序遍历
void inOrderTraverse(Node *p)
{
    if(p)
    {
        if(p->left)
        {
            if(isOper(p->left->oper)&&getOperPri(p->left->oper)<getOperPri(p->oper))
            {
                cout<<"(";
                inOrderTraverse(p->left);
                cout<<")";
            }
            else
            inOrderTraverse(p->left);
        }
        cout<<p->oper;
        if(p->right)
        {
            if(isOper(p->right->oper)&&getOperPri(p->right->oper)<=getOperPri(p->oper))
            {
                cout<<"(";
                inOrderTraverse(p->right);
                cout<<")";
            }
            else
            inOrderTraverse(p->right);
        }
    }
}  

//表达式生成二叉树
void generateTree(Node*& p, string expr)
{
    stack <char> operStack;
    stack <Node*> dataStack;
    char tmpchr,c;
    int idx=0;
    tmpchr=expr[idx++];
    while(operStack.size()!=0 || tmpchr!='\0')
    {
        if(tmpchr!='\0' && !isOper(tmpchr))//不是运算符,则进操作数的栈
        {
            p=new Node(tmpchr);
            dataStack.push(p);
            tmpchr=expr[idx++];
        }
        else
        {
            switch(tmpchr)
            {
            case '('://进栈
                operStack.push('(');
                tmpchr=expr[idx++];
                break;
            case ')'://脱括号
                while(true)
                {
                    c=operStack.top();
                    operStack.pop();
                    if(c=='(')
                    {
                        break;
                    }
                    p=new Node(c);
                    if(dataStack.size())
                    {
                        p->right=dataStack.top();
                        dataStack.pop();
                    }
                    if(dataStack.size())
                    {
                        p->left=dataStack.top();
                        dataStack.pop();
                    }
                    dataStack.push(p);
                }
                tmpchr=expr[idx++];
                break;
            default:
                if(operStack.size()==0 || tmpchr!='\0' && getOperPri(operStack.top())< getOperPri(tmpchr))
                {//进栈
                    operStack.push(tmpchr);
                    tmpchr=expr[idx++];
                }
                else
                {//出栈
                    p=new Node(operStack.top());
                    p->oper=operStack.top();
                    if(dataStack.size())
                    {
                        p->right=dataStack.top();
                        dataStack.pop();
                    }
                    if(dataStack.size())
                    {
                        p->left=dataStack.top();
                        dataStack.pop();
                    }
                    dataStack.push(p);
                    operStack.pop();
                }
                break;
            }
        }
    }
    p=dataStack.top();
    dataStack.pop();
}  

int main()
{
   string expression;
   Node* tree;  

   cout<<"请输入字符串表达式:";
   cin>>expression;
   generateTree(tree,expression);  

   cout<<"前缀表达式为:";
   preOrderTraverse(tree);
   cout<<endl;  

   cout<<"中缀表达式为:";
   inOrderTraverse(tree);
   cout<<endl;  

   freeTree(tree);
   cout<<endl;  

   return 0;
}  

 

作者:阿凡卢

出处:http://www.cnblogs.com/luxiaoxun/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

http://www.cnblogs.com/luxiaoxun/archive/2012/08/04/2622800.html

时间: 2024-10-27 05:36:03

表达式求值、表达式转二叉树的相关文章

MYSQL表达式求值和MYSQL类型转换

    2.4 表达式求值和类型转换    MySQL允许编写包括常量.函数调用和表列引用的表达式.这些值可利用不同类型的运算符进行组合,诸如算术运算符或比较运算符.表达式的项可用圆括号来分组.表达式在SELECT 语句的列选择列表和WHERE 子句中出现得最为频繁,如下所示:    所选择的每列给出了一个表达式,如WHERE 子句中所示的那样.表达式也出现在DELETE 和UPDATE语句的WHERE 子句中,以及出现在INSERT 语句的VALUES( ) 子句中.    在MySQL遇到一

后缀表达式求值及校验

摘要: 本程序是一个完整的后缀表达式计算,主要用栈的操作实现,本程序封装了CStack类实现栈的操作,本程序最大的特色在于运用动态监视表达式的算法对表达式进行数据校验,对一切合法的表达式进行计算,检验出所有任何非法表达式并提示. 关键字:后缀表达式,校验 题目:后缀表达式求值. 要求:输入后缀表达式,输入为整数和四则运算,输出计算结果. 例如: 输入:2 3 * 1 - 输出:5 分析:2*3-1=5 输入:1 2 + 5 4 * 3 - * 6 - 输出:45 分析:(1+2)*(5*4-3)

C#算术表达式求值

算术表达式求值是一个经典的问题,很多学习编程的人都对此不陌生.本来我并不想写一个算术表达式求值的算法.在网上我看到了一篇文章,名叫<快速精确的对数学表达式求值>( http://www-128.ibm.com/developerworks/cn/java/j-w3eva/ ).才有兴趣着一个玩玩.写来写去,觉得真得很经典.所以把我写的代码拿出来让大家看看吧.因为时间较紧.所以变量名没有做得很规范. w3eavl是用JAVA写得,我用C#把它重写了一下.基本上能用,只是三角函数/反三角函数/双曲

网易游戏开发笔试题:lisp表达式求值

一.文章来由 按照惯例有这个section,但是木有什么可写的,一道笔试题而已~~~ 二.lisp表达式求值 题目如下: 分析: 初看题目,这就是一道很简单的ACM字符处理题,有点类似中缀表达式求值.但是字符题非常需要细心,一不小心就出错,我的实现是用的栈实现,而且只用了一个栈,所以实现起来,要处理字符和括号,还有操作符,捉襟见肘...应该直接用两个栈实现,一个存操作数,一个存操作符,这样就方便了~~ 上代码: #include <iostream> #include <string&g

bug-这是我写的表达式求值,在编译器中运行是对的,但在刷题系统中却说是错,求打什么呢帮我找找Bug

问题描述 这是我写的表达式求值,在编译器中运行是对的,但在刷题系统中却说是错,求打什么呢帮我找找Bug 2C #include""stdio.h""#include""stdlib.h""#include""malloc.h""#include""string.h""#include""math.h""#de

如何应用堆栈的思想实现表达式求值?

问题描述 如何应用堆栈的思想实现表达式求值?例:输入(3*(1+2-3)*4)输出结果! 解决方案 解决方案二:这个是典型的数据结构的问题数据结构书上面都会有这样的先把上述的表达式转换为"后缀表达式"312+3-*4*数字全部压入栈:碰到运算符,在栈中提取最上面两个数字,做运算,然后放回栈当栈中没有数据的时候,运算完成大清早的脑子还混乱,不知有没有大漏洞解决方案三:恩--谢谢你啊!以后有问题请多多指教

关于c++表达式求值的一些问题,求大神解答

问题描述 关于c++表达式求值的一些问题,求大神解答 看完裘老师的这篇关于表达式求值的帖子C/C++表达式求值.有个地方不明白. 有这样一句话 看下面例子:(a + b) * (c + d) fun(a++, b, a+5) 这里"*"的两个运算对象中哪个先算?fun及其三个参数按什么顺序计算?对第一个表达式,采用任何计算顺序都没关系,因为其中的子表达式都是引用透明的.第二个例子里的实参表达式出现了副作用,计算顺序就非常重要了.少数语言明确规定了运算对象的计算顺序(Java规定从左到右

问题求助 数据结构-使用双栈实现中缀表达式求值一个字符栈一个数字栈

问题描述 使用双栈实现中缀表达式求值一个字符栈一个数字栈 程序写好没输出啊,急求啊......主要BUG 在Nibolansuanfa()这个自定义函数里面前面的可以忽略..... /*核心函数*/ double Nibolansuanfa(char *str,stack *s) { initstack(&s);//初始化栈 char st[20],tc,xy;//st[20]里面放数字字符串 int j=0,i=0,yxcount=0; double d; while(str[j]!='')

c语言栈-栈的问题,用栈编写一个算术表达式求值

问题描述 栈的问题,用栈编写一个算术表达式求值 用栈做一个简单的算术运算,我觉得思想没问题,可是编译不过去,上网找了很多资料,觉得是栈的基本操作有问题,初始化有问题,可具体是什么错误我也不是很了解,求大神指教!! #include #include typedef struct { int data[100]; int top1; }SqStack1; typedef struct { char suanfu[100]; int top2; }SqStack2; SqStack1 shuzi;