題目:寫一個程序,實現基於二叉樹表示的算術表達式Expression的操作。
頭文件:應保存爲“Expression.h”
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<ctype.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
//#define OVERFLOW 0
//二叉樹節點類型
typedef enum { INT, CHAR } ElemTag; //INT爲實型,CHAR爲字符型
//二叉樹數據域
typedef struct TElemTag
{
ElemTag tag;
union
{
int num;
char c;
};
} TElemTag;
//二叉樹鏈式存儲結構
typedef struct BiTNode
{
TElemTag data; //數據域
struct BiTNode *lchild, *rchild; //左右孩子指針
} BiTNode, *BiTree;
typedef BiTree SElemType; //棧SqStack的元素
//棧的順序存儲結構
#define STACK_INIT_SIZE 30 //初始存儲空間
#define STACKINCREMENT 5 //存儲空間增量
typedef struct SqStack
{
SElemType *base;
SElemType *top;
int stacksize;
} SqStack;
int InitStack(SqStack *S)
{
(*S).base = (SElemType *) malloc (STACK_INIT_SIZE * sizeof(SElemType));
if(!(*S).base)
exit(OVERFLOW);
(*S).top = (*S).base;
(*S).stacksize = STACK_INIT_SIZE;
return OK;
}
int StackEmpty(SqStack S)
{
if(S.top == S.base)
return TRUE;
else
return FALSE;
}
int Push(SqStack *S, SElemType e) //元素e壓棧
{
if((*S).top - (*S).base >= (*S).stacksize)
{//棧滿,追加存儲空間
(*S).base = (SElemType *) realloc((*S).base, ((*S).stacksize + STACKINCREMENT) * sizeof(SElemType));
if(!(*S).base) //存儲分配失敗
exit(OVERFLOW);
(*S).top = (*S).base + (*S).stacksize;
(*S).stacksize += STACKINCREMENT;
}
*((*S).top)++ = e;
return OK;
}
int Pop(SqStack *S, SElemType *e)
{
if((*S).base == (*S).top)
return ERROR;
*e = *--(*S).top;
return OK;
}
int GetTop(SqStack S, SElemType *e)
{
if(S.top > S. base)
{
*e = *(S.top - 1);
return OK;
}
return ERROR;
}
主程序:
#include"Expression.h"
//判斷是否操作符
int isoperator(char optr)
{
switch(optr)
{
case '+':
case '-':
case '*':
case '/':
case '^': return TRUE;
default: return FALSE;
}
}
//判斷字符a的類型
void Judge(BiTree *E, char a)
{
if(isdigit(a)) //a是常量
{
(*E) -> data.tag = INT;
(*E) -> data.num = a - '0';
}
else //a爲字符
{
(*E) -> data.tag = CHAR;
(*E) -> data.c = a;
}
}
int ReadExpr(BiTree *E, char *expr)
{
int i, len; //len爲expr的長度
SqStack S; //操作符棧
BiTree p, q; //輔助變量
gets(expr);
len = strlen(expr);
//printf("len = %d\n", len);
(*E) = (BiTree)malloc(sizeof(BiTNode)); //申請根節點
(*E) -> lchild = NULL;
(*E) -> rchild = NULL;
if(len == 1) //表達式長度爲1時
{
if(isdigit(expr[0]))
{
(*E) -> data.tag = INT;
(*E) -> data.num = expr[0] - '0';
return OK;
}
else if(isalpha(expr[0]))
{
(*E) -> data.tag = CHAR;
(*E) -> data.c = expr[0];
return OK;
}
else
{
printf("輸入的字符不是運算符也不是變量常量,錯誤!\n");
return ERROR;
}
}
else
{
Judge(E, expr[0]);
InitStack(&S);//初始化棧
q = (*E);
Push(&S, q);//
Push(&S, q);//根結點入棧兩次是爲判斷先序輸入的表達式是不是正確的表達式
for(i = 1; i < len && !StackEmpty(S); i++)
{
p = (BiTree)malloc(sizeof(BiTNode));
Judge(&p, expr[i]);
p -> lchild = NULL;
p -> rchild = NULL;
if(isoperator(expr[i])) //是運算符,運算符入棧
{
if( !q -> lchild ) //左孩子不空,往左走
{
q -> lchild = p;
Push(&S, p);
q = p;
}
else //否則右孩子不空,往右走
{
q -> rchild = p;
Push(&S, p);
q = p;
}
}
else //不是運算符,出棧
{
if( !q -> lchild )
{
q -> lchild = p;
Pop(&S, &q);
}
else
{
q -> rchild = p;
Pop(&S, &q);
}
}
}//end for
if(StackEmpty(S) && i >= len)
{
//printf("SM:%d i:%d", StackEmpty(S), i);
return OK;//表達式爲前綴表達式
}
else
{
//printf("SM:%d i:%d", StackEmpty(S), i);
return ERROR; //不是前綴表達式
}
}
}
//如果兩個字符是運算符,比較兩個運算符的優先級,a比b優先,返回OK,否則返回ERROR
int PriCompare(char a, char b)
{
if(isoperator(a) && isoperator(b))
{
if(a == '^')
{
if(b != '^')
return OK; //a的優先級比b高
else
return ERROR;
}
else if( a == '*' || a == '/')
{
if(b == '*' || b == '/' || b == '^')
return ERROR;
else
return OK;
}
else //其餘a的優先級不比b高
return ERROR;
}
else //不是運算符
return ERROR;
}
//中序遍歷輸出中序綴表達式
void WriteExpr(BiTree E)
{
if(E)//樹不爲空
{
//先遞歸左子樹
if(E -> lchild && E -> lchild -> data.tag == CHAR)//左孩子不空且爲字符
{
if(PriCompare(E -> data.c, E -> lchild -> data.c))//E的優先級比其左孩子的高
{ //帶括號輸出表達式
printf("(");
WriteExpr(E -> lchild);
printf(")");
}
else//不帶括號輸出左子樹
WriteExpr(E -> lchild);
}
else//左子樹
WriteExpr(E -> lchild);
//訪問並輸出根節點
if(E -> data.tag == INT)
{
printf("%d", E -> data.num);
}
else
{
printf("%c", E -> data.c);
}
//後遞歸右子樹
if(E -> rchild && E -> rchild -> data.tag == CHAR)//右孩子不空且爲字符
{
if(PriCompare(E -> data.c, E -> rchild -> data.c))//E的優先級比其右孩子的高
{ //帶括號輸出表達式
printf("(");
WriteExpr(E -> rchild);
printf(")");
}
else//不帶括號輸出右子樹
WriteExpr(E -> rchild);
}
else//輸出右子樹
WriteExpr(E -> rchild);
}
}
//對表達式中的所有變量V的賦值,參數flag爲表示是否賦值過的標誌
void Assign(BiTree *E,char V,int c,int *flag)
{
if(*E)
{
if((*E)->data.tag==CHAR&&(*E)->data.c==V)//如果找到要賦值的變量,賦值
{
(*E)->data.tag=INT;
(*E)->data.num=c;
*flag=1;
}
Assign(&((*E)->lchild),V,c,flag);//遞歸左子樹
Assign(&((*E)->rchild),V,c,flag);//遞歸左子樹
}
}
int powINT(int x, int exp)
{
int i, result = 1;
for(i = 1; i <= exp; i++)
result *= i;
return result;
}
int Operate(int a, char oprt, int b)
{
switch(oprt)
{
case '+':return a + b;
case '-':return a - b;
case '*':return a * b;
case '/':
if(b != 0)
return a / b;
else
{
printf("除數不能爲0\n");
break;
}
case '^':return powINT(a, b);
default:break;
}
}
//檢查是否還有沒賦值的變量
int Check(BiTree E)
{
if(E && E -> data.tag == CHAR)//樹不空且爲結點爲字符
{
if(isalpha(E -> data.c))
return ERROR;
Check(E -> lchild);
Check(E -> rchild);
return OK;
}
}
int Value(BiTree E)
{
if(E)
{
//結點的左右孩子空, 是葉子結點, 返回其值
if(!E -> lchild && !E -> rchild && E -> data.tag == INT)
return E -> data.num;
//以後根遍歷次序求解表達式的值
return Operate(Value(E -> lchild), E -> data.c, Value(E -> rchild));
}
}
void CompoundExpr(char P, BiTree *E1, BiTree E2)
{
BiTree E;
E = (BiTree)malloc(sizeof(BiTNode));
E -> data.tag = CHAR;
E -> data.c = P;
E -> lchild = *E1;
E -> rchild = E2;
(*E1) = E;
printf("\n表達式E複合成功!其表達式變爲:\n");
WriteExpr(E);
}
//輸出選擇菜單
int menu()
{
printf("1.輸入前綴表達式\n");
printf("2.輸出表達式的中綴表示式\n");
printf("3.對變量賦值\n");
printf("4.計算表達式的值\n");
printf("5.構造一個新的複合表達式\n");
printf("0.退出\n\n");
printf("請輸入你的選擇: ");
int choice = -1;
scanf("%d%*c", &choice);
return choice;
}
int main()
{
BiTree E,newE; //二叉樹
char EXPR[81]; //前綴表達式
int flag = ERROR, flag2 = ERROR; //標記表達式是否賦值成功, OK爲成功, ERROR爲失敗
char V; //要賦值的變量
char P; //合併的操作符
while(1)
{
switch(menu())
{
case 1:
do{
printf("請輸入正確的前綴表達式: ");
flag = ReadExpr(&E, EXPR);
if(flag == OK)
printf("表達式構造成功.\n\n");
else
{
printf("表達式構造失敗.\n");
printf("請輸入正確的前綴表達式: ");
}
}while(flag == ERROR);
if(flag == OK)
{
printf("前綴表達式的中綴表示式爲: ");
WriteExpr(E);
printf("\n\n");
}
break;
case 2:
if(flag == OK)
{
printf("前綴表達式的中綴表示式爲: ");
WriteExpr(E);
printf("\n");
}
else
printf("表達式還沒有構造, 請先構造表達式.\n");
break;
case 3:
if(flag == OK)
{
int Assign_tag = ERROR;//是否賦值成功的標記
char ch;//保存要賦值的變量
int n;//保存要賦的值
printf("請輸入要賦值的變量名: ");
ch = getchar();
printf("\n要賦值爲: ");
scanf("%d", &n);
Assign(&E, ch, n, &Assign_tag);
if(Assign_tag == OK)
{
printf("賦值成功!\n");
printf("賦值後表達式爲:");
WriteExpr(E);
printf("\n");
}
else
printf("表達式裏沒有 %c 這個變量!\n", ch);
}
else
printf("表達式還沒有構造, 請先構造表達式.\n");
break;
case 4:
if(flag == OK)
{
int chk = ERROR;
chk = Check(E);
if(chk == OK)//檢查表達式裏是否還有未賦值的變量
{
WriteExpr(E);
printf("=%d\n", Value(E));
}
else
{
printf("表達式裏還有未賦值變量!\n\n");
}
}
break;
case 5:
if(flag == OK)
{
do{
printf("請輸入新的表達式: ");
flag2 = ReadExpr(&newE, EXPR);
if(flag2)
printf("表達式2構造成功.\n");
else
{
printf("表達式2構造失敗.\n");
printf("請輸入正確的前綴表達式.\n");
}
}while(flag2 == ERROR);
printf("前綴表達式2的中綴表示式爲: ");
WriteExpr(newE);
printf("\n\n");
do{
printf("請輸入運算符: ");
P = getchar();
}while(!isoperator(P));
CompoundExpr(P, &E, newE);
printf("複合的前綴表達式的中綴表示式爲: ");
WriteExpr(E);
printf("\n\n");
}
break;
case 0:
printf("\n請按任意鍵退出!\n");
getch();
exit(0);
default:
printf("\n輸入有誤!請按任意鍵回到主菜單重新選擇!\n");
getch();
break;
}
}
}