數據結構課程設計 表達式類型的實現

題目:寫一個程序,實現基於二叉樹表示的算術表達式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;
        }
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章