✅简介:与大家一起加油,希望文章能够帮助各位!!!!
保持学习、保持热爱、认真分享、一起进步!!!
实现一个简单的计算器。通过键盘输入一个包含圆括号、加减乘除等符号组成的算术表达式字符串,输出该算术表达式的值。要求:
(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;
}
}
利用二叉树的性质去解决这个问题反而使问题变得复杂了,大概是想让我们熟练的使用二叉树的相关知识。练习和巩固对二叉树的理解和操作,而不是作为实际解决表达式求值问题的最佳方案。
需要注意的是:我在定义结构体的时候数据域的类型是一个指针。
以上均是个人的理解,如果有不对的地方请各位大佬帮忙斧正!!追光的人,终会光芒万丈!!