• 算法与数据结构3.3 calculator


    ★实验任务

    小 V 发明了一个神奇的整数计算器:

    给定一个合法的表达式,这个计算器能求出这个表达式的最终答案。

    表达式可能包含:

    +:运算符,整数加法。如 1+1=2

    -:运算符,整数减法。如 1-1=0

    :运算符,整数乘法。如 11=1

    /:运算符,整数除法。如 3/2=1

    (:左括号

    ):右括号

    操作数:保证为非负整数,且操作数没有正号(如不会出现+1 等)

    现在,给定一个表达式,小 V
    在用这个计算器计算前想先知道最终答案是多少,你能 帮帮他吗?

    ★数据输入

    一个合法的表达式,表达式长度不超过 1000。

    ★数据输出

    表达式的最终结果。

    ★Notice

    题目保证:输入的操作数,计算的中间值,计算的最终结果都在 int 范围内

    ★样例

    输入示例 输出示例
    1+1
    1+2/3
    (1+2)*3
    2
    1
    9

    ★思路

      solve1

        建立两个栈:数字栈、符号栈

        按顺序遍历算式

        遇到数字注意按多位数读取,压入数字栈

        若符号栈为空或为 ' ( ' ,压入符号栈

        遇到 + - / ,向前计算优先级大于等于本符号优先级的,算到 ' ( '停止。将本符号压入符号栈

        优先级 / * 最高,+ - 次之

        故 + - 前面的 + - * / 都要算, * / 前面的
    / 要算, + -不算,遇到 + - 停止

        遇到 ' ) ',向前算到 ' ( '

        最后数字栈栈顶元素即为解

      solve 2
        将原表达式转换为后续表达式。

        为能正确读取后续表达式,可在所有数字、符号间加上空格。

        此时,表达式将比原表达式长,原来长度1000数组不够用,要开大一点

        最后用后续表达式计算结果

      附:中缀表达式转后缀表达式的方法

        1.遇到操作数:直接输出(添加到后缀表达式中)

        2.栈为空时,遇到运算符,直接入栈

        3.遇到左括号:将其入栈

        4.遇到右括号:执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出。

        5.遇到其他运算符:加减乘除:弹出所有优先级大于或者等于该运算符的栈顶元素,然后将该运算符入栈

        6.最终将栈中的元素依次出栈,输出。

    ★Code

     
                #include <iostream>
    #include <cstdlib>
    #include <string>
    #include <vector>
    #include <cstring>
    using namespace std;
    
    char priority(char pre, char post)
    {
    	if (pre == '+')
    	{
    			 if (post == '+') return '>';
    		else if (post == '-') return '>';
    		else if (post == '*') return '<';
    		else if (post == '/') return '<';
    		else if (post == '(') return '<';
    		else if (post == ')') return '>';
    	}
    	else if (pre == '-')
    	{
    			 if (post == '-') return '>';
    		else if (post == '+') return '>';
    		else if (post == '*') return '<';
    		else if (post == '/') return '<';
    		else if (post == '(') return '<';
    		else if (post == ')') return '>';
    	}
    	else if (pre == '*')
    	{
    			 if (post == '*') return '>';
    		else if (post == '/') return '>';
    		else if (post == '+') return '>';
    		else if (post == '-') return '>';
    		else if (post == '(') return '<';
    		else if (post == ')') return '>';
    	}
    	else if (pre == '/')
    	{
    			 if (post == '/') return '>';
    		else if (post == '*') return '>';
    		else if (post == '+') return '>';
    		else if (post == '-') return '>';
    		else if (post == '(') return '<';
    		else if (post == ')') return '>';
    	}
    	else if (pre == '(')
    	{
    			 if (post == '*') return '<';
    		else if (post == '/') return '<';
    		else if (post == '+') return '<';
    		else if (post == '-') return '<';
    		else if (post == '(') return '<';
    		else if (post == ')') return '=';
    	}
    }
    int caculate(int Operand1, int Operand2, char Operator) ;
    int calculateResult(string str) {                        //用于计算计算生成算式的值 
    		vector< int > Operands;                              //运算数栈 
    		vector< char > Operators;                              //运算符栈 
    		int OperandTemp = 0;
    		char LastOperator = 0;                                 //记录上一次所遇到的符号 
    		for (int i = 0; i < str.size(); i++) {                 //此循环用于去括号 
    			char ch = str[i];
    			if ('0' <= ch && ch <= '9') {
    				OperandTemp = OperandTemp * 10 + ch - '0';
    			}
    			else if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '(' || ch == ')') {
    				if (ch != '(' && LastOperator != ')') {         //结合本次和上次所遇见的符号来判断是否需要将当前存储的运算数压入栈 
    					Operands.push_back(OperandTemp);
    					OperandTemp = 0;
    				}
    				char Opt2 = ch;                                 
    				for (; Operators.size() > 0;) {
    					char Opt1 = Operators.back();               
    					char CompareRet = priority(Opt1,Opt2);   //用当前符号与栈顶符号来对算式简化 
    					if (CompareRet == '>') {                    //当前的符号的优先级小于栈顶符号时就可以将栈顶符号计算掉并将结果压入栈  
    						int Operand2 = Operands.back();
    						Operands.pop_back();
    						int Operand1 = Operands.back();
    						Operands.pop_back();
    						Operators.pop_back();
    						int Ret = caculate(Operand1, Operand2, Opt1);
    						Operands.push_back(Ret);
    					}
    					else if (CompareRet == '<') {                //当前的符号优先级大于栈顶符号不能进行运算所以跳出循环来存储当前符号 
    						break;
    					}
    					else if (CompareRet == '=') {                //这个是“(”,“) ”结合的情况 所以移除“(”并退出循环 
    						Operators.pop_back();
    						break;
    					}
    				}
    				if (Opt2 != ')') {
    					Operators.push_back(Opt2);
    				}
    				LastOperator = Opt2;
    			}
    		}
    		if (LastOperator != ')') {                               //接下来就是计算一个不含括号的算式了 
    			Operands.push_back(OperandTemp);
    		}
    		for (; Operators.size() > 0;) {
    			int Operand2 = Operands.back();
    			Operands.pop_back();
    			int Operand1 = Operands.back();
    			Operands.pop_back();
    			char Opt = Operators.back();
    			Operators.pop_back();
    			int Ret = caculate(Operand1, Operand2, Opt);
    			Operands.push_back(Ret);
    		}
    		return Operands.back();                                                 //返回结果 
    	}
    	int caculate(int Operand1, int Operand2, char Operator) {        //计算函数 
    		int result = 0;
    		if (Operator == '+') {
    			result = Operand1 + Operand2;
    		}
    		if (Operator == '-') {
    			result = Operand1 - Operand2;
    		}
    		if (Operator == '*') {
    			result = Operand1*Operand2;
    		}
    		if (Operator == '/') {
    			result = Operand1 / Operand2;
    		}
    		return result;
    }
    int main()
    {
    	string str;
    	cin>>str;
    	int ans=calculateResult(str);
    	cout<<ans;
    	return 0;
    }
            
    
  • 相关阅读:
    FreeMarker常用语法学习
    Oracle如何实现创建数据库、备份数据库及数据导出导入的一条龙操作-------sql方式
    Oracle Partition 分区详细总结
    oracle 当中,(+)是什么意思
    SQL中EXISTS的用法
    JS return false 与 return true
    Merge into语句用法及其效率问题
    几种设置表单元素中文本输入框不可编辑的方法
    Oracle存储过程基本语法
    UNIX网络编程——Socket粘包问题
  • 原文地址:https://www.cnblogs.com/031602523liu/p/7676378.html
Copyright © 2020-2023  润新知