目录python
计算机如何进行表达式求值?算法
例:算术表达式\(5+6/2-3*4\),正确理解:\(5+6/2-3*4=5+3-3*4=8-3*4=8-12=-4\)数组
例:\(62/3-42*+=?\)app
后缀表达式求值策略:从左向右“扫描”,逐个处理运算数和运算符号函数
启示:须要有种存储方法,能顺序存储运算数,并在须要时“倒序”输出。性能
例:\(62/3-42*+=?\)spa
时间复杂性能:\(T(N)=O(N)\)3d
堆栈(Strack):具备必定操做约束的线性表,只在一端(栈顶,Top)作插入、删除指针
类型名称:堆栈(Stack)code
数据对象集:一个有0个或多个元素的有穷线性表。
操做集:长度为\(MaxSize\)的堆栈\(s\in{Stack}\),堆栈元素\(item\in{E}lementType\)
Stack CreateStack(int MaxSize)
:生成空堆栈,其最大长度为\(MaxSize\);int IsFull(stack S, int MaxSize)
:判断堆栈\(S\)是否已满;void Push(Stack S, ElementType item)
:将元素\(item\)压入堆栈;int IsEmpty(Stack S)
:判断堆栈\(S\)是否为空;ElementType Pop(Stack S)
:删除并返回栈顶元素;\(Push\)和\(Pop\)能够穿插交替进行;
按照操做系列
Push(S,A),Push(S,B),Push(S,C),Pop(S),Pop(S,Pop(s)
堆栈输出是:\(CBA\)Push(S,A),Pop(S),Push(S,B),push(S,C),Pop(S),Pop(S)
堆栈输出是:\(ACB\)例:若是三个字符按\(ABC\)书序压入堆栈:\(ABC\)的全部排列不必定都是出栈的序列,没法产生\(CAB\)这样的序列。
栈的顺序存储结构一般由一个一维数组和一个记录栈顶元素位置的变量组成。
/* c语言实现 */ # define Maxsize <储存数据元素的最大个数> typedef struct SNode *Stack; struct SNode{ ElementType Data[MaxSize]; int Top; }
/* c语言实现 */ void Push(Stack PtrS, ElementType item) { if(PtrS->Top == Maxsize-1){ printf("堆栈满"); return; }else{ PtrS->Data[++(PtrS->Top)] = item; /* 先+再返回 */ return; } }
/* c语言实现 */ ElementType Pop(Stack PtrS) { if(PtrS->Top == -1){ printf("堆栈空");, return ERROR; /* ERROR是ElementType的特殊值,标志错误 */ }else return (PtrS->Data[(PtrS->Top)--]); /* 先返回再- */ }
分析:一种比较聪明的方法是使这两个栈分别从数组的两头开始向中间生长;当两个栈的栈顶指针相遇时,表示两个栈都满了。
/* c语言实现 */ # define MaxSize <存储数据元素的最大个数> struct DStack{ ElementType Data[MaxSize]; int Top1; /*堆栈1的栈顶指针 */ int Top2; /*堆栈2的栈顶指针 */ } S; S.Top1 = -1; S.Top2 = MaxSize;
void Push(struct DStack *PtrS, ElementType item, int Tag) { /* Tag做为区分两个堆栈的标志,取值为1和2 */ if (PtrS->Top2 - PtrS->Top1 == 1){ /*堆栈满*/ printf("堆栈满"); return; } if (Tag == 1) /* 对第一个堆栈操做 */ Ptrs->Data[++(PtrS->Top1)] = item; else /*对第二个堆栈操做 */ Ptrs->Data[--(PtrS->Top2)] = item; }
/* c语言实现 */ ElementType Pop(struct DStack *PtrS, int Tag) { /* Tag做为区分两个堆栈的标志,取值为1和2 */ if (Tag == 1){ /* 对第一个堆栈操做 */ if (PtrS->Top1 == -1){ /* 堆栈1空 */ printf("堆栈1空"); return NULL; } else return PtrS->Data[(PtrS->Top1)--]; } else { /* 对第二个堆栈操做 */ if (PtrS->Top2 == MaxSize){ /* 堆栈2空 */ printf("堆栈2空"); return NULL; }else return PtrS->Data[(PtrS->Top2)++]; } }
栈的链式存储结构实际上就是一个单链表,叫作链栈。插入和删除操做只能在链栈的栈顶进行。栈顶指针Top应该在链表的开始;若是栈顶指针放在链表尾部,没法进行出栈操做,由于单链表出栈时找不到前一个结点。
/* c语言实现 */ typedef struct SNode *Stack; struct SNode{ ElementType Data; struct SNode *Next; };
/* c语言实现 */ Stack CreateStack() { /* 构建一个堆栈的头结点,返回指针 */ Stack S; S = (Stack)malloc(sizeof(struct SNode)); s->Next = NULL; return S; }
/* c语言实现 */ int IsEmpty(Stack S) { /* 判断堆栈S是否为空,若为空函数返回整数1,不然返回0 */ return (s->Nesxt == NULL); }
/* c语言实现 */ void Push(ElementType item, Stack S) { /* 将元素item压入堆栈S */ struct SNode *TmpCell; TmpCell = (struct SNode *)malloc(sizeof(struct SNode)); TmpCell->ELement = item; TmpCell->Next = S->Next; S->Next = TmpCell; }
牢记链表头才是栈顶
/* c语言实现 */ ElementType Pop(Stack S) { /* 删除并返回堆栈S的栈顶元素 */ struct SNode *FirstCell; ElementType TopElem; if (IsEmpty(S)){ printf("堆栈空"); return NULL; } else { FirstCell = S->Next; S->Next = FirstCell->Next; TopElem = FirstCell->Element; free(FirstCell); return TopElem; } }
回忆:应用堆栈实现后缀表达式求值的基本过程:从作到右读入后缀表达式的各项(运算符或运算数)
运算数:入栈;
最后,堆栈顶上的元素就是表达式的结果值。
基本策略:将中缀表达式转换为后缀表达式,而后求值
如何将中缀表达式转换为后缀?
观察一个简单例子:\(2+9/3-5\quad->\quad{2\,9\,3/+5-}\)
例:\(a*(b+c)/d=?\quad-->\quad{a}\,b\,c+*d/\)
注意:\((\)的优先级大于*,括号内的\(+\)的优先级大于括号外的*,遇到\()\)应该消除前一个\((\)
时间性能:\(T(N)=O(N)\)
从头至尾读取中缀表达式的每一个对象,对不一样对象按不一样的状况处理。
\((2*(9+6/3-5)+4)\)
# python语言实现 class Stack(object): def __init__(self): self.stack = [] def push(self, value): # 进栈 self.stack.append(value) def pop(self): # 出栈 if self.stack: self.stack.pop() else: raise LookupError('stack is empty!') def is_empty(self): # 若是栈为空 return bool(self.stack) def top(self): # 取出目前stack中最新的元素 return self.stack[-1]