1. 程式人生 > >四則運算 C++ 棧實現

四則運算 C++ 棧實現

#include <STDIO.H>
#include <STDLIB.H>

#define MAX_EXP 100         //表示式最大長度
#define MAX_INT 10          //整數最大位數
#define NO_RESULT -99999    //計算異常的返回值

enum node_type{ NUM, OP };

struct node{
    int number;
    char operation;
    enum node_type type;
    struct node *next;
};

struct stack{
    struct
node *top; int length; }; typedef struct node Node; typedef struct stack Stack; int GetResult(const char []); void StringToMidExp(const char [], Stack *); int TenPow(int); void MidExpToBackExp(Stack *, Stack *); int BackExpToResult(Stack *); void ShowStack(const Stack *); void ShowNode(const Node *); void
InitStack(Stack *); void Push(Stack *, Node *); void Pop(Stack *, Node *); void ClearStack(Stack *); void Reverse(Stack *, Stack *); int main(void) { char expression[MAX_EXP]; int result; printf("輸入四則運算表示式:\n"); scanf("%s", expression); result = GetResult(expression); if (result == NO_RESULT) { printf
("表示式有誤,計算失敗。\n"); } else { printf("計算結果是:%d\n", result); } return 0; } //根據表示式的字串計算結果 int GetResult(const char exp[]) { Stack middleExp, backExp; Stack *pm, *pb; pm = &middleExp; pb = &backExp; InitStack(pm); InitStack(pb); StringToMidExp(exp, pm); printf("中綴表示式:"); ShowStack(pm); MidExpToBackExp(pm, pb);//字尾表示式儲存在pb棧中 printf("字尾表示式:"); ShowStack(pb); return BackExpToResult(pb); } //字串轉換成中綴表示式 //棧ps最後儲存的就是原輸入的中綴表示式形式 void StringToMidExp(const char exp[], Stack *ps) { //num陣列用來記錄數字的字元在相應位置上的值,以便後期還原成數值形式 int num[MAX_INT]; int k, n, count, temp; Stack m_stack; Stack *pm; Node *q; k = 0; count = 0; pm = &m_stack; InitStack(pm); while (exp[k] != '\0')//持續迴圈,直到字串處理完畢 { //只要是數字就進行以下處理 if (exp[k] >= '0' && exp[k] <= '9') //數字0到9 { //48是'0'的ASCII碼值 num[count] = exp[k] - 48; //num陣列記錄整數的每一位 count++; //count記錄整數的位數 } //能夠進入這條分支的,就是運算子 else if ((exp[k] >= 40 && exp[k] <= 43) || exp[k] == 45 || exp[k] == 47) //運算子 { //將該運算子之前的字元形式的數字轉換成與之對應的數值型 if (count > 0) { n = 0; temp = 0; //經過該while迴圈,字串形式的數字就被轉換成了數值型 while (n < count) { /** 這裡的TenPow是自己定義的一個函式TenPow(n)就是10的n次方 很明顯,在nun陣列中索引越小的數字位數越高 具體關係就是: 位數 = count-n-1 (n就是num陣列中的索引) */ temp += num[n] * TenPow(count - n -1); //每一位乘以10的某次方 n++; } //申請一個Node大小的記憶體空間,並用Node型指標q指向該地址 //給q的資料域和資料型別域賦值 q = (Node *)malloc(sizeof(Node)); q->type = NUM; q->number = temp; //將q壓進pm棧 Push(pm, q); } //為了下一波數字字串的錄入做準備,需要把count重置為0 count = 0; //位數清零 //運算子前面的數字進棧了,接下來就該運算子進棧了 q = (Node *)malloc(sizeof(Node)); //和上面數字進棧的方式相同,先賦值,然後壓棧 q->type = OP; q->operation = exp[k]; Push(pm, q); } k++; } //既然輸入的是一個算數式,那麼末尾一定是一個數字 //由於沒有運算子了,while迴圈中的else if語句就不會觸發,最後一個數字就不會被轉換 //因此需要在迴圈結束之後處理最後一個數字 if (count > 0) //把最後一個數字轉換出來 { n = 0; temp = 0; while (n < count) { temp += num[n] * TenPow(count - n -1); n++; } q = (Node *)malloc(sizeof(Node)); q->type = NUM; q->number = temp; Push(pm, q); } //顛倒次序之後,在出棧的時候就是按照中綴表示式的從左至右的次序輸出的 //從始至終,pm都只是一個區域性變數,最後的中綴表示式是儲存在ps中的 Reverse(pm, ps); //顛倒一下次序 } //計算10的n次方 int TenPow(int n) { if (n == 0) { return 1; } else { int i, k; i = 0; k = 1; while (i < n) { k *= 10; i++; } return k; } } //中綴表示式轉換成字尾表示式 //有關中綴表示式轉換成字尾表示式的詳細內容,可以參考我的這篇部落格: //http://blog.csdn.net/include_heqile/article/details/79036631 void MidExpToBackExp(Stack *pm, Stack *pb) { Stack tempStack, oprStack; Stack *pt, *pr; Node *q, *r; pt = &tempStack; //臨時儲存字尾表示式 pr = &oprStack; //用來決定運算子的順序 InitStack(pt); InitStack(pr); //這個while迴圈就是中綴表示式轉換為字尾表示式的處理過程 //每一次迴圈,都會從中綴表示式的棧中讀取出一個元素 while (pm->top) { q = (Node *)malloc(sizeof(Node)); Pop(pm, q); //如果讀到的是數字,直接進棧(最終的棧,就是用來儲存字尾表示式的棧) if (q->type == NUM) { Push(pt, q); } else { if (q->operation == '+' || q->operation == '-') { //因為對於+和-運算子來說, //只有 ( 操作符的優先順序比他們低 //這時才會停止彈棧,然後他自己再進棧 while (pr->top && pr->top->operation != '(') { //彈棧,將彈出的操作符入字尾表示式棧 r = (Node *)malloc(sizeof(Node)); Pop(pr, r); Push(pt, r); } //彈棧停止,自己進字尾表示式棧 Push(pr, q); } else if (q->operation == '*' || q->operation == '/') { //對於* / 運算子來講,左括號 ( + - 的優先順序都是比他低的 while (pr->top && pr->top->operation != '(' && pr->top->operation != '+' && pr->top->operation != '-') { r = (Node *)malloc(sizeof(Node)); Pop(pr, r); Push(pt, r); } Push(pr, q); } //左括號是不會進入字尾表示式棧的 else if (q->operation == '(') { Push(pr, q); } else//這個就是q->operation == ')' 的情況 { while (pr->top) { //一直彈棧,直到碰到左括號 if (pr->top->operation == '(') { r = (Node *)malloc(sizeof(Node)); Pop(pr, r); free(r); break; } r = (Node *)malloc(sizeof(Node)); Pop(pr, r); Push(pt, r); } free(q); } } } while (pr->top) //棧內剩餘運算子全部出棧 { r = (Node *)malloc(sizeof(Node)); Pop(pr, r); Push(pt, r); } Reverse(pt, pb); //顛倒一下次序 } //根據字尾表示式計算結果 int BackExpToResult(Stack *ps) { if (!ps->top) //空棧說明表示式有誤 { return NO_RESULT; } Stack tempStack; Stack *pt; Node *q; int num_left, num_right, result; pt = &tempStack; InitStack(pt); while (ps->top) { if (ps->top->type == NUM) { q = (Node *)malloc(sizeof(Node)); Pop(ps, q); Push(pt, q); } else { q = (Node *)malloc(sizeof(Node)); Pop(pt, q); num_right = q->number; free(q); if (!pt->top) //pt棧內沒有第2個數了,說明表示式有誤 { return NO_RESULT; } q = (Node *)malloc(sizeof(Node)); Pop(pt, q); num_left = q->number; free(q); q = (Node *)malloc(sizeof(Node)); Pop(ps, q); switch(q->operation) { case '+': result = num_left + num_right; break; case '-': result = num_left - num_right; break; case '*': result = num_left * num_right; break; case '/': result = num_left / num_right; break; } free(q); q = (Node *)malloc(sizeof(Node)); q->type = NUM; q->number = result; Push(pt, q); } } q = (Node *)malloc(sizeof(Node)); Pop(pt, q); result = q->number; free(q); if (pt->top) //pt棧內還有數字,說明表示式有誤 { return NO_RESULT; } else { return result; } } //顯示棧中元素 void ShowStack(const Stack *ps) { if (ps->top) { Node *p = ps->top; while (p->next) { ShowNode(p); printf(" "); p = p->next; } ShowNode(p); printf("\n"); } else { printf("無\n"); } } //顯示一個節點元素 void ShowNode(const Node *p) { if (p->type == NUM) { printf("%d", p->number); } else { printf("%c", p->operation); } } //初始化棧 void InitStack(Stack *ps) { ps->length = 0; ps->top = NULL; } //節點入棧 void Push(Stack *ps, Node *pn) { pn->next = ps->top; ps->top = pn; ps->length++; } //節點出棧 void Pop(Stack *ps, Node *pn) { if (ps->top) { Node *q = ps->top; pn->next = NULL; pn->number = q->number; pn->operation = q->operation; pn->type = q->type; ps->top = q->next; free(q); ps->length--; } else { pn = NULL; } } //清空棧 void ClearStack(Stack *ps) { Node *q; while (ps->top) { q = ps->top; ps->top = q->next; free(q); ps->length--; } } //反轉棧中元素的次序 void Reverse(Stack *ps1, Stack *ps2) { if (ps1->top) { Node *q; ClearStack(ps2);//先把ps2清空,之後將ps1中的元素依次出棧,然後在壓到ps2中即可 while (ps1->top) { //臨時變數,用來暫時儲存出棧的元素 q = (Node *)malloc(sizeof(Node)); Pop(ps1, q); Push(ps2, q); } } else { ps2->top = NULL; ps2->length = 0; } }