要求說明:
(1)從鍵盤接收算術表達式,以“#”表示接收結束;
(2)輸出算術表達式的值;
(3)操作數僅限於非負整數,操作符只能是+、-、*、/、^、(、)
(4)可以判斷表達式的合法性(如括號的匹配)
寫作業時遇到的一道題目,覺得比較麻煩,估計以後會有人遇到相同的問題,就寫了篇博客記錄下來。
主要思路:
(1)先將表達式轉化成後綴表達式
(2)逐個讀取後綴表達式,計算結果
轉化成後綴表達式:
(1)設立操作符棧。
(2)設表達式的結束符爲“#”,預設操作符棧的棧底爲“#”。
(3)若當前字符是操作數,則直接發送給後綴式。
(4)若當前字符爲操作符且優先級大於棧頂操作符,則人棧,否則退出棧頂操作符發送給後綴式。
(5)若當前字符是結束符,則自棧頂至棧底依次將棧中所有操作符發送給後綴式。
(6)“(”對它之前後的操作符起隔離作用,則若當前操作符爲“(”時人棧。
(7)“)”可視爲自相應左括號開始表達式的結束符,則從棧頂起,依次退出棧頂操作
符發送給後綴式直至棧頂字符爲“("止。“(”不發送到後綴式。
轉化成後綴表達式函數代碼:
/*SeqStack *L操作符棧,char *str1讀取的表達式,char *str2返回的後綴表達式*/
void Conversion(SeqStack *S,char *str1,char *str2)
{
int i=0;
char *p=str1,e;
//預設操作符棧的棧底爲“#”
Push(S,'#');
while (*p!='\0')
{
//若當前字符不是操作符是操作數,則直接發送給後綴式。
if (!Isoperator(*p))
{
str2[i++]=*p;
}
else
{
if (*p=='(')
Push(S,*p);
else if (*p==')')
{
while(GetTop(S)!='(')
{
Pop(S,&e);
str2[i++]=e;
}
Pop(S,&e); /*pop掉前括號*/
}
else if (*p=='#')
{
while (!IsEmpty(S))
{
Pop(S,&e);
str2[i++]=e;
}
}
else if (Compare(*p,GetTop(S)))
{
Push(S,*p);
}
else if (!Compare(*p,GetTop(S)))
{
Pop(S,&e);
str2[i++]=e;
continue; /*continue應該要加*/
}
}
p++;
}
str2[i-1]='\0'; /*#號也存進去了,所以用'\0'覆蓋掉*/
}
完整計算表達式代碼:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
#define TRUE 1
#define FALSE 0
#define Stack_Size 50
char ops[8]= {'+','-','*','/','(',')','^','#'}; /*運算符數組*/
int priority[8] = {1,1,2,2,0,0,3,-1};
typedef struct
{
char elem[Stack_Size];
int top;
} SeqStack; /*運算符棧的定義*/
typedef struct
{
int elem[Stack_Size];
int top;
} nSeqStack; /* 運算數棧的定義*/
void InitStack(SeqStack *S) /*初始化運算符棧*/
{
S->top =-1;
}
void InitStackn(nSeqStack *S) /*初始化運算數棧*/
{
S->top =-1;
}
int IsEmpty(SeqStack *S) /*判斷棧S爲空棧時返回值爲真,反之爲假*/
{
return(S->top==-1?TRUE:FALSE);
}
int IsEmptyn(nSeqStack *S) /*判斷棧S爲空棧時返回值爲真,反之爲假*/
{
return(S->top==-1?TRUE:FALSE);
}
/*判棧滿*/
int IsFull(SeqStack *S) /*判斷棧S爲滿棧時返回值爲真,反之爲假*/
{
return(S->top==Stack_Size-1?TRUE:FALSE);
}
int IsFulln(nSeqStack *S) /*判斷棧S爲滿棧時返回值爲真,反之爲假*/
{
return(S->top==Stack_Size-1?TRUE:FALSE);
}
int Push(SeqStack *S, char x) /*運算符棧入棧函數*/
{
if (S->top==Stack_Size-1)
{
printf("Stack is full!\n");
return FALSE;
}
else
{
S->top++;
S->elem[S->top]=x;
return TRUE;
}
}
int Pushn(nSeqStack *S, int x) /*運算數棧入棧函數*/
{
if (S->top==Stack_Size-1)
{
printf("Stack is full!\n");
return FALSE;
}
else
{
S->top++;
S->elem[S->top]=x;
return TRUE;
}
}
int Pop(SeqStack *S, char *x) /*運算符棧出棧函數*/
{
if (S->top==-1)
{
printf("運算符棧空!\n");
return FALSE;
}
else
{
*x=S->elem[S->top];
S->top--;
return TRUE;
}
}
int Popn(nSeqStack *S, int *x) /*運算數棧出棧函數*/
{
if (S->top==-1)
{
printf("運算數棧空!\n");
return FALSE;
}
else
{
*x=S->elem[S->top];
S->top--;
return TRUE;
}
}
char GetTop(SeqStack *S) /*運算符棧取棧頂元素函數*/
{
if (S->top ==-1)
{
printf("運算符棧爲空!\n");
return FALSE;
}
else
{
return (S->elem[S->top]);
}
}
int GetTopn(nSeqStack *S) /*運算數棧取棧頂元素函數*/
{
if (S->top ==-1)
{
printf("運算符棧爲空!\n");
return FALSE;
}
else
{
return (S->elem[S->top]);
}
}
int Isoperator(char ch) /*判斷輸入字符是否爲運算符函數,是返回TRUE,不是返回FALSE*/
{
int i;
for (i=0; i<8; i++)
{
if(ch==ops[i])
return TRUE;
}
return FALSE;
}
int Compare(char c1,char c2)
{
int m,n;
/*賦值c1對應的n*/
if (c1=='+' || c1=='-')
m=1;
else if (c1=='*' || c1=='/')
m=2;
else if (c1=='(' || c1==')')
m=0;
else if (c1=='^')
m=3;
else if (c1=='#')
m=-1;
/*賦值c2對應的n*/
if (c2=='+' || c2=='-')
n=1;
else if (c2=='*' || c2=='/')
n=2;
else if (c2=='(' || c2==')')
n=0;
else if (c2=='^')
n=3;
else if (c2=='#')
n=-1;
return m>n;
}
/*SeqStack *L操作符棧,char *str1讀取的表達式,char *str2返回的後綴表達式*/
void Conversion(SeqStack *S,char *str1,char *str2)
{
int i=0;
char *p=str1,e;
//預設操作符棧的棧底爲“#”
Push(S,'#');
while (*p!='\0')
{
//若當前字符不是操作符是操作數,則直接發送給後綴式。
if (!Isoperator(*p))
{
str2[i++]=*p;
}
else
{
if (*p=='(')
Push(S,*p);
else if (*p==')')
{
while(GetTop(S)!='(')
{
Pop(S,&e);
str2[i++]=e;
}
Pop(S,&e); /*pop掉前括號*/
}
else if (*p=='#')
{
while (!IsEmpty(S))
{
Pop(S,&e);
str2[i++]=e;
}
}
else if (Compare(*p,GetTop(S)))
{
Push(S,*p);
}
else if (!Compare(*p,GetTop(S)))
{
Pop(S,&e);
str2[i++]=e;
continue; /*continue應該要加*/
}
}
p++;
}
str2[i-1]='\0'; /*#號也存進去了,所以用'\0'覆蓋掉*/
}
int Calc(char *str)
{
nSeqStack *n,nn;
n=&nn;
int i;
int x,y,result;
char *p=str;
InitStackn(n);
while (*p!='\0')
{
if (!Isoperator(*p))
{
Pushn(n,*p-'0');
}
else
{
Popn(n,&x);
Popn(n,&y);
switch (*p)
{
case '+':
result=y+x;
break;
case '-':
result=y-x;
break;
case '*':
result=y*x;
break;
case '/':
result=y/x; /*假設都能整除*/
break;
case '^':
result=y;
for (i=1;i<x;i++)
{
result=result*y;
}
break;
default:
printf("error\n");
break;
}
Pushn(n,result);
}
p++;
}
return result;
}
int main()
{
/*
*整體步驟
*(1)表達式轉化成後綴表達式
*(2)表達式逐個讀取進行計算
*/
char str1[100],str2[100];
scanf("%s",str1);
SeqStack *s,ss;
s=&ss;
InitStack(s);
Conversion(s,str1,str2);
printf("後綴表達式:%s\n",str2);
int result = Calc(str2);
printf("表達式結果:%d\n",result);
return 0;
}
附:
利用後綴表達式求解,只需要從左向右依次掃描表達式,
(1)遇到操作數人棧,
(2)遇到操作符.則做出棧兩次,獲得兩個操作數,
後出棧的操作數爲第一個操作對象,對它們進行計算,
計算結果作爲下次運算的操作數入棧。
重複上述操作,直到後綴表達式讀取結束,既可完成表達式的計算。