数据结构——计算器实现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;
}

 

posted @ 2018-11-28 11:26  怪兽不纯粹  阅读(1295)  评论(0)    收藏  举报