简单四则运算之逆波兰式解法小结(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\n",  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] != '\0') {
        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

 

posted @ 2020-11-07 12:16  箐茗  阅读(225)  评论(0编辑  收藏  举报