因为找工作的原因,发现自己的数据结构和算法太薄弱了,被虐的很惨,遂下定决心开始从头学习数据结构和算法,就在MOOC上找了一门浙江大学开设的数据结构课程,也特地开了博客来记录一下此次学习之旅,也在这里定下一个目标,希望能够坚持到底,奥利给!!
什么是堆栈
首先从一个非常经典的算术表达式求解问题开始堆栈的学习。
5 + 6 / 2 - 3 * 4
如何求解上面的表达式?
1、表达式由两类对象构成:运算数和运算符号
2、不同的运算符号有不同的优先级
一般,我们见到的算术表达式称为中缀表达式,因为运算符号位于两个运算数之间,如 a + b * c - d / e。
为了方便计算机计算,我们一般将中缀表达式转换为后缀表达式:如a b c * + d e / -.
如何将中缀表达式转换为后缀表达式
需要借助堆栈来实现,按照我们计算表达式的流程,我们从左往右扫描表达式,并用堆栈来记录运算符号,当我们遇到一个运算符号小于先前记录的运算符序列的最后一个时(同优先级符号的从左往右优先级递减),这就表明我们应该事先运算前面的子表达式,所以将堆栈里的运算符弹出,直到在堆栈里遇到的运算符小于当前的预算符号。带括号的表达式中,左括号在堆栈外时,优先级为最高,当在堆栈里时,优先级最低。所以在扫描表达式时遇到左括号直接入入栈,遇到右括号后,开始弹出堆栈里的运算符,直到遇到左括号后,左括号弹出,因为括号优先级最低,所以此时运算符堆栈应该会出清。
转换规则:
这样,我们就完成了从中缀表达式到后缀表达式的转换,接下来,我们可以对该后缀表达式进行求值运算。
后缀表达式的求值策略:
1、首先我们知道,后缀表达式已经将预算符号的优先级和预算数进行了一定的排列,所以我们可以重做往右扫描,逐个处理运算符和运算数。
遇到预算数时:压入堆栈存储,达到记住未参与运算数的目的
遇到预算符号时:将栈里的运算数取出和运算符做运算,然后将运算结果入栈存储
直到扫描到表达式的最末端,结束搜索,做完运算后,栈应该是空的。
贴上我自己的实现:
/** 求后缀表达式 ***/ #include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX_SIZE 1000 typedef char ElementType; typedef struct t_stack { ElementType data[MAX_SIZE]; int top; }Stack_t; typedef Stack_t * pStack; typedef struct t_dstack { ElementType StackBuf[MAX_SIZE]; int top1; int top2; }DStack_t; pStack stack_New(void) { pStack NewStack = (pStack)malloc(sizeof(Stack_t)); memset(NewStack->data, 0, sizeof(NewStack->data)); NewStack->top = -1; return NewStack; } /* 堆栈存储运算发符号 */ pStack stack = NULL; char tempResult[100] = {0}; int charNum = 0; int stack_isEmpty(Stack_t *s) { if (s) { if (s->top == -1) return 1; else return 0; } else return 1; } ElementType pop(pStack s) { if (!stack_isEmpty(s)) { return s->data[(s->top)--]; } } void push(pStack s, ElementType x) { if (s && s->top != MAX_SIZE - 1) { s->data[++(s->top)] = x; } } ElementType stack_gettop(pStack s) { if (!stack_isEmpty(s)) { return s->data[(s->top)]; } else { return -1; } } int tokenLevel(char token) { int level = 0; if (token == '*' || token == '/') { level = 1; } else if (token == '(') { level = -1; } return level; } int tokenCmp(char checktoken) { int ret = 0; char toptoken = stack_gettop(stack); int checklevel = tokenLevel(checktoken); int stacklevel = tokenLevel(toptoken); if (checktoken == ')' && toptoken == '(') { pop(stack); return 0; } if (toptoken == -1) { /* 空栈直接压入操作符号 */ push(stack, checktoken); return 0; } else if (checklevel <= stacklevel || checktoken == ')') { /* 弹出堆栈内的运算符 */ tempResult[charNum++] = pop(stack); tokenCmp(checktoken); } else { push(stack, checktoken); return 0; } return ret; } int main(void) { char expressString [100] = {0}; stack = stack_New(); int ret = 0; while (scanf("%s", expressString) != EOF) { int i = 0; memset(tempResult, 0, sizeof(tempResult)); charNum = 0; while (expressString[i] != '