• 数据结构 栈的应用 --表达式求值


    一: 中缀表达式求值 

    思想:

    需要2个栈,运算对象栈OPND,运算符栈OPTR,

    1:将栈OPND初始化为空,栈OPTR初始化为表达式的定界符#

    2:扫描表达式,直到遇到结束符#

      2.1:当前字符是运算对象,入栈OPND

      2.2:当前字符是运算符且优先级比栈OPTR的栈顶运算符优先级高,入栈OPTR,处理下一个字符

      2.3:当前字符是运算符且优先级比栈OPTR的栈顶运算符优先级低,则从栈OPND出栈2个运算对象,从栈OPTR出栈一个运算符进行运算,并将运算结果入栈OPND,处理当前字符

      2.4:当期字符是运算符且优先级与栈OPTR的栈顶运算符的优先级相同,将栈OPTR的栈顶运算符出栈,出理下一个字符。

    3:输出栈OPND中的栈顶元素,即运算结果

    //expseqstack.h
    //10只是示例性的数据,可以根据实际问题具体定义
    const int StackSize=10;  
    typedef struct
    {
    	char op;
    	int inputprecedence;
    	int stackprecedence;
    }DataType1;
    
    template <class T>       //定义模板类SeqStack
    class SeqStack
    {
    public:
        SeqStack();            //构造函数,栈的初始化
    	~SeqStack();            //析构函数
    	void init();
        void Push(T x);          //将元素x入栈
        T Pop();                //将栈顶元素弹出
        T GetTop();	         //取栈顶元素(并不删除)
    	bool Empty();           //判断栈是否为空
    public:
        T data[StackSize];      //存放栈元素的数组
        int top;                //栈顶指针,指示栈顶元素在数组中的下标
    };
    
    /*
     * 前置条件:栈不存在
     * 输    入:无
     * 功    能:栈的初始化
     * 输    出:无
     * 后置条件:构造一个空栈
     */
    
    template <class T>
    SeqStack<T>::SeqStack()
    {
    	top=-1;
    }
    
    /*
     * 前置条件:栈已存在
     * 输    入:无
     * 功    能:销毁栈
     * 输    出:无
     * 后置条件:释放栈所占用的存储空间
     */
    
    template <class T>
    SeqStack<T>::~SeqStack()
    {
    
    } 
    
    template <class T>
    void SeqStack<T>::init()
    {
    	top=0;
    } 
    
    /*
     * 前置条件:栈已存在
     * 输    入:元素值x
     * 功    能:在栈顶插入一个元素x
     * 输    出:如果插入不成功,抛出异常
     * 后置条件:如果插入成功,栈顶增加了一个元素
     */
    
    template <class T> 
    void SeqStack<T>::Push(T x)
    {
        if (top== StackSize-1) throw "上溢";
        top++;
        data[top]=x;
    }
    
    /*
     * 前置条件:栈已存在
     * 输    入:无
     * 功    能:删除栈顶元素
     * 输    出:如果删除成功,返回被删元素值,否则,抛出异常
     * 后置条件:如果删除成功,栈顶减少了一个元素
     */     
    
    template <class T>
    T SeqStack<T>::Pop()
    { 
        T x;
        if (top==-1) throw "下溢";
        x=data[top--];
        return x;
    }
    
    /*
     * 前置条件:栈已存在
     * 输    入:无
     * 功    能:读取当前的栈顶元素
     * 输    出:若栈不空,返回当前的栈顶元素值
     * 后置条件:栈不变
     */
    
    template <class T> 
    T SeqStack<T>::GetTop()
    {
    	if (top!=-1)  
        return data[top];
    }
    
    /*
     * 前置条件:栈已存在
     * 输    入:无
     * 功    能:判断栈是否为空
     * 输    出:如果栈为空,返回1,否则,返回0
     * 后置条件:栈不变
     */
    
    template <class T> 
    bool SeqStack<T>::Empty()
    {
    	if(top==-1) return 1;
    	else return 0;
    } 
    

      

    //main.cpp
    #include"expseqstack.h"
    #include<iostream>
    #include<string>
    using namespace std;
    
    //检查符号之间的优先级,1表示>,0表示=,-1表示<,c1栈内的运算,c2栈外的运算  
    int check(char c1, char c2)  
    {  
        int a1, a2;  
        if (c1 == '+' || c1 == '-')  
            a1 = 3;  
        if (c1 == '*' || c1 == '/')  
            a1 = 5;  
        if (c1 == '(')  
            a1 = 1;  
        if (c1 == ')')  
            a1 = 7;  
        if (c1 == '#')  
            a1 = 0;  
      
        if (c2 == '+' || c2 == '-')  
            a2 = 2;  
        if (c2 == '*' || c2 == '/')  
            a2 = 4;  
        if (c2 == '(')  
            a2 = 6;  
        if (c2 == ')')  
           a2 = 1;  
        if (c2 == '#')  
            a2 = 0;  
      
        if (a1 > a2)  
            return 1;  
        if (a1 == a2)  
            return 0;  
        if (a1 < a2)  
            return -1;  
    }  
      
    //符号运算函数  
    double sum(char c, double d1, double d2)  
    {  
        switch (c)  
        {  
        case '+':  
            return d1 + d2;  
            break;  
        case '-':  
            return d1 - d2;  
            break;  
        case '*':  
            return d1 * d2;  
            break;  
        case '/':  
            return d1 / d2;  
           break;  
        default:  
            break;  
        }  
    }  
      
    int main()  
    {  
       char *op = "+-*/()#";  
        string str;  
        cout<<"请输入表达式:"<<endl;
    	cin>>str;  
    	
       //给表达式字符串str添加‘#’结束标志符  
        str.append(1, '#');  
        SeqStack<char> OPTR;//运算符栈  
       SeqStack<double> OPND;//操作数栈  
        int a = -1;  
        //先将'#'入栈  
       OPTR.Push('#');  
        while (true)  
       {  
            int b = a + 1;  
            a = str.find_first_of(op, a + 1);  
            if (a == string::npos)  
               break;  
            if (a != b)  
           {  
                string ss(str, b, a - b);  
                double d = atof(ss.c_str());  
                //数据先入栈  
                OPND.Push(d);  
            }  
            //运算符优先级比较  
            char val;  
            val=OPTR.GetTop();  
            int che = check(val, str[a]);  
              if (-1 == che)//栈外优先级大直接入栈  
              {  
                  OPTR.Push(str[a]);  
              }  
              if (0 == che)//栈内外优先级相等则出栈  
              {  
                  OPTR.Pop();  
              }  
              if (1 == che)//栈内优先级大,出栈进行运算  
              {  
                  char val;  double d1;    double d2;  
                  val=OPTR.GetTop();  
                  
                  d1=OPND.GetTop();  
                  d1=OPND.Pop();  
                
                  d2=OPND.GetTop();  
                  d2=OPND.Pop();  
                  d1 = sum(val, d2, d1);  
                  //运算结果入栈  
                  OPND.Push(d1);  
                  OPTR.Pop();  
                  a--;  
              }  
        }  
        double s;  
        s=OPND.GetTop();  
        cout <<s<<endl;  
        return 0;  
    }  
    

      二:中缀表达式转后缀表达式并求值

    中缀表达式转后缀表达式思想:

    1:栈S初始化为空栈

    2:扫描表达式的每个字符,

      2.1:当前字符是运算对象,输出此字符,处理下一个字符

      2.2:当前字符是运算符且优先级比栈S的栈顶的运算符优先级高,此字符入栈S,处理下一个字符

      2.3:当前字符是运算符且优先级比栈S的栈顶的运算符优先级低,则将栈S的栈顶元素弹出并输出

      2.4:当前字符是运算符且优先级比栈S的栈顶的运算符优先级相同,则将栈S的栈顶元素弹出,处理下一个字符

    注:只有遇到 ) 的情况下,才弹出  (  ,但不输出。

    例子:中缀表达式 3*(4+2)/2-5     ====>>后缀表达式3 4 2 + * 2 / 5 -

    3  后缀表达式求值:

      1:初始化栈S

      2:扫描当前表达式

        2.1当前字符是运算对象,则入栈S,处理下一个字符

        2.2当前字符是运算符,则从栈S出栈2个运算对象,执行运算并将结果入栈S,处理下一个字符

      3:输出栈S的栈顶元素,就是表达式结果。

    //头文件 PrefixToPostfix.h
    #include <vector>  
    using namespace std;  
    
    bool isoperator(char op);                         // 判断是否为运算符  
    int priority(char op);                            // 求运算符优先级  
    void postfix(char pre[] , char post[],int &n);    // 把中缀表达式转换为后缀表达式  
    double read_number(char str[],int *i);            // 将数字字符串转变成相应的数字  
    double postfix_value(char post[]);                // 由后缀表达式字符串计算相应的中值表达式的值   
    //PrefixToPostfix.cpp
    
    #include "PrefixToPostfix.h"  
    #include"expseqstack.h"
    #include <iostream>  
    using namespace std;  
    
    bool isoperator(char op)  
    {  
       switch(op)  
        {  
        case '+':  
        case '-':  
        case '*':  
        case '/':  
            return 1;  
        default :   
            return 0;  
       }  
    }  
      
    int priority(char op)  
    {  
       switch(op)  
        {  
        case '#':  
            return -1;  
        case '(':  
            return 0;  
        case '+':  
        case '-':  
            return 1;  
        case '*':  
        case '/':  
            return 2;  
        default :  
           return -1;  
        }  
    } 
    
    //   把中缀表达式转换为后缀表达式,返回后缀表达式的长度(包括空格)  
    void postfix(char pre[] ,char post[],int &n)  
    {  
        int i = 0 ,j=0;  
        SeqStack<char> stack;  
        stack.init();       // 初始化存储操作符的栈  
      
        stack.Push('#');    // 首先把结束标志‘#’放入栈底  
      
        while(pre[i]!='#')  
        {  
            if((pre[i]>='0' && pre[i] <='9')||pre[i] =='.') // 遇到数字和小数点直接写入后缀表达式  
            {  
                post[j++] = pre[i];  
                n++;  
            }  
            else if (pre[i]=='(')   // 遇到“(”不用比较直接入栈  
                stack.Push(pre[i]);  
            else if(pre[i] ==')')  // 遇到右括号将其对应左括号后的操作符(操作符栈中的)全部写入后缀表达式  
            {  
                while(stack.GetTop()!='(')  
               {  
                   post[j++] = stack.Pop();  
                   n++;  
                }  
               stack.Pop(); // 将“(”出栈,后缀表达式中不含小括号  
            }  
           else if (isoperator(pre[i]))  
            {  
                post[j++] = ' '; // 用空格分开操作数(  
               n++;  
                while(priority(pre[i]) <= priority(stack.GetTop()))   
                {  
                    // 当前的操作符小于等于栈顶操作符的优先级时,将栈顶操作符写入到后缀表达式,重复此过程  
                    post[j++] = stack.Pop();  
                   n++;  
                }  
      
                stack.Push(pre[i]); // 当前操作符优先级大于栈顶操作符的优先级,将该操作符入栈  
            }  
      
           i++;  
        }  
        while(stack.top) // 将所有的操作符加入后缀表达式  
        {  
           post[j++] = stack.Pop();  
           n++;  
       }  
    }  
      
    double read_number(char str[],int *i)  
    {  
       double x=0.0;  
        int k = 0;  
       while(str[*i] >='0' && str[*i]<='9')  // 处理整数部分  
        {  
            x = x*10+(str[*i]-'0');  
            (*i)++;  
        }  
      
        if(str[*i]=='.') // 处理小数部分  
       {  
            (*i)++;  
           while(str[*i] >= '0'&&str[*i] <='9')  
            {  
             x = x * 10 + (str[*i]-'0');  
               (*i)++;  
                k++;  
            }  
        }  
        while(k!=0)  
        {  
            x /= 10.0;  
            k--;  
       }  
      
       return x;  
    }  
     
    double postfix_value(char post[])  
    {  
        SeqStack<double> stack;    // 操作数栈  
        stack.init();  
      
        int i=0 ;  
       double x1,x2;  
      
       while(post[i] !='#')  
        {  
           if(post[i] >='0' && post[i] <='9')  
               stack.Push(read_number(post,&i));  
            else if(post[i] == ' ')  
                i++;  
            else if (post[i] =='+')  
            {  
                x2 = stack.Pop();  
                x1 = stack.Pop();  
                stack.Push(x1+x2);  
                i++;  
            }  
            else if (post[i] =='-')  
            {  
                x2 = stack.Pop();  
                x1 = stack.Pop();  
                stack.Push(x1-x2);  
                i++;  
            }  
            else if (post[i] =='*')  
            {  
                x2 = stack.Pop();  
              x1 = stack.Pop();  
                stack.Push(x1*x2);  
               i++;  
            }  
            else if (post[i] =='/')  
            {  
                x2 = stack.Pop();  
               x1 = stack.Pop();  
                stack.Push(x1/x2);  
                i++;  
            }  
        }  
        return stack.GetTop();  
    }  
    //main.cpp
    #include "PrefixToPostfix.h"  
    #include"expseqstack.h"
    #include <iostream>  
    using namespace std;  
    
    void main()  
    {  
        SeqStack<int> stack ;  
       stack.init();  
     
        //char pre[] ="22/(5*2+1)#";  
        char exp[100];  
        cout << "输入表达式(中缀,以#结束):";  
        cin >> exp;  
      
       char post[100] ;  
        //cout <<"中缀表达式为:"<< pre << endl;  
      
        int n =0;           // 返回后缀表达式的长度  
       postfix(exp,post,n);  
        cout <<"后缀表达式为:";  
       for( int i =0 ;i < n ;i++)  
           cout << post[i] ;  
      
        cout << "
    由后缀表达式计算出的数值结果:  ";  
       cout << postfix_value(post) << endl;  
      
       system("pause");  
    }  
  • 相关阅读:
    WPF 使用XML作为绑定源时Xaml注意事项
    WPF 使用动画设置特殊值的方法
    WPF 使用EventTrigger时设置SouceName技巧
    WPF 鼠标移动时触发图片旋转(非动画)
    WPF 隐藏式控件
    WPF TabItem设置Visibility隐藏Control内容
    WPF Adorner 简易图片取色器
    WPF Xaml中创建集合
    WPF 通过EventTrigger修改鼠标样式
    WPF DataGrid点击列头选择全列并具有背景色
  • 原文地址:https://www.cnblogs.com/DonAndy/p/5950468.html
Copyright © 2020-2023  润新知