目錄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]