【华为机试】HJ50 四则运算

知识点与难度

字符串、基础数学、栈、中等难度

描述

输入一个表达式(用字符串表示),求这个表达式的值。

保证字符串中的有效字符包括[‘0’-‘9’],‘+’,‘-’, ‘*’,‘/’ ,‘(’, ‘)’,‘[’, ‘]’,‘{’ ,‘}’。且表达式一定合法。

数据范围:表达式计算结果和过程中满足 ∣val∣≤1000  ,字符串长度满足 1≤n≤1000 

输入描述:

输入一个算术表达式

输出描述:

得到计算结果

输入输出示例:

输入:

3+2*{1+2*[-4/(8-6)+7]}

输出:

25

我的代码:

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

int checkNumber(char c) {
    if ('0' <= c && c <= '9') {
        return c - '0';
    }
    return -1;
}

int getPriority(char c) {
    if (c == '+' || c == '-') {
        return 0;
    } else if (c == '*' || c == '/') {
        return 1;
    } else if (c == '#' || c == '(' || c == '{' || c == '[') {
        return -1;
    } else {
        return 2;
    }
}

float getCalculation(char opt, float n1, float n2) {
    //cout << n1 << opt << n2 << endl;
    if (opt == '+') {
        return n1 + n2;
    } else if (opt == '-') {
        return n1 - n2;
    } else if (opt == '*') {
        return n1 * n2;
    } else {
        return n1 / n2;
    }
}

int main() {
    string s;
    int start = 1;
    int minus = 0;
    stack<float> num;
    stack<char> op;
    op.emplace('#');
    float temp;
    int n;
    int priority;
    float n1; //数一
    float n2; //数二
    char opt; //运算符
    int key = 0;
    while (cin >> s) { // 注意 while 处理多个 case
        int i = 0;
        while (i < s.length()) {
            // 负数的特殊处理
            if (start == 1) {
                if (s[i] == '-') {
                    minus = 1;
                    i++;
                }
                start = 0;
            }
            //读取数字
            temp = 0;
            while (i < s.length() && (n = checkNumber(s[i])) != -1) {
                temp = temp * 10 + n;
                key = 1;
                i++;
            }
            if (key != 0) {
                if (minus == 1) {
                    num.emplace(-temp);
                    minus = 0;
                } else {
                    num.emplace(temp);
                }
                key = 0;
            }
            //读取操作符
            while (i < s.length() && (n = checkNumber(s[i])) == -1) {
                if (start == 1) {
                    if (s[i] == '-') {
                        minus = 1;
                        i++;
                    }
                    start = 0;
                    continue;
                }
                priority = getPriority(s[i]);
                if (priority == 2) {    //右括号
                    while (getPriority(op.top()) != -1) {
                        opt = op.top();
                        op.pop();
                        n2 = num.top();
                        num.pop();
                        n1 = num.top();
                        num.pop();
                        n1 = getCalculation(opt, n1, n2);
                        num.emplace(n1);
                    }
                    op.pop();

                } else if (priority == -1) { //左括号
                    op.emplace(s[i]);
                    start = 1;
                } else {                    //运算符
                    while (priority <= getPriority(op.top()) ) {
                        opt = op.top();
                        op.pop();
                        n2 = num.top();
                        num.pop();
                        n1 = num.top();
                        num.pop();
                        n1 = getCalculation(opt, n1, n2);
                        num.emplace(n1);
                    }
                    op.emplace(s[i]);
                }
                i++;
            }
        }
        while (num.size() > 1) {
            opt = op.top();
            op.pop();
            n2 = num.top();
            num.pop();
            n1 = num.top();
            num.pop();
            n1 = getCalculation(opt, n1, n2);
            num.emplace(n1);
        }
        cout << num.top() << endl;
    }
}
// 64 位输出请用 printf("%lld")

我的代码分析:

首先定义符号栈数字栈,当输入数字时入数字栈,当输入符号时,查看当前符号与符号栈顶元素的优先级,若优先级当前符号大于栈顶符号,则入栈,否则,符号栈弹出一个运算符,数字栈弹出两个数字,运算后的结果压入数字栈。特殊的,输入左括号时直接入栈,输入右括号时出栈运算直到左括号出栈。当输入完成时,进行出栈运算,直到栈底只剩一个元素,该元素即为计算结果。

checkNumber() 用来检验是否为数字,是数字返回数字0-9,不是返回-1。

getPriority() 用来获取运算符优先级,加减为0,乘除为1,所有左括号与#号为-1,右括号为2。

getCalculation() 进行二元运算返回结果。

因为在表达式与括号内的头部可能出现负数,因此要校验一下开头是不是负数,用start变量标识是否为表达式或括号的开头,用minus变量标识开头是否为负数。之后循环读取数字,压入数字栈。接下来读取操作符,根据输入进行运算。表达式读取完成,出栈运算,直到只剩下一个元素。

top1代码:

#include <iostream>
#include <string.h>

using namespace std;

int char_i = 0;//使用全局变量,防止递归产生的无线循环

int cal(char *character){
    int result = 0;
    
    int num[100] = {0};
    int num_index = 0;

    char sigh = '+';
    int len = strlen(character);
    while(char_i<len){
        int num_m = 0;
        if(character[char_i]=='('||character[char_i]=='['||character[char_i]=='{'){
            char_i++;
            num_m = cal(character);
        }

        while (1)
        {
            if (character[char_i] >= '0' && character[char_i] <= '9')
            {
                num_m = num_m * 10 + character[char_i] - '0';
                char_i++;
            }
            else
                break;
        }

        switch(sigh){
            case '+':
                num[num_index] = num_m;
                num_index++;
                break;
            case '-':
                num[num_index] = -num_m;
                num_index++;
                break;
            case '*':
                num[num_index-1] *= num_m; 
                break;
            case '/':
                num[num_index-1] /= num_m; 
                break;
            default:
                break;
        }
        sigh = character[char_i];
        if (character[char_i] == '}' || character[char_i] == ']' || character[char_i] == ')') {//结束本次递归,返回括号内运算的结果
            char_i++;
            break;
        }
        char_i++;
        
        
    }
    

    for (int i = 0; i < num_index; i++)
    {
        result += num[i];
    }

    return result;
    
    
    
}


int main() {
	char character[100] = { 0 };
	int result = 0;
	cin >> character;

	result = cal(character);

	cout << result << endl;
}

top1代码分析:

只使用一个数字数组,将整个表达式转换成一个加法运算。预设一个‘+’运算符,这样当第一个数字为负数时,补了一个+0,之后的加法运算就是向数字数组中添加一个正数,减法运算添加一个负数,乘除法则是取前一个数字进行运算后返回数组。对于括号则是进行递归调用,计算完括号中的内容后返回。

总结:

将整个表达式转换成一个加法运算,我觉得还挺妙的,对于括号这种形式的运算,也要想到递归的算法来简化问题。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值