感谢宫水三叶老师的代码思路;
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)