栈的应用——实现简易计算器(一)

周日晚上心血来潮,想用栈做个简单的计算器,于是便动手鼓捣了。参照书上的思想,我用了两个栈来解决这个问题。
1)栈S1用来存放运算符,栈S2用来存放操作数。由于运算符为char型而操作数为int型,因此,需要使用类模板来声明两个不同数据类型的栈。
2)为简单起见,只能计算0-9之内的数(由于每次只能读入一个字符入栈,如果是大于等于10的任意数,就要设计另外的算法使“相邻”的两个数字组合为一个数)。
3)运算符涉及优先级的问题,为此,需要一个判断优先级的函数Priority(),该函数返回运算符的优先级。现在的问题是,对于最初输入以及最后入栈的运算符,它与谁进行比较?为此,先将一符号“#”压入栈中作为栈底,并且在输入表达式时以“#”号结尾。一开始我在Priority()函数中令“#”的优先级最低,但之后我发现有更为简便的方法:在该函数中只要遇到“#”或“(”或“)”,就返回-1,对于“(”还有另一更简单的处理方式:只要一读入“(”,就让其入栈。从代码中可以知道,这两种处理方式是不冲突的。

这是本人做的第一个“小程序”,虽然到了这一步仍然只能计算10以内的整数的加减乘除,但是这毕竟是多次调试、改错并优化后的结果,在这个过程中也得到了很多经验,对栈的理解也更透彻了。本来想把之前阶段性的代码贴出来,并附上解决方法,但由于没有保存之前的代码,那些碰到的问题以及解决方法都无法分享了sigh。

以下为完整代码:

#include"SeqStack.h"    //该头文件的声明在另一篇博客中

int Calculate(SeqStack<char>&);
int Priority(char);

int Priority(char op)       //判断输入的运算符的优先级
{
    switch(op){
    case '+':   case '-':return 1;
    case '*':   case '/':return 2;
    default:    return -1;
    }
}

int Calculate(SeqStack<char>& S1)       //S1为char型的栈,用于存放运算符
{
    SeqStack<int>S2;        //S2为int型的栈,用于存放操作数
    char ch,a,b,c,d,m,n,p,t;
    int op1,op2,op3,op4,op5,op6,op7,op8,a1,a2,n1,n2;
    S1.push('#');       //先将#存入栈S1中
    cout<<"请输入需要计算的表达式(表达式需以#结尾):\n";
    do{
        ch = getchar();
        switch(ch){
        case '0':   case '1':
        case '2':   case '3':
        case '4':   case '5':
        case '6':   case '7':
        case '8':   case '9':
            S2.push(ch - '0');      //将char型的数值转换为int型并压入栈S2中
            break;
        case ' ':       //若输入的表达式含有空格,则转入下一字符
            break;
        case '+':
            if(Priority(S1.get_top()) < Priority('+'))      //若当前栈顶运算符优先级低于‘+’,则将当前扫描到的字符‘+’入栈
                S1.push('+');
            else{
                S2.pop(op1);
                S2.pop(op2);        //将栈S2最外面的两个数字弹出
                if(S1.get_top() == '+')     //判断S1栈顶的运算符,以做出相应的运算
                    S2.push(op2 + op1);
                else if(S1.get_top() == '-')
                    S2.push(op2 - op1);
                else if(S1.get_top() == '*')
                    S2.push(op2 * op1);
                else
                    S2.push(op2 / op1);
                S1.pop(c);      //该运算符已做过相应的运算,出栈
                S1.push('+');   //将‘+’压入栈中,作为S1新的栈顶
            }
            break;
        case '-':
            if(Priority(S1.get_top()) < Priority('-'))
                S1.push('-');
            else{
                S2.pop(op3);
                S2.pop(op4);
                if(S1.get_top() == '+')
                    S2.push(op4 + op3);
                else if(S1.get_top() == '-')
                    S2.push(op4 - op3);
                else if(S1.get_top() == '*')
                    S2.push(op4 * op3);
                else
                    S2.push(op4 / op3);
                S1.pop(d);
                S1.push('-');
            }
            break;
        case '*':
            if(Priority(S1.get_top()) < Priority('*'))
                S1.push('*');
            else{
                S2.pop(op5);
                S2.pop(op6);
                if(S1.get_top() == '+')
                    S2.push(op6 + op5);
                else if(S1.get_top() == '-')
                    S2.push(op6 - op5);
                else if(S1.get_top() == '*')
                    S2.push(op6 * op5);
                else
                    S2.push(op6 / op5);
                S1.pop(t);
                S1.push('*');
            }
            break;
        case '/':
            if(Priority(S1.get_top()) < Priority('/'))
                S1.push('/');
            else{
                S2.pop(op7);
                S2.pop(op8);
                if(S1.get_top() == '+')
                    S2.push(op8 + op7);
                else if(S1.get_top() == '-')
                    S2.push(op8 - op7);
                else if(S1.get_top() == '*')
                    S2.push(op8 * op7);
                else
                    S2.push(op8 / op7);
                S1.pop(m);
                S1.push('/');
            }
            break;
        case '(':       //只要一遇到左括号,即将其压入栈中
            S1.push('(');
            break;
        case ')':
            do{
                S2.pop(n1);
                S2.pop(n2);
                if(S1.get_top() == '+')
                    S2.push(n2 + n1);
                else if(S1.get_top() == '-')
                    S2.push(n2 - n1);
                else if(S1.get_top() == '*')
                    S2.push(n2 * n1);
                else
                    S2.push(n2 / n1);
                S1.pop(n);      //将已参加过运算的运算符出栈
            }while(S1.get_top() != '(');        //通过该循环保证括号中的所有表达式已计算完毕
            S1.pop(p);                          //更重要的是要将左括号退出  右括号从未进栈
            break;
        case '#':           //输入的表达式需以#结尾,方便判断运算符的优先级
                S2.pop(a1);
                S2.pop(a2);
                if(S1.get_top() == '+')
                    S2.push(a2 + a1);
                else if(S1.get_top() == '-')
                    S2.push(a2 - a1);
                else if(S1.get_top() == '*')
                    S2.push(a2 * a1);
                else
                    S2.push(a2 / a1);
                S1.pop(a);      //将当前运算符出栈
                S1.pop(b);      //将栈底的#出栈,至此,栈S1已空。
            break;
        default:
            break;
        }
    }while(ch != '\n');         //若扫描至换行符,则退出循环,至此,表达式计算完成。
    return S2.get_top();        //S2的栈底元素即为最终的结果
}

int main()
{
    SeqStack<char>S;
    cout<<Calculate(S);
}

标题上加了个(一),希望之后会有(二)甚至更多的文章吧,把这个计算器再优化些,功能再丰富些:)

附一张模拟表达式出栈、入栈过程的手稿:
这里写图片描述

 

posted @ 2016-03-29 13:05  larryking  阅读(9352)  评论(2编辑  收藏  举报