双栈实现基本计算器(力扣-224)

感谢宫水三叶老师的代码思路;

AC代码如下

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
char s[300005] ;
typedef struct {
    int *nums;
    char *ops;
    int top_nums;
    int top_ops;
} Stack;

void initStack(Stack *stack, int maxSize) {
    stack->nums = (int *)malloc(maxSize * sizeof(int));
    stack->ops = (char *)malloc(maxSize * sizeof(char));
    stack->top_nums = -1;
    stack->top_ops = -1;
}

void pushNum(Stack *stack, int num) {
    stack->nums[++stack->top_nums] = num;
}

void pushOp(Stack *stack, char op) {
    stack->ops[++stack->top_ops] = op;
}

int popNum(Stack *stack) {
    if (stack->top_nums >= 0) {
        return stack->nums[stack->top_nums--];
    } else {
        return 0;
    }
}

char popOp(Stack *stack) {
    if (stack->top_ops >= 0) {
        return stack->ops[stack->top_ops--];
    } else {
        return '+';
    }
}

int calculate(char *s) {
    Stack stack;
    initStack(&stack, strlen(s));
    pushNum(&stack, 0); // 为了防止第一个数为负数,先往 nums 加个 0
    int n = strlen(s);
    for (int i = 0; i < n; i++) {
        char c = s[i];
        if (c == '(') {
            pushOp(&stack, c);
        } else if (c == ')') {
            while (stack.top_ops >= 0 && stack.ops[stack.top_ops] != '(') {
                int b = popNum(&stack);
                int a = popNum(&stack);
                char op = popOp(&stack);
                pushNum(&stack, op == '+' ? a + b : a - b);
            }
            popOp(&stack); // 弹出左括号
        } else {
            if (isdigit(c)) {
                int cur_num = 0;
                int j = i;
                while (j < n && isdigit(s[j])) {
                    cur_num = cur_num * 10 + (s[j++] - '0');
                }
                pushNum(&stack, cur_num);
                i = j - 1;
            } else {
                if (i > 0 && (s[i - 1] == '(' || s[i - 1] == '+' || s[i - 1] == '-')) {
                    pushNum(&stack, 0);
                }
                while (stack.top_ops >= 0 && stack.ops[stack.top_ops] != '(') {
                    int b = popNum(&stack);
                    int a = popNum(&stack);
                    char op = popOp(&stack);
                    pushNum(&stack, op == '+' ? a + b : a - b);
                }
                pushOp(&stack, c);
            }
        }
    } 
    while (stack.top_ops >= 0) {
        int b = popNum(&stack);
        int a = popNum(&stack);
        char op = popOp(&stack);
        pushNum(&stack, op == '+' ? a + b : a - b);
    }
    return popNum(&stack);
}

int main() {
    scanf("%s",s);
    printf("%d", calculate(s)); 
    return 0;
}

 一 :引入所需要的头文件:

#include <ctype.h>所引用的是isdigit()函数,用来判断括号内的字符是否为整型,是则返回1,否则返回0;

#include <stdlib.h>所引用的是malloc分配空间的函数,为链表后续分配新空间;

#include <string.h>所引用的是strlen()函数,用来输出括号内的字符串长度;

二:定义结构体,分别是数据栈,符号栈,以及两栈的头结点;(+,-,(,)均属于符号)

三:初始化栈,头结点令-1表示为空;

四:将数据压入栈中的函数,++stack->top先移位再赋值; 

        将数据输出的函数,若栈内不为空(top>=0)两栈返回值后再移位;

        若为空,数据栈返回0,符号栈返回+;(为了防止栈出现异常情况而设定的默认值)

五:关键函数calculate函数:

        1,注意stack结构体引用的时候不用加上指针,既Stack stack,因为此时只需要在局部函数内部进行数值的改变即可,不需要再通过指针间接的访问;

        2,在进行入栈之前先往栈中压入数据0,以防第一个数据为负数,导致结果错误。

        3,理清思路,先判断给定字符串的判断位是否为括号,“(”先压入符号栈中,直到遇到下一个“)”再依次往前计算,直到遇到第一个左括号,然后将左括号从符号栈清除;若判断不为括号,再判断是否为数字字符,若是数字,则通过进位依次“-‘0’”来将数字字符转为整型,并压入栈中,返回数位时记得将迭代的变量-1,以保证不会漏掉数位(记不得也可以不加,但不排除会遇到特殊情况);若既不是括号也不是数字,则只可能为加减号,判断此符号前一位是否还是符号,若是,则加上0防止出现错误计算,遇到符号后便开始计算,从两栈提取数据开始运算,一样的不要忘记将前括号弹出;for循环判断全部结束后,再依次对两栈进行最后的数据运算,直到符号栈再无运算符号则代表字符串运算结束;

六:值得注意的是:

        1,其中计算的过程我使用的是令临时变量来获取两栈对应位的数据,再通过判断加减,算得数据后压入数据栈;同时也完成了对应的栈的输入和输出工作;

        2,后括号始终都没有入栈的操作,其终止条件就是遇到第一个前括号为止,依次往前计算的好处就是不用担心括号前的符号对内部进行影响;

        3,在处理计算时:

while(stack.top_ops>=0&&stack.ops[stack.top_ops]!='(');
            {
                int j=i;
                int b=popnum(&stack);
                int a=popnum(&stack);
                char c=popops(&stack);
                pushnum(&stack,c=='+'?a+b:a-b);
            }

注意b在a的前面定义,既b所对应的操作会提前a一步完成,所以之后的a-b中,所一一对应的数位才没有出错(例如,1-3,此时先读入b,既b赋值是3,a便是1,然后进行a-b,对应的便是1-3而不是3-1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值