ZZULI_实现一个简单的计算器(二叉树的性质)

✅简介:与大家一起加油,希望文章能够帮助各位!!!!
保持学习、保持热爱、认真分享、一起进步!!!

 试验任务:

实现一个简单的计算器。通过键盘输入一个包含圆括号、加减乘除等符号组成的算术表达式字符串,输出该算术表达式的值。要求:

(1)系统至少能实现加、减、乘、除等运算;

(2)利用二叉树算法思想求解表达式的值,先构造由表达式构成的二叉树,按中序、后序遍历的方式输出二叉树中的结点,然后再利用通过对二叉树进行后序遍历求解算术表达式的值。

  1. 构造二叉树:

    • 使用栈来实现中序表达式转后序表达式。遍历表达式列表,遇到操作数直接输出,遇到运算符则与栈顶运算符比较优先级,如果栈顶运算符优先级更高,则将栈顶运算符弹出并输出,直到栈为空或栈顶运算符优先级不高于当前运算符,然后将当前运算符入栈。
    • 将栈中剩余的运算符依次弹出并输出,即可得到后序表达式列表。
    • 使用后序表达式列表构造二叉树。遍历后序表达式列表,遇到操作数则创建叶子节点,遇到运算符则创建一个新的节点,该节点的值为运算符,并将运算符的两个操作数作为其左右子树。将节点入栈,依次重复上述过程,直到遍历完后序表达式列表。
  2. 后序遍历二叉树求解表达式的值:

    • 对构造好的二叉树进行后序遍历,遇到操作数则将其值入栈,遇到运算符则从栈中弹出两个操作数,并执行相应的运算,将结果入栈。
    • 最后栈中只剩下一个元素,即表达式的值。

具体代码实现如下:

#include
#include
#include
#include
#define BitreeElemType char*
#define max 100
//定义二叉树的存储结构 
typedef struct _BiNode{
	BitreeElemType data;
	struct _BiNode *lchild,*rchild;
}BiNode, *BiTree;
typedef struct{
	int Stack_n[max];//结果栈 
	int Stack_n_locate[max];//记号 
	char Stack_o[max];//操作符栈 
	int N,O;
} SqStack;
/*
	首先要把中序表达式转化为后续表达式,接着按照在一个个出栈 
*/
int Priority(char op);
void TransForm(char* s[]);
void InitSq(SqStack* Sq);
void Creat_BiTree(char* s[],int size,BiTree* Tree);
void PostOrder(BiTree T);
int RstExpression(BiTree T);
int PerOperation(char op,int a,int b);
int main(){
	char* s[max];
	BiTree Tree;
	TransForm(s);
	int size=0;
	for(int i=0;s[i]!=NULL;i++)
		size++;
	Creat_BiTree(s,size,&Tree);
	printf("OK");
	PostOrder(Tree);
	int sum=RstExpression(Tree);
	printf("运算结果为%d\n",sum);
	for(int i=0;s[i]!=NULL;i++){
		free(s[i]);
	}
	return 0;
}
void InitSq(SqStack* Sq){
	Sq->N=Sq->O=0;
	for(int i=0;iStack_n_locate[i]=0;
	}
} 
void TransForm(char* s[]){
	SqStack Sq;
	//初始化栈
	InitSq(&Sq);
	printf("请输入要计算的表达式:\n");
	char str[100];
	scanf("%s",str);
	int len=strlen(str);
	for(int i=0;i0&&Priority(str[i])<=Priority(Sq.Stack_o[Sq.O-1])){
						//这里直接让操作符强制转换成int型存入结果栈 
						Sq.Stack_n[Sq.N++]=Sq.Stack_o[--Sq.O];
						//标记一下
						Sq.Stack_n_locate[Sq.N-1]=1;
					}
					Sq.Stack_o[Sq.O++]=str[i++]; 
				}
			}	
		}
	}
	while(Sq.O!=0){
		//这里直接让操作符强制转换成int型存入结果栈 
		Sq.Stack_n[Sq.N++]=Sq.Stack_o[--Sq.O];
		//标记一下
		Sq.Stack_n_locate[Sq.N-1]=1;
	}
	for (int t = 0; t < Sq.N; t++) {
	    if (Sq.Stack_n_locate[t] == 1) {
	        // 如果是已经存储的字符,则直接赋值给s[t]
	        char* p=(char*)malloc(sizeof(char)*2);
	        *p=(char) Sq.Stack_n[t];
	        *(p+1)='\0';
			s[t] = p;
	    } else 
		{
		// 如果是数字的话直接转化为字符串,方便后续使用 
		// 分配足够的内存空间来存储转换后的字符串,包括字符串结尾的空字符
		s[t]=(char*)malloc(sizeof(char)*(snprintf(NULL,0,"%d",Sq.Stack_n[t])+1));
		// 将数字转化为字符串并存储在分配的内存空间中
		snprintf(s[t],sizeof(char)*(snprintf(NULL,0,"%d",Sq.Stack_n[t])+1),"%d",Sq.Stack_n[t]);
	    }
	}
	s[Sq.N]=NULL;
}
int Priority(char op){
	switch (op) {
        case '+':
        case '-':
            return 1;
        case '*':
        case '/':
            return 2;
        case '%' :
			return 3; 			
        default:
            return 9;
    }
}
void Creat_BiTree(char* s[],int size,BiTree* Tree){
	BiTree Stack[size+1];
	int high=0;
	for(int i=0;idata=s[i];
			//弹出的第一个元素作为右子树
			p->rchild=Stack[--high];
			//弹出的第二个元素作为左子树 
			p->lchild=Stack[--high];
			//最后将这个元素进栈
			Stack[high++]=p; 
		}else{
			//如果是操作数的话直接进栈 
			BiTree q=(BiTree)malloc(sizeof(BiNode));
			q->data=s[i];
			q->lchild=q->rchild=NULL;
			Stack[high++]=q;
		} 
	}
	*Tree=Stack[--high];
}
void PostOrder(BiTree T) {
if (T==NULL)
return;
PostOrder(T->lchild);
PostOrder(T->rchild);
printf("%s\n", T->data);
}
//后序遍历二叉树,计算结果
int RstExpression(BiTree T){
    if (T == NULL) {
        return 0;
    }

    if (T->lchild == NULL && T->rchild == NULL) {
    	//将字符串直接转化为数字,并且不需要判断是否为数字(叶子节点一定是数字) 
        return atoi(T->data);
    }
    int leftVal = RstExpression(T->lchild);
    int rightVal = RstExpression(T->rchild);
    return PerOperation(*(T->data),leftVal,rightVal);
}
int PerOperation(char op,int a,int b){
		 switch (op) {
		        case '+':
		            return a + b;
		        case '-':
		            return a - b;
		        case '*':
		            return a * b;
		        case '/':
		            return a / b;
		        case '%':
		        	return a % b;
		        default:
		            return 0;
		    }
}

总结: 

利用二叉树的性质去解决这个问题反而使问题变得复杂了,大概是想让我们熟练的使用二叉树的相关知识。练习和巩固对二叉树的理解和操作,而不是作为实际解决表达式求值问题的最佳方案。
需要注意的是:我在定义结构体的时候数据域的类型是一个指针。
以上均是个人的理解,如果有不对的地方请各位大佬帮忙斧正!!

追光的人,终会光芒万丈!!

你可能感兴趣的:(数据结构,数据结构,算法)