• 简单四则运算之逆波兰式解法小结(C)


    简单四则运算之逆波兰式解法

    前提:数字为单个0~9,只有四则运算符,不含括号优先级(数字和优先级均可拓展)

    易错点

    1. 字符串读取

    不含空格:整行读取

    开辟char数组,以字符串形式 %s 读取,以空白符为分割;

    含有空格:单个字符逐个读取

    开辟char字符, %c 读取;

    【注意 %c 的读取不会跳过空格等空白符,对于以空格为间隔的输入,可在 %c 前面加空格处理。即 "(空格)%c" 】

    2. 数字与运算符混合处理

    单个字符判断是否为十进制数字(0~9): isdigit() 函数 (头文件<ctype.h>)

    数字字符char转int计算:- ‘0’

    int数字转字符char输出:+ ‘0’

    precede函数检查优先级:注意优先级相等情况的考虑!

    操作数读取时注意先后顺序,被除(减)数和除(减)数不要弄反了!!

    知识考点归纳

    一般的表达式计算采用的是中缀(操作数在操作符两边紧挨着),逆波兰式则采用的是后缀(操作符紧挨在两个操作数后面)。

    注意从左到右依次运算这一默认优先级。

    表达式读取核心逻辑

    1. 创建rpn主栈存储逆波兰式,oprs临时栈存储运算符;
    2. 先读取起始的三个字符,数字入rpn,运算符入oprs;
    3. 此后必为一个运算符,一个数字交替出现。所以,新读取运算符先与top(oprs)比较,后者优先级大于等于前者均出栈入rpn,新运算符一直与oprs栈顶元素比较,直到运算符优先级比栈顶高或者栈空为止。
    4. 读取完全部输入后不要忘记检查oprs是否为空,不为空则全部出栈依次入栈rpn。
    5. 因为是栈结构,所以最后输出前一定要进行反转
    6. 逆波兰式的的读取计算较简单一些:读取数字一直入临时栈(存储操作数),直到读取运算符,弹出栈顶的两个元素进行运算(注意两个数的顺序),结果再入栈,继续读取,直到最后剩一个数字即为最终运算结果。(注意数字和字符的转化)

    代码(C,包括简单的栈实现)

    //简单四则远算(不含括号,两级运算优先级)逆波兰式解法
    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    
    #define ERROR 0
    #define OK 1
    
    typedef struct Stack {
        char *data;
        int top_index, max_size;
    } Stack;
    
    void init(Stack *s, int size) {
        s->data = (char *)malloc(sizeof(char) * size);
        s->max_size = size;
        s->top_index = -1;
        return;
    }
    
    int push(Stack *s, int data) {
        if (s->top_index >= s->max_size - 1) {
            return ERROR;
        }
        s->top_index++;
        s->data[s->top_index] = data;
        return OK;
    }
    
    int top(Stack *s) {
        return s->data[s->top_index];
    }
    
    int pop(Stack *s) {
        if (s->top_index < 0) {
            return ERROR;
        }
        s->top_index--;
        return OK;
    }
    
    int empty(Stack *s) {
        if (s->top_index < 0) {
            return 1;
        } else {
            return 0;
        }
    }
    
    void clear(Stack *s) {
        free(s->data);
        free(s);
        return;
    }
    
    int precede(char c1, char c2) {
        int score1, score2;
        if(c1 == '+' || c1 == '-') {
            score1 = 0;
        } else {
            score1 = 1;
        }
        if(c2 == '+' || c2 == '-') {
            score2 = 0;
        } else {
            score2 = 1;
        }
        return score1 >= score2;
    }
    
    Stack *reverse(Stack *s) {
        Stack *tmp = (Stack *)malloc(sizeof(Stack));
        init(tmp, 20);
        while (!empty(s)) {
            push(tmp, top(s));
            pop(s);
        }
        clear(s);
        return tmp;
     }
    
    void output(Stack *s) {
        for (int i = s->top_index; i > 0; --i) {
            printf("%c", s->data[i]);
        }
        printf("%c
    ",  s->data[0]);
        return;
    }
    
    void calculate(Stack *s, char op) {
        int a = top(s) - '0';
        pop(s);
        int b = top(s) - '0';
        pop(s);
        switch (op) {
            case '+' : push(s, (b + a) +'0'); break;
            case '-'  : push(s, (b - a) + '0'); break;
            case '*'  : push(s, (b * a) + '0'); break;
            case '/'  : push(s, (b / a) + '0'); break;
        }
    }
    
    int calc(Stack *s) {
        Stack *tmp = (Stack *)malloc(sizeof(Stack));
        init(tmp, 20);
        char data;
        while (!empty(s)) {
            data = top(s);
            pop(s);
            if (isdigit(data)) {
                push(tmp, data);
            } else {
                calculate(tmp, data);
            }
        }
        return top(tmp) - '0';
    }
    
    int main() {
        Stack *rpn = (Stack *)malloc(sizeof(Stack));
        init(rpn, 20);
        Stack *oprs = (Stack *)malloc(sizeof(Stack));
        init(oprs, 20);
        char *tmp = (char *)malloc(sizeof(char) * 20);
        scanf("%s", tmp);
        int i = 0;
        push(rpn, tmp[i++]);
        push(oprs, tmp[i++]);
        push(rpn, tmp[i++]);
        while (tmp[i] != '') {
            while (!empty(oprs) && precede(top(oprs), tmp[i])) {
                push(rpn, top(oprs));
                pop(oprs);
            }
            push(oprs, tmp[i++]);
            push(rpn, tmp[i++]);
        }
        while (!empty(oprs)) {
            push(rpn, top(oprs));
            pop(oprs);
        }
        rpn = reverse(rpn);
        output(rpn);
        printf("%d", calc(rpn));
        clear(oprs);
        clear(rpn);
        free(tmp);
        return 0;
    }

    C++实现(包括Stack类)

    #include <iostream>
    #include <cassert>
    #include <string>
    using std::cin;
    using std::cout;
    using std::endl;
    using std::string;
    template<typename Type> 
    class Stack{
    public:
        Stack(int new_size) {
            size = new_size;
            data = new Type[size];
            top_index = -1;
        }
        ~Stack() {
            delete[] data;
        }
        bool push(const Type &val) {
            if (top_index + 1 >= size) {
                return false;
            }
            top_index++;
            data[top_index] = val;
            return true;
        }
        bool empty() {
            return top_index < 0;
        }
        Type top() {
            assert(top_index >= 0);
            return data[top_index];
        }
        bool pop() {
            if (empty()) {
                return false;
            }
            top_index--;
            return true;
        }
        void output() {
            for (int i = top_index; i >= 0; i--) {
                i == top_index || putchar(' ');
                cout << data[i];
            }
            cout << endl;
            return;
        }
        void reverse() {
            Type *old_data = data;
            data = new Type[size];
            for (int i = 0; i <= top_index; i++) {
                data[i] = old_data[top_index - i];
            }
            delete[] old_data;
            return;
        }
    private:
        Type *data;
        int top_index, size;
    
    };
    
    bool precede(const char &a, const char &b) {
        if ((a == '+' || a == '-') && (b == '*' || b == '/')) {
            return false;
        }
        return true;
    }
    
    int calc(char op, int a, int b) { 
        switch(op) {
            case '+': {
                return a + b;
            } break;
            case '-': {
                return b - a;
            } break;
            case '*': {
                return a * b;
            } break;
            case '/': {
                return b / a;
            } break;
        }
    }
    
    int compute(Stack<char> &s) {
        Stack<char> temp(20);
        int a, b;
        char op;
        while (!s.empty()) {
            if (isdigit(s.top())) {
                temp.push(s.top());
                s.pop();
            }
            else {
                op = s.top();
                s.pop();
                a = temp.top() - '0';
                temp.pop();
                b = temp.top() - '0';
                temp.pop();
                temp.push(calc(op, a, b) + '0');
            }
            
        }
        return temp.top() - '0';
    }
    
    
    int main() {
        string str;
        cin >> str;
        Stack<char> rpn(20);
        Stack<char> opr(20);
        for (int i = 0; i < str.length(); i++) {
            if (isdigit(str[i])) {
                rpn.push(str[i]);
            }
            else {
                while (!opr.empty() && precede(opr.top(), str[i])) {
                    rpn.push(opr.top());
                    opr.pop();
                }
                opr.push(str[i]);
            }
        }
        while (!opr.empty()) {
            rpn.push(opr.top());
            opr.pop();
        }
        rpn.reverse();
        cout << compute(rpn);
    }

    易错用例1:

    1+4/2+1
    1
    4 2 / + 1 + a = 4, b = 2, op = / a = 2, b = 1, op = + a = 3, b = 1, op = + 4

    易错用例2:

    1*2+3*4
    1
    2 * 3 4 * + a = 1, b = 2, op = * a = 2, b = 4, op = * a = 8, b = 3, op = + 11
    Min是清明的茗
  • 相关阅读:
    JS 按钮下一步(onclick点击事件)
    socketserver模块
    进程
    僵尸进程和孤儿进程
    守护进程
    互斥锁
    进程间通信=>IPC机制
    生产者消费者模型
    线程
    守护线程
  • 原文地址:https://www.cnblogs.com/MinPage/p/13940594.html
Copyright © 2020-2023  润新知