樹結構的應用:表達式類型的實現

#include <iostream>
#include<cmath>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
using namespace std;
struct BiTNode					//結點的數據
{
	bool tag;			//true爲數字,false爲字符		
	int num;
	char c;
	BiTNode *lchild,*rchild;
};

struct SqStack										//順序棧
{
	BiTNode *base;									// 在棧構造之前和銷燬之後,base的值爲NULL 
	int stacksize;									//當前已分配的存儲空間,以元素爲單位 
	int top1;
	BiTNode **address;                        //存儲當前最頂端數據的地址,在構造二叉樹的時候會有地址的存儲返回子樹的根節點

	int InitStack(int n)					// 構造一個空棧S
	{  
		base=new BiTNode[n];
		stacksize=n;
		address=new BiTNode *[n];
		top1=0;             //從0開始存數據
		return OK;
	}

	int StackEmpty()						// 若棧S爲空棧,則返回TRUE,否則返回FALSE 
	{ 
		if(top1==0)   
			return TRUE;
		else  
			return FALSE;
	}

	int Push(BiTNode *e)						// 插入元素e爲新的棧頂元素
	{  
		*(base+top1)=*e;
		address[top1]=e;
		top1++;
		return OK;
	}

	BiTNode* Pop()						// 若棧不空,則刪除S的棧頂元素,用e返回其值,並返回OK;否則返回ERROR/
	{ 
		if(top1<0) return ERROR;
		top1--;
		return address[top1];
	}
};

BiTNode *tree;									//定義樹
SqStack Stack;								 //定義棧,在建立二叉樹的的時候作爲中間變量,存儲部分子樹的根節點

void judge_value(BiTNode *t,char exprstring)		//判斷字符string[i],加引用是爲了在調用函數的時候改變原來t的值
{

	if(exprstring>='0'&&exprstring<='9')		//爲常量
	{
		t->tag=true;
		t->c='#';                              //有數字的時候,字符賦值爲#
		t->num=exprstring-48;
	}
	else									//爲變量
	{
		t->tag=false;
		t->num=-1;                          //當是字符形式,則數字賦值爲-1
		t->c=exprstring;
	}
}

int ReadExpr(char *exprstring,int len)				//以字符序列的形式輸入語法正確的前綴表示式並構造表達式
{
	int i;								//len爲表達式的長度 
	BiTNode *p,*q;
	tree=new BiTNode;					//申請二叉樹的根結點的空間 
	tree->lchild=NULL;
	tree->rchild=NULL;
	if(len==1)											//表達式長度爲1時,二叉樹只有根結點 	
		judge_value(tree,exprstring[0]);			//將exprstring[0]存入二叉樹的結點中 
	else 
	{
		judge_value(tree,exprstring[0]);		//同理
		Stack.InitStack(len);					//初始化棧 
		q=tree;
		Stack.Push(tree);									//入棧 
		Stack.Push(tree);										//入棧,根結點入棧兩次是爲判斷先序輸入的表達式是不是正確的表達式 
		for(i=1;i<len&&!Stack.StackEmpty();i++)
		{
			p=new BiTNode;
			judge_value(p,exprstring[i]);						//將exprstring[i]存入二叉樹的結點中 
			p->lchild=NULL;
			p->rchild=NULL;				
			if(exprstring[i]=='+'||exprstring[i]=='-'||exprstring[i]=='*'||exprstring[i]=='/'||exprstring[i]=='^')
			{											//爲運算符,運算符入棧,左孩子不空,向左孩子走,否則,如果右孩子不空,向右孩子走 
				if(!q->lchild)	
				{
					q->lchild=p;
					Stack.Push(p);
					q=p;
				}
				else	
				{
					q->rchild=p;
					Stack.Push(p);
					q=p;
				}
			}
			else						//不是運算符,運算符出棧 
			{
				if(!q->lchild)	
				{
					q->lchild=p;
					q=Stack.Pop();
				}
				else	
				{
					q->rchild=p;
					q=Stack.Pop();
				}
			}
		}
		if(Stack.StackEmpty()&&i>=len)	return OK;                      //只有棧爲空的時候才把二叉樹構造成功
		else	
		{
			cout<<"                      輸入的字符串無法構造成表達式!"<<endl;
			return ERROR;
		}
	}
	return OK;
}
int Compare(char c1,char c2)				//比較兩個運算符的優先級,c1比c2優先,返回OK,否則返回ERROR 
{		
	if((c1=='^'||c1=='*'||c1=='-'||c1=='+'||c1=='/')&&(c2=='^'||c2=='*'||c2=='-'||c2=='+'||c2=='/'))		//c1和c2爲運算符 
	{
		if(c1=='^')							//c1爲指數運算符,則當c2不爲'^'時,c1比c2優先 
		{
			if(c2!='^') return OK;
			else return ERROR;
		}
		else if(c1=='*'||c1=='/')					//c1爲乘法或除法運算符,則當c2爲'+'或'-',c1比c2優先 
		{
			if(c2=='^'||c2=='*'||c2=='/') return ERROR;
			else return OK;
		}
		else return ERROR;					//其餘,c1不比c2優先 
	}
	else return ERROR;				//c1和c2不是運算符 
}
	

void WriteExpr(BiTNode *Tree)						//用帶括弧的中綴表示式輸出表達式
{
	if(Tree)										//樹不爲空 
	{												//先遞歸左子樹 
		if(Tree->lchild&&!Tree->lchild->tag)		//二叉樹的左孩子不爲空,且左孩子爲字符 
		{
			if(Compare(Tree->c,Tree->lchild->c))    //Tree->c的優先級大於Tree->lchild->c必須帶有並輸出() 
			{
				cout<<"(";
				WriteExpr(Tree->lchild);
				cout<<")";
			}
			else									//否則,不帶括弧輸出左子樹 	
				WriteExpr(Tree->lchild);			
		}
		else 										//否則,輸出左子樹 
			WriteExpr(Tree->lchild);				
			
		if(Tree->tag)								//訪問輸出根結點的值 
		{
			cout<<Tree->num;
		}
		else
			cout<<Tree->c;
			
		if(Tree->rchild&&!Tree->rchild->tag)				//後遞歸右子樹,樹的右孩子不爲空,且右孩子爲字符 
		{
			if(Compare(Tree->c,Tree->rchild->c))			//Tree->c比Tree->rchild->c優先 
			{
				cout<<"(";
				WriteExpr(Tree->rchild);
				cout<<")";
			
			}													//帶括弧輸出右子樹 
			else 
				WriteExpr(Tree->rchild);							//否則,不帶括弧輸出右子樹 
		}
		else 
			WriteExpr(Tree->rchild);//否則,輸出右子樹 
	}
}
//賦值語句

void Assign(BiTNode *Tree,char V,int c,int *flag)
{
	if(Tree)
	{
		if(Tree->tag==false&&Tree->c==V)		//如果找到要賦值的變量,賦值 
		{
			Tree->tag=true;
			Tree->num=c;
			*flag=1;
		}
		Assign(Tree->lchild,V,c,flag);//遞歸左子樹 
		Assign(Tree->rchild,V,c,flag);//遞歸左子樹 
	}
}

int Check(BiTNode *Tree)                   //檢查二叉樹中是否還存在沒有賦值的變量,以便求算數表達式的值 
{
	if(Tree&&Tree->tag==false)            //二叉樹不爲空,並且根節點爲字符
	{		
		if(Tree->c!='*'&&Tree->c!='^'&&Tree->c!='-'&&Tree->c!='+'&&Tree->c!='/')return ERROR;        //是字符但不是運算符
		if(Check(Tree->lchild))               //遞歸左子樹 
			Check(Tree->rchild);              //遞歸右子樹 	
	}
}

int Calculate(int n1,char opr,int n2)             //運算符計算,返回計算結果值
{
	int result;
	switch(opr)                                   //匹配多種情況
	{
		case '+':
			result=n1+n2;
			return result;
			break;
		case '-':
			result=n1-n2;
			return result;
			break;
		case '*': 
			result=n1*n2;
			return result;
			break;
		case '/':
			result=n1/n2;
			return result;
			break;
		case '^':
			result=pow(n1,n2);
			return result;
			break;
		default:break;
	}	
}
int Value(BiTNode *Tree)                   //計算返回整個表達式的值
{
	if(Tree)							//二叉樹不爲空 
	{
		if(!Tree->lchild&&!Tree->rchild&&Tree->tag) return (Tree->num);    //結點的左孩子和右孩子爲空,爲葉子結點,返回結點的值 
		return Calculate(Value(Tree->lchild),Tree->c,Value(Tree->rchild));   //運算求值,後根遍歷的次序對表達式求值 
	}
}
void main()
{
	char Expr_string[1000];                           //存放剛開始輸入的字符串
	int n,ttt=1;
	while(ttt)
	{
con:	cout<<"                 是否還要計算,是請按1,否請按0:";
		cin>>ttt;
		system("cls");
		flushall();                              //輸入之前清理緩衝區
		cout<<"                       請輸入前綴表達式:";
		cin.getline(Expr_string,1000);                //從鍵盤輸入一串字符串作爲表達式
		n=strlen(Expr_string);
		if(n==1)                                 //輸入的表達式字符串長度爲1
		{
			if(Expr_string[0]=='+'||Expr_string[0]=='-'||Expr_string[0]=='*'||Expr_string[0]=='/'||Expr_string[0]=='^')//輸入的表達式只有一個運算符 
			{ 
				cout<<"                       表達式只有一個運算符,錯誤!"<<endl;
				goto con;
			} 
			else 
				if((Expr_string[0]>='0'&&Expr_string[0]<'9')||(Expr_string[0]>='a'&&Expr_string[0]<='z')||(Expr_string[0]>='A'&&Expr_string[0]<='Z'))
				{ 
					cout<<"                       表達式只有一個字符"<<endl;
					goto con;
				}
				else 
				{
					cout<<"     輸入的字符不是運算符也不是變量或常量,錯誤!"<<endl;
					goto con;
				}
		}
		if(ReadExpr(Expr_string,n))
		{
				cout<<"                       二叉樹構造成功!"<<endl;
				cout<<"                       中綴表達式爲:";
				WriteExpr(tree);
				cout<<endl;
			int s=0,Assign_flag=0,t=Check(tree);              //s記錄有幾個變量
			while(!t)                  //檢驗表達式中是否有變量,如果有的話就重新賦予整數值,跳出循環式則整個表達式完整
			{
				if(t)cout<<"                       表達式不存在未賦值的變量!"<<endl;
				else
				{
					int c;char V;
					cout<<"                       表達式中存在變量未賦值!"<<endl;
					cout<<"                       請輸入要賦值的值:";	cin>>V;
					cout<<"                       請輸入要將賦值爲:";	cin>>c;
					Assign(tree,V,c,&Assign_flag);                 //把所有的要賦予的值全在Assign賦值完成
					if(Assign_flag)	
					{
						cout<<"                       賦值成功!"<<endl;
					}
					else
					{
						cout<<"表達式裏沒有"<<V<<",請重新輸入!"<<endl;
					}
				}
				t=Check(tree);
			}
			cout<<"                       整個表達式賦值成功!"<<endl;
			cout<<"                       表達式爲:";
			WriteExpr(tree);
			cout<<endl;
			int result=Value(tree);
			cout<<"                       算數表達式的值爲: ";
			WriteExpr(tree);
			cout<<"="<<result<<endl;
		}
		else
			goto con;
	}
}


測試數據:

0
a
-91
+a*bc
+*5^x2*8x
+++*3^x3*2^x2x6
-^+5a32
--+++*3^x3*2^x2x6

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