動手敲程式碼——棧(經典問題練習)
阿新 • • 發佈:2019-01-29
/*用棧實現計算器*/
/*經典的用來練習棧的題目,需要藉助逆波蘭表示式*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define MAXSIZE 64
#define OK 1
#define ERROR 0
typedef struct
{
int data[MAXSIZE];
int top;
}stacknode;
/*建立一個順序棧*/
stacknode * sqstack_create(void)
{
stacknode * p;
p = (stacknode *)malloc(sizeof (*p));
assert(p); //分配空間後加上斷言是個好習慣
p->top = -1;
return p;
}
/*入棧操作*/
int sqstack_push(int n, stacknode * p)
{
if(p->top == (MAXSIZE - 1)) //棧滿
{
return ERROR;
}
p->data[++p->top] = n;
return OK;
}
/*出棧操作*/
int sqstack_pop(int *dest, stacknode * p)
{
if (p->top == -1) //棧空
{
return ERROR;
}
*dest = p->data[p->top--];
return OK;
}
/*獲取棧頂值*/
int sqstack_top(int *dest, stacknode *p) //const修飾指標*p,p指向的內容不可改變
{
if(p->top == -1) //棧空
{
return ERROR;
}
*dest = p->data[p->top];
return OK;
}
/*列印棧中內容*/
int sqstack_print(stacknode *p)
{
int n = p->top;
if(n == -1) //棧空
{
return ERROR;
}
while(n)
{
printf(" %d ",p->data[n--]);
}
printf(" %d ",p->data[n]);
printf("\n");
}
/*判斷棧是否為空*/
int sqstack_is_empty(stacknode *p)
{
return (p->top == -1);
}
/*優先順序判斷函式*/
int get_priority(int ope)
{
switch (ope)
{
case '+':
case '-':return 1;
case '*':
case '/':return 2;
case '(':return 0;
default:return ERROR;
}
}
/*提取兩個數和一個操作符進行計算,得到的結果再壓棧*/
void compute(stacknode *pnum,int ope)
{
int num1,num2;
int result;
sqstack_pop(&num1,pnum);
sqstack_pop(&num2,pnum);
switch (ope)
{
case '+': result = num1 + num2;
case '-': result = num1 - num2;
case '*': result = num1 * num2;
case '/': result = num1 / num2;
}
sqstack_push(result,pnum);
}
/*進行優先順序計算*/
void deal_ope(stacknode *pnum,stacknode *pope,int ope)
{
int old_ope;
if(sqstack_is_empty(pope)||ope == '(') //當空棧或符號為( 時,將符號壓棧後返回
{
sqstack_push(ope,pope);
return;
}
sqstack_top(&old_ope,pope); //得到棧頂元素
if(get_priority(ope)>get_priority(old_ope)) //比較優先順序,入參的符號優先順序大於棧頂元素時, 將符號壓棧後返回
{
sqstack_push(ope,pope);
return;
}
while(get_priority(ope)<=get_priority(old_ope))
{
sqstack_pop(&old_ope,pope);
compute(pnum,old_ope); //以棧頂符號計算 後壓棧
if(sqstack_is_empty(pope))
{
break;
}
sqstack_top(&old_ope,pope);
}
sqstack_push(ope,pope); //將新的操作符入棧
}
//處理括號 ,進行括號裡的高優先順序計算,之後將計算結果壓入數字棧,並且將括號丟棄
void deal_bracket(stacknode *pnum,stacknode *pope)
{
int old_ope;
sqstack_top(&old_ope,pope); //得到符號棧棧頂元素
while(old_ope != '(')
{
sqstack_pop(&old_ope,pope); //符號棧出棧
compute(pnum,old_ope); //計算後將結果壓入數字棧
sqstack_top(&old_ope,pope); //得到棧頂元素,進行下一次迴圈
}
sqstack_pop(&old_ope,pope); //將( 出棧丟去
}
int main()
{
/*str為表示式陣列*/
char str[MAXSIZE];
printf("請輸入你要計算的表示式:\n");
gets(str);
int i = 0;
int value = 0; //數字的值
int flag = 0;
int old_ope;
stacknode *pnum,*pope; // 定義兩個指向棧結構體的指標
pnum = sqstack_create(); // 建立存放數字的棧
pope = sqstack_create(); // 建立存放運算子號的棧
/* 表示式字串解析函式,然後將高優先順序的符號/(*)進行計算重新入棧
退出while大家的優先順序都一樣+-*/
while (str[i] != '\0')
{
//獲取輸入的數字
if (str[i] >= '0' && str[i] <= '9')//num
{
value = value * 10 + str[i] - '0';
flag = 1;
}
else//ope
{
if (flag)
{
//flag = 1說明value裡面儲存了數字,將其入棧
sqstack_push (value, pnum);
//num標誌清零,value存放數字的變數清零
flag = 0;
value = 0;
}
if(str[i] == ')')
{
//如果是右括號,則
deal_bracket(pnum,pope);
}
else//+-*/(等情況
{
deal_ope(pnum,pope,str[i]);
}
}
i++;
}
//如果flag = 1.說明value裡面還有數值,將其入棧
if (flag)
{
sqstack_push(value,pnum);
}
//然後將符號與數字依次出棧計算。數字出棧計算完成之後回再次在compute中入棧
while (!sqstack_is_empty(pope))
{
sqstack_pop(&old_ope,pope);
compute(pnum,old_ope);
}
//取出數字棧最後剩下的數字,就是最後的答案
sqstack_pop(&value,pnum);
//列印結果
printf("%s = %d\n",str,value);
return 0;
}