数据结构——计算器实现1(C语言)
程序执行路线:表达式——>表达式树——>使用数的遍历进行计算
程序缺点:没有健壮性。因为是直接从缓存中读出并进行树的建造。
处理方式:使用其他的数据结构进行数据的存储和对运算表达式的语法检测,从而使用于建树的表达式总是正确且合法的
/*项目1:
Work :Calculator
Author :yrc
Version :?
CopyRight :You Notice CopyRight
Description :使用树的数据结构完成计算器的功能
初始功能:1、有括号版本,4、默认输入表达式正确(程序没有健壮性),实现多位数运算,程序输入不能存在负数
代码问题1:被恶意篡改
程序已改进:1、输入带括号的表达式并建立树(递归) ; 2、使用char* = (cha*)malloc(sizeof(char)*n),实现多位数运算
程序待改进:1、增强程序健壮性:使用队列处理输入的数据,进行基础的语法排错。2、实现小数运算(修改代码细节:字符数组转数字)
//////////////////////
*/
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#define Max_Size 10
#define AddSize 3
#define MAX_Value 20 //默认运算数最大为10位
typedef char* Char;
typedef struct BiNode //建立树的结点结构
{
char *data; //数据域
struct BiNode *lChild; //左孩子指针
struct BiNode *rChild; //有孩子指针
} BiNode,*BiTree;
typedef struct sqlStack //建立栈结构
{
BiTree* base; //栈底记录指针
BiTree* top; //栈顶记录指针
int StackSize; //记录总空间
}*SqlStack,StackHead;
int Init_Satck(SqlStack S) //初始化栈
{
S->base = (BiTree*)malloc(sizeof(BiTree)*Max_Size); //为栈分配堆空间
if(S->base == NULL)
{
printf("Memory Allocate is Failure!\n"); //提示栈空间分配失败
exit(1); //空间分配失败,则程序强制退出
}
S->top = S->base; //初始时,栈顶与指向栈底
S->StackSize = Max_Size; //记录栈空间大小
return 1; //返回创建成功
}
int IsEmpty_S(SqlStack S) //判断栈是否为空
{
if(S->top == S->base) //栈为空时,栈顶指向栈底
{
return 1; //返回栈为空
}
else
{
return 0; //返回栈非空
}
}
int Stack_push(SqlStack S,BiTree new_node) //元素入栈
{
/**
*1、先判断是否已经满栈,若满栈则进行空间的再分配。
*2、栈空间足够,进行数据元素的入栈。
***/
if((S->top - S->base) >= S->StackSize) //将栈当前使用的空间与栈总空间进行比较
{
S->base = (BiTree*)realloc(S->base,(S->StackSize+AddSize)*sizeof(BiTree)); //栈满则利用realloc()进行空间的再分配
if(S->base == NULL) //判断空间分配结果
{
printf("Memory Allocate is Failure!\n");
exit(1);
}
}
*(S->top)++ = new_node; //元素入栈,并使栈顶指针后移(栈顶指针永远指向为空)
return 1; //返回元素入栈成功
}
int Stack_Pop(SqlStack S,BiTree *top_node) //数据元素出栈
{
/**
*1、先判断是否为栈空,栈空则直接返回出栈失败。
*2、栈非空,则进行数据元素的出栈。
*3、因为默认栈顶指针指向的位置为空,所以当元素被取出后,则默认栈位为空,实际上数据元素仍然存在,
*只是在等待下一次元素入栈后进行栈位覆盖。
**/
if(IsEmpty_S(S)) //判断栈是否为空
{
printf("data_Stack is Empty!\n");
return 0; //返回出栈失败
}
else
{
*(top_node) = *(--(S->top)); //栈顶指针前移,获得第一个数据元素并取出
return 1; //返回出栈成功
}
}
int Stack_getTop(SqlStack S, char *ch,BiTree *temp) //获得栈顶元素的值
{
/**
*函数问题:此函存在问题,当不传入temp时,temp会被恶意更改
*函数功能:1、先判断栈是否为空,如果为空,则返回栈顶元素获取失败。
* 2、如果非空,则获得栈顶指针的前一个栈位置,并通过解引用获得元素的值。
*
***/
printf("temp2的值:%p\n",*temp); //测试语句
if(IsEmpty_S(S)) //判断栈是否为空
{
printf("Stack is Empty!\n");
return 0; //栈为空,则返回栈顶元素获取失败
}
else
{
printf("前一个temp2的地址:%p\n\n",*(S->top - 1)); //测试语句
BiTree agent = *((S->top)-1); //获得栈顶指针的前一个栈位
*ch = *(agent->data); /*语法正确性未检测*/ //保存获得的值
//测试语句
printf("运算符栈顶元素:%c\n\n",*ch); //测试语句
printf("temp2的值:%p\n",*temp); //测试语句
return 1; //返回栈顶元素获取成功
}
}
int get_priority(char ch1, char ch2) //判断前后元算符优先级
{
/**
*算法原理:1、假设+和-优先级为1,/和*优先级为2,并默认优先级2大于优先级1,
* 当后进运算符与先进运算符相同时,则判断为前一个运算符更优先。
* 2、当后进运算符优先级为1,则默认前一个运算符优先
* 3、当后进运算符优先级为2,则判断前一个运算符,如果前一个运算符优先级为2,则前一个运算符优先级高
*如果前一个运算符优先级为1,则前一个运算符优先级低。
***/
if(ch2 == '+' || ch2 == '-') //后进运算符优先级为1
{
return 1;
}
else
{
if(ch1 == '/' || ch1 == '*') //后进运算符为2,且先进运算符为2
{
return 1;
}
else
{
return 0;
}
}
}
int Create_BiTree(BiTree parent,BiTree lson,BiTree rson) //建立子树
{
/**
* 1、先判断双亲结点是否为空
* 2、若双亲结点非空,则创建双亲的左右孩子。
**/
if(parent)
{
parent->lChild = lson; //为双亲建立左孩子
parent->rChild = rson; //为双亲建立有孩子
return 1; //返回子树创建成功
}
else
{
return 0; //返回子树创建失败
}
}
int InorderTraverse(BiTree T) //数的遍历
{
/***
*遍历原理:使用递归进行树的遍历,并且通过改变根结点的访问顺序,获得不同的遍历结果。
*1、建议采用中根遍历,如果遍历结果等于输入结果,则树表达式树建立成功。
*2、先判断根结点是否为空,为空,则进行递归的回返
*3、通过不同的遍历规则,排列代码语句
**/
int i=0;
if(T)
{
/**
*此处使用的是中根遍历
*/
if(T->lChild)
InorderTraverse(T->lChild);
while(T->data[i]!='\0')
{
printf("%c",T->data[i++]);
}
if(T->rChild)
InorderTraverse(T->rChild);
}
else
return 0;
}
int preorderTrvaerse(BiTree T)
{
int i=0;
if(T)
{
/**
*此处使用的是中根遍历
*/
while(T->data[i]!='\0')
{
printf("%c",T->data[i++]);
}
if(T->lChild)
preorderTrvaerse(T->lChild);
if(T->rChild)
preorderTrvaerse(T->rChild);
}
else
return 0;
}
int postOrderTrvaerse(BiTree T)
{
int i=0;
if(T)
{
/**
*此处使用的是中根遍历
*/
if(T->lChild)
postOrderTrvaerse(T->lChild);
if(T->rChild)
postOrderTrvaerse(T->rChild);
while(T->data[i]!='\0')
{
printf("%c",T->data[i++]);
}
}
else
return 0;
}
int GetBiTDepth(BiTree T)
{
/**
*
*算法原理:使用递归达到所有的叶子节点,并通过递归回返,使双亲获得自己左右孩子所能达到的最大深度,
*并将左右孩子的最大深度当作双亲的深度,并最终回溯到根结点(根结点的深度也是为所有孩子深度的最大值)。
*
****/
int LH, RH; //记录左右孩子返回的深度
if(T == NULL) //递归结束条件
return 0;
LH = GetBiTDepth(T->lChild);
RH = GetBiTDepth(T->rChild);
/***
*return RH >=LH ? RH+1:LH+1;
*
**/
if(RH > LH)
return RH+1;
return LH+1;
}
int InitArray_digit(char* dight) //将记录数字的数字每个位都置为#
{
char *temp = dight; //使用代理指针
while(*temp!='\0') //
{
*temp = '\0';
temp++;
}
return 1;
}
int digit_copy(Char *ch1, char *ch2,int len) //实现操作ch1 = ch2;
{
*ch1 = (char*)malloc(sizeof(char)*(len+1));
(*ch1)[len] = '\0';
int i=0;
while(i<len)
{
(*ch1)[i] = ch2[i];
i++;
}
return 0;
}
void Clear_BiTree(BiTree T)
{
if(T)
{
if(T->lChild) Clear_BiTree(T->lChild);
if(T->rChild) Clear_BiTree(T->rChild);
free(T->data);
free(T->lChild);
free(T->rChild);
}
}
BiTree build_process()
{
int i;
int flag = 1,value_count,K_flag=0;
char ch,pre_ch; //记录前后字符
char temp_value[MAX_Value+1]; //定义临时数组
BiTree lson = NULL,rson = NULL,Bi_parent = NULL,temp1 = NULL,temp2 = NULL; //定数树的基本家庭成员
StackHead digit_Satck; //数字栈
StackHead Operate_Satck; //运算符栈
Init_Satck(&digit_Satck); //初始化栈
Init_Satck(&Operate_Satck);
value_count = 0;
temp_value[MAX_Value] = '\0';
InitArray_digit(&temp_value);
while((ch = getchar())!='\n') /*遍历输入的字符串*/
{
if(isdigit(ch)) /*判断是否为数字*/
{
if(value_count<=20)
temp_value[value_count++] = ch;
}
else
{
switch(ch)
{
/**
*
*括号处理代码未完善
**/
case '(':
temp1 = build_process();
//测试语句
printf("得到的根节点的书为:");
K_flag = 1;
//测试语句
break;
case ')':
/**
* 此处代码未完善
*
***/
temp1 = (BiTree)malloc(sizeof(BiNode)); //临时数字结点
digit_copy(&(temp1->data),temp_value,value_count);
temp1->lChild = NULL;
temp1->rChild = NULL;
Stack_push(&digit_Satck,temp1); //数字数据入栈
while(!IsEmpty_S(&Operate_Satck))
{
Stack_Pop(&Operate_Satck,&Bi_parent);
Stack_Pop(&digit_Satck,&rson);
Stack_Pop(&digit_Satck,&lson);
Create_BiTree(Bi_parent,lson,rson);/*构建子树*/
Stack_push(&digit_Satck,Bi_parent);
}
return Bi_parent;
break;
case '.':
if(value_count<=20)
temp_value[value_count++] = ch;
break;
default:
temp2 = (BiTree)malloc(sizeof(BiNode)); //临时字符结点
temp2->data = (char*)malloc(sizeof(char)*2);
temp2->data[1] = '\0';
if(temp2 == NULL || temp2->data == NULL)
{
printf("Memory Allocate is Failure!\n");
exit(1);
}
temp2->lChild = NULL;
temp2->rChild = NULL;
temp2->data[0] = ch;
if(!K_flag)
{
temp1 = (BiTree)malloc(sizeof(BiNode)); //临时数字结点
if(temp1 == NULL)
{
printf("Memory Allocate is Failure!\n");
exit(1);
}
printf("………………此次打包运算符为:%c\n\n",*(temp2->data));
digit_copy(&(temp1->data),temp_value,value_count);
temp1->lChild = NULL;
temp1->rChild = NULL;
}
else
{
K_flag = 0;
}
Stack_push(&digit_Satck,temp1); //数字数据入栈
if(IsEmpty_S(&Operate_Satck)) //判断运算符栈是否为空
{
Stack_push(&Operate_Satck,temp2); //为空,则运算符入栈
}
else
{
flag = 1;
Stack_getTop(&Operate_Satck,&pre_ch,&temp2); //此语句存在bug
while(flag && get_priority(pre_ch,ch)) //判断get_priority(pre_ch,ch)
{
Stack_Pop(&Operate_Satck,&Bi_parent);
Stack_Pop(&digit_Satck,&rson);
Stack_Pop(&digit_Satck,&lson);
Create_BiTree(Bi_parent,lson,rson);/*构建子树*/
Stack_push(&digit_Satck,Bi_parent); /*根节点入栈*/
if(!IsEmpty_S(&Operate_Satck))
{
Stack_getTop(&Operate_Satck,&pre_ch,&temp2); //不为空,则取出前一个字符判断优先级
}
else
{
flag =0;
}
}
Stack_push(&Operate_Satck,temp2);
}
}
InitArray_digit(temp_value);
value_count = 0;
}
}
printf("即将进行最后处理!\n\n");
printf("\n");
if(!K_flag)
{
temp1 = (BiTree)malloc(sizeof(BiNode)); //临时数字结点
if(temp1 == NULL)
{
printf("Memory Allocate is Failure!\n");
exit(1);
}
digit_copy(&(temp1->data),temp_value,value_count);
temp1->lChild = NULL;
temp1->rChild = NULL;
}
Stack_push(&digit_Satck,temp1); //数字数据入栈
while(!IsEmpty_S(&Operate_Satck))
{
Stack_Pop(&Operate_Satck,&Bi_parent);
Stack_Pop(&digit_Satck,&rson);
Stack_Pop(&digit_Satck,&lson);
Create_BiTree(Bi_parent,lson,rson);/*构建子树*/
Stack_push(&digit_Satck,Bi_parent);
}
return Bi_parent;
}
void get_digit(char *str_digit, double *real_value) //字符数组转数字
{
double temp=0;
int i=0;
while(str_digit[i]!='\0') //此时默认输入只有整数部分。
{
temp = temp*10+str_digit[i]-'0';
i++;
}
*real_value = temp;
}
void my_calculate(char opera, double *result, double x, double y) //进行运算(现在只能进行四则运算)
{
double temp=0;
switch(opera)
{
case '+':
temp = x+y;
break;
case '-':
temp = x-y;
break;
case '*':
temp = x*y;
break;
case '/':
temp = x/y;
break;
default :
printf("运算符错误!程序强制退出!\n");
exit(1);
}
*result = temp;
}
double get_Result(BiTree T) //获得运算表达式结果
{
double L_value, R_value,cur_value;
if(T)
{
if((T->lChild == NULL) && (T->rChild == NULL))
{
get_digit(T->data,&cur_value);
return cur_value;
}else
{
if(T->lChild)
L_value = get_Result(T->lChild);
if(T->rChild)
R_value = get_Result(T->rChild);
my_calculate(T->data[0],&cur_value,L_value,R_value); //存在左右孩子,证明此结点为运算符结点
return cur_value;
}
}
}
int main()
{
BiTree Parent = NULL;
double my_result = 0;
while(1)
{
printf("请输入运算表达式: ");
Parent = build_process();
//printf("表达式树的深度:%d\n\n",GetBiDepth(Parent));
printf("先序遍历:");
preorderTrvaerse(Parent);
printf("\n");
printf("中序遍历:");
InorderTraverse(Parent);
printf("\n");
printf("后序遍历:");
postOrderTrvaerse(Parent);
my_result = get_Result(Parent);
printf("\n\n\计算结果为: %lf\n\n",my_result);
Clear_BiTree(Parent);
my_result = 0;
}
return 0;
}

浙公网安备 33010602011771号