栈实现四则运算-思想(10以下正整数)

2 篇文章 0 订阅

栈实现四则运算-思想(10以下正整数)

  • 实现四则运算求值,就是要求计算机像人一样按运算符优先级进行数值计算,如何实现这一过程,栈给我们提供了思路,及只需要将计算表达式转换为两个栈:一个是数值的栈,一个是运算符的栈,然后按照栈操作完成每一步计算。

一、栈结构特点

  1. 栈的最主要特点是后进先出。
  2. 栈是一种运算受限的线性表,限定仅在表尾进行插入和删除操作的线性表。栈的所有插入和删除操作均在栈顶进行,而栈底不允许插入和删除。
  3. 向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
    图1 入栈
    图1 入栈过程
    图2 出栈过程
    图2 出栈过程

二、实现四则运算基本思想

1.前中后缀表达式的转换(二叉树的应用)

  • 自然表达式转换为前/中/后缀表达式,其实是很简单的。首先将自然表达式按照优先级顺序,构造出与表达式相对应的二叉树,然后对二叉树进行前/中/后缀遍历,即得到前/中/后缀表达式。举例说明 将自然表达式转换成二叉树:a×(b+c)−d。
    – a. 根据表达式的优先级顺序,首先计算(b+c),形成二叉树。
    – b. 然后是a×(b+c),在写时注意左右的位置关系。
    – c. 最后在右边加上 −d。
    表达式转换为二叉树
    图3 表达式转换为二叉树

  • 然后最这个构造好的二叉树进行遍历,三种遍历如下:
    ① 前序遍历:根-左-右
    ② 中序遍历:左-根-右
    ③ 后序遍历:左-右-根

2.中缀表达式转后缀表达式(栈的应用)

  • 中缀表达式9+(3−1)∗3+9/2转化为后缀表达式为931−3∗+92/+.
  • 规则:从左到右遍历中缀表达式的每一数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈 顶符号的优先级,是右括号或优先级低于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。
a.初始化一空栈,用来对符号进出栈使用。

b.第一个字符是数字9,输出9,后面是符号“+”,进栈。

c.第三个字符是“(”,依然是符号,因其只是左括号,还没有配对,故进栈。

d.第四个字符是数字3,输出,总表达式为9 3,接着是“-”,进栈。

e.接下来是数字1,输出,总表达式为9 3 1,后面是符号“)”,此时,我们需要去匹配此前的“(”,所以栈顶依次出栈,并输出,直到“(”出栈为止。此时左括号上方只有“-”,因此输出“-”。总的表达式为9 3 1 -。

f.接着是数字3,输出,总的表达式为9 3 1 - 3.紧接着是符号“*”,因为此时的栈顶符号为“+”号,优先级低于“*”,因此不输出,“*”进栈。

g.之后是符号“+”,此时当前栈顶元素“*”比这个“+”的优先级高,因此栈中元素出栈并输出(没有比“+”更低的优先级,所以全部出栈),总输出表达式为9 3 1 - 3 * +。然后将当前这个符号“+”进栈。

h.紧接着数字9,输出,总表达式为9 3 1 - 3 * + 9。后是符号“/”,所以“/”进栈。

i.最后一个数字2,输出,总的表达式为9 3 1 - 3 * + 9 2。

j.因已经到最后,所以将栈中符号全部出栈并输出。最终输出的后缀表达式结果为9 3 1 - 3 * + 9 2 / +。

3.后缀表达式计算结果(栈的应用)

  • 后缀表达式为:931−3∗+92/+
  • 规则:从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果。
a.初始化一个空栈。此栈用来对要运算的数字进行进出使用。

b.后缀表达式中前三个是、都是数字,所以9 3 1 进栈。

c.接下来是“-”,所以将栈中的1出栈作为减数,3出栈作为被减数,并运算3-1得到2,再讲2进栈。

d.接着是数字3进栈。

e.后面是“*”,也就意味着栈中3和2出栈,2与3相乘,得到6,并将6进栈。

f.下面是“+”,所以栈中6和9出栈,9和6相加,得到15,将15进栈。

g.接着是9和2两数字进栈。

h.接下来是符号“/”,因此,栈顶的2与9出栈,9与2相除,得到4,将4进栈。

i.最后一个是符号“+”,所以15与4出栈并相加,得到19,将19进栈。

j.结果是19出栈,栈变为空。

4.代码(C++)

#include <stack>
#include <iostream>
#include <string>

/*
 *比较两个操作符的优先级,op1比op2高返回1,一样返回0,低返回-1
*/
int compareOperatorPriority(char op1,char op2){
    switch(op1){
        case '+': case '-':
            return (op2 == '*' || op2 == '/'? -1:0);
            break;
        case '*': case '/':
            return (op2 == '-' || op2 == '+'? 1:0);
    }
    return -1;
}

/*
 *判断是否为数字
 */
bool isDigit(char c){
    int a = c - '0';
    if(a >= 0 && a <= 9){
        return true;
    }else{
        return false;
    }
}

/*
 *判断是否为操作符
 */
bool isOperator(char c){
    if( c == '+' || c == '-' || c == '*' || c == '/'){
        return true;
    }else{
        return false;
    }
}

/*
 *得到后缀表达式
*/
string getSuffixExpression(string str)
{
    stack<char> numbersAndOperators;
    stack<char> operators;

    //开始遍历字符串
    for(int i = 0;i<str.length();i++)
    {
        if(isDigit(str[i]))
        {
            numbersAndOperators.push(str[i]); //如果是数字,则直接进入栈numbersAndOperators
        }
        else if(isOperator(str[i]))
        {
            //如果是操作符
            if(operators.empty() || operators.top() == '(')
            {
                //若栈空或栈顶为(
                operators.push(str[i]);
            }
            else if(compareOperatorPriority(str[i], operators.top())>0)
            {
                //若操作符比栈顶操作符优先级高
                operators.push(str[i]);
            }
            else
            {
                while(true)
                {
                    numbersAndOperators.push(operators.top());
                    operators.pop();
                    if(operators.empty() || operators.top() == '(')
                    {
                        operators.push(str[i]);
                        break;
                    }
                    else if(compareOperatorPriority(str[i],operators.top())>0)
                    {
                        operators.push(str[i]);
                        break;
                    }
                }
            }
        }
        else if(str[i] == '(')
        {
            operators.push(str[i]);
        }
        else if(str[i] == ')')
        {
            while(operators.top() != '(')
            {
                numbersAndOperators.push(operators.top());
                operators.pop();
            }
            operators.pop();//丢掉'('
        }
        else
        {
            cout<< "Bad Expression!" << endl;
            exit(-1);
        }
    }

    while(!operators.empty())
    {
        numbersAndOperators.push(operators.top());
        operators.pop();
    }

    string suffix = string(numbersAndOperators.size(),'a');
    int i = 0;
    while(!numbersAndOperators.empty()){
        suffix[i] = numbersAndOperators.top();
        numbersAndOperators.pop();
        i++;
    }

    reverse(begin(suffix), end(suffix));
    return suffix;
}

/*
 *根据后缀表达式计算
*/
int calculate(string str){
    stack<int> numbers;
    for(int i = 0;i < str.length();i++){
        if(isDigit(str[i])){
            numbers.push(str[i]-'0');
        }
        else if(isOperator(str[i]))
        {
            //遇到操作符,取出栈顶2个数字,并计算,计算结果压入栈
            int a = numbers.top();
            numbers.pop();
            int b = numbers.top();
            numbers.pop();
            int tempResult;
            if(str[i] == '+'){
                tempResult = b + a;
            }else if(str[i] == '-'){
                tempResult = b - a; //这里注意被减数和减数的顺序,不要弄反
            }else if(str[i] == '*'){
                tempResult = b * a;
            }else if(str[i] == '/'){
                tempResult = b / a;
            }
            numbers.push(tempResult);
        }
    }
    return numbers.top();
}

int main(int argc, char const *argv[])
{
    /* code */
    string input ;
    cout<<"Please input a exoression: ";
    cin>>input;
    cout<<"The input is : "<<input<<endl;
    input = getSuffixExpression(input);
    cout<<"The suffix exoression is :" << input << endl;
    int result = calculate(input);
    cout<<"The result is "<<result << endl;

    return 0;
}

三、总结

  1. 本例只是简单叙述利用栈简单实现四则运算,涉及10以上整数、小数和负数的四则运算,还需进一步进行优化;
  2. 数据结构对于程序员来说,是很重要的学习内容,在今后的的学习工作中,要保持不断学习和提高。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值