zoukankan      html  css  js  c++  java
  • C语言实现二叉树的建立、遍历以及表达式的计算

    实现代码

    #include <stdio.h>
    #include <stdlib.h>
    #include <malloc.h>
    #include <ctype.h>
    
    #define StackInitSize 100
    #define max 20
    #define isNum 1
    #define isCha 0
    #define lenNum sizeof(struct nodeNum)
    #define lenCha sizeof(struct nodeCha)
    #define lenBiTree sizeof(struct biTreeNode)
    
    //操作数节点元素
    struct nodeNum{
        int number;
    };
    //操作符节点元素
    struct nodeCha{
        char ch;
    };
    //共用体
    typedef union demo{
        int number;
        char cha;
    }Demo;
    //二叉树节点
    struct biTreeNode{
        int flag;
        Demo useUnion;
        struct biTreeNode *lchild;
        struct biTreeNode *rchild;
    };
    //二叉树节点栈     !会初始化两个二叉树节点栈!
    struct biTreeStack{
        struct biTreeNode *base;
        struct biTreeNode *top;
        int stackSize;
    };
    //操作数栈
    struct numStack{
        struct nodeNum *base;
        struct nodeNum *top;
        int stackSize;
    };
    //操作符栈
    struct chaStack{
        struct nodeCha *base;
        struct nodeCha *top;
        int stackSize;
    };
    //初始化二叉树栈
    void biTreeInitStack(struct biTreeStack *stack0)
    {
        stack0->base = (struct biTreeNode *)malloc(StackInitSize * lenBiTree);
        if(!stack0->base)
        {
            printf("没有足够空间!
    退出程序!
    ");
            exit(0);
        }
        stack0->top = stack0->base;
        stack0->stackSize = StackInitSize;
    }
    //初始化操作数栈
    void numInitStack(struct numStack *stack1)
    {
        stack1->base = (struct nodeNum *)malloc(StackInitSize * lenNum);
        if(!stack1->base)
        {
            printf("没有足够空间!
    退出程序!
    ");
            exit(0);
        }
        stack1->top = stack1->base;
        stack1->stackSize = StackInitSize;
    }
    //初始化操作符栈
    void chaInitStack(struct chaStack *stack2)
    {
        stack2->base = (struct nodeCha *)malloc(StackInitSize * lenCha);
        if(!stack2->base)
        {
            printf("没有足够空间!
    退出程序!
    ");
            exit(0);
        }
        stack2->top = stack2->base;
        stack2->stackSize = StackInitSize;
    }
    //压入操作符
    void chaPush(struct chaStack *stack3,char ch)
    {
        if(stack3->top - stack3->base >= stack3->stackSize)
        {
            printf("栈满!
    退出程序!
    ");
            exit(0);
        }
        stack3->top->ch = ch;
        stack3->top++;
    }
    //压入操作数
    void numPush(struct numStack *stack4,int number)
    {
        if(stack4->top - stack4->base >= stack4->stackSize)
        {
            printf("栈满!
    退出程序!
    ");
            exit(0);
        }
        stack4->top->number = number;
        stack4->top++;
    }
    //压入栈节点
    void biTreeNodePush(struct biTreeStack *curBiTree,struct biTreeNode curTreeNode)
    {
        if(curBiTree->top - curBiTree->base >= curBiTree->stackSize)
        {
            printf("栈满!
    退出程序!
    ");
            exit(0);
        }
        *curBiTree->top = curTreeNode;
        curBiTree->top++;
    }
    //弹出栈节点
    //因为是对指针进行操作,在弹完栈后再往里压栈就会覆盖原来的内容,所以就会出现问题!!!!!!
    struct biTreeNode *biTreeNodePop(struct biTreeStack *curBiTree)
    {
        if(curBiTree->top != curBiTree->base)
        {
            curBiTree->top--;
            return curBiTree->top;
        }
        else
        {
             printf("栈已空!
    退出程序!
    ");
             exit(0);
        }
    }
    void recoverPtr(struct biTreeStack *curBiTree)
    {
        curBiTree->top++;
        curBiTree->top++;
    }
    //弹出操作符
    char chaPop(struct chaStack *stack5)
    {
        if(stack5->top != stack5->base)
        {
            stack5->top--;
            return stack5->top->ch;
        }
        else
        {
             printf("栈已空!
    退出程序!
    ");
             exit(0);
        }
    }
    //弹出操作数
    int numPop(struct numStack *stack6)
    {
        if(stack6->top != stack6->base)
        {
            stack6->top--;
            return stack6->top->number;
        }
        else
        {
            printf("栈已空!
    退出程序!
    ");
            exit(0);
        }
    }
    //运算符栈取顶
    char chaGetTop(struct chaStack stack7)
    {
        if(stack7.top >= stack7.base)
        {
            stack7.top--;
            return stack7.top->ch;
        }
        else
        {
            printf("栈已空!
    退出程序!
    ");
            exit(0);
        }
    }
    //运算数栈取顶
    int numGetTop(struct numStack stack8)
    {
        if(stack8.top >= stack8.base)
        {
            stack8.top--;
            return stack8.top->number;
        }
        else
        {
            printf("栈已空!
    退出程序!
    ");
            exit(0);
        }
    }
    //判断并返回算符间的优先关系
    char Precede(char ch1,char ch2)
    {
        char ch = ' ';
        switch(ch1)
        {
            case '$':
                if('+' == ch2||'-' == ch2||'*' == ch2||'/' == ch2||'(' == ch2)
                {
                    ch = '<';
                }
                else if(')' == ch2)
                {
                    printf("输入有误!
    退出程序!
    ");
                    exit(0);
                }
                else if('$' == ch2)
                {
                    ch = '=';
                }
            break;
            case ')':
                if('+' == ch2||'-' == ch2||'*' == ch2||'/' == ch2||')' == ch2||'$' == ch2)
                {
                    ch = '>';
                }
                else if('(' == ch2)
                {
                    printf("输入有误!
    退出程序!
    ");
                    exit(0);
                }
            break;
            case '(':
                if('+' == ch2||'-' == ch2||'*' == ch2||'/' == ch2||'(' == ch2)
                {
                    ch = '<';
                }
                else if(')' == ch2)
                {
                    ch = '=';
                }
                else if('$' == ch2)
                {
                    printf("输入有误!
    退出程序!
    ");
                    exit(0);
                }
            break;
            case '/':
                if('+' == ch2||'-' == ch2||'*' == ch2||'/' == ch2||')' == ch2||'$' == ch2)
                {
                    ch = '>';
                }
                else if('(' == ch2)
                {
                    ch = '<';
                }
            break;
            case '*':
                if('+' == ch2||'-' == ch2||'*' == ch2||'/' == ch2||')' == ch2||'$' == ch2)
                {
                    ch = '>';
                }
                else if('(' == ch2)
                {
                    ch = '<';
                }
            break;
            case '-':
                if('+' == ch2||'-' == ch2||')' == ch2||'$' == ch2)
                {
                    ch = '>';
                }
                else if('*' == ch2||'/' == ch2||'(' == ch2)
                {
                    ch = '<';
                }
            break;
            case '+':
                if('+' == ch2||'-' == ch2||')' == ch2||'$' == ch2)
                {
                    ch = '>';
                }
                else if('*' == ch2||'/' == ch2||'(' == ch2)
                {
                    ch = '<';
                }
            break;
            default:
                {
                    printf("非法输入!
    退出程序!
    ");
                    exit(0);
                }
        }
        return ch;
    }
    //将弹出的数进行计算
    int Operate(int numa,char ch,int numb)
    {
        int number = 0;
        switch(ch)
        {
            case '+':
                number = numa + numb;
            break;
            case '-':
                number = numa - numb;
            break;
            case '*':
                number = numa * numb;
            break;
            case '/':
                number = numa / numb;
            break;
        }
        return number;
    }
    //先序遍历二叉树
    void preOrder(struct biTreeNode *biTree)
    {
        if(biTree->flag == isNum)
        {
            printf("%d   ",biTree->useUnion.number);
        }
        else if(biTree->flag == isCha)
        {
            printf("%c   ",biTree->useUnion.cha);
        }
        if(biTree->lchild != NULL) preOrder(biTree->lchild);
        if(biTree->rchild != NULL) preOrder(biTree->rchild);
    }
    //后序遍历二叉树
    void aftOrder(struct biTreeNode *biTree)
    {
        if(biTree->lchild != NULL) aftOrder(biTree->lchild);
        if(biTree->rchild != NULL) aftOrder(biTree->rchild);
        if(biTree->flag == isNum)
        {
            printf("%d   ",biTree->useUnion.number);
        }
        else if(biTree->flag == isCha)
        {
            printf("%c   ",biTree->useUnion.cha);
        }
    }
    //显示二叉树
    void outPutBiTree(struct biTreeNode *biTree)
    {
        if(biTree != NULL)
        {
            if(biTree->flag == isNum)
            {
                printf("%d ",biTree->useUnion.number);
            }
            else if(biTree->flag == isCha)
            {
                printf("%c ",biTree->useUnion.cha);
            }
        }
        if(biTree->lchild != NULL)
        {
            printf("(");
            outPutBiTree(biTree->lchild);
            printf(",");
        }
        if(biTree->rchild != NULL)
        {
            outPutBiTree(biTree->rchild);
            printf(")");
        }
    }
    //表达式求值并创建二叉树
    int doEvaluateExpression()
    {
        char ch,x,the;
        int numa,numb;
        int count;
        int i,temp;
        long number,num[max];
        struct numStack opnd;
        struct chaStack optr;
        struct biTreeNode tempTreeNode,*finTreeNode,*treeNode_1,*treeNode_2;
        struct biTreeStack binaryTree,binaryTree_0;
        numInitStack(&opnd);//初始化操作数栈
        chaInitStack(&optr);//初始化操作符栈
        biTreeInitStack(&binaryTree);//初始化二叉树节点栈
        biTreeInitStack(&binaryTree_0);//初始化二叉树节点栈副本
        chaPush(&optr,'$');
        printf("请输入表达式(以$号结束):
    ");
        ch = getchar();
        //如果产生矛盾,可以尝试将所有数据一次性读入一个数组里,
        //进而可以通过对数组下标进行操作而达到目的,
        //或者使用ungetc()函数
        while(!(ch == '$' && chaGetTop(optr) == '$'))
        {
            if(isdigit(ch))    //如果是数字就进运算数栈
            {
                count = 0;
                number = 0;
                while(isdigit(ch))//如果getchar()得到的是数字,则连续读
                {
                    count++;
                    num[count-1] = ch-48;
                    ch = getchar();
                }
                temp = count;
                for(i = 0; i < count; i++)//判断数字有几位
                {
                    temp--;
                    number += num[i] * pow(10,temp);
                }
                numPush(&opnd,number);
                tempTreeNode.flag = isNum;
                tempTreeNode.useUnion.number = number;
                tempTreeNode.rchild = NULL;
                tempTreeNode.lchild = NULL;
                biTreeNodePush(&binaryTree,tempTreeNode);
            }
            else
            {
                //若无限循环则说明  ch 可能为空了
                switch(Precede(chaGetTop(optr),ch))//判断优先级
                {
                    case '<':                   //栈顶元素优先权低
                        chaPush(&optr,ch);
                        ch = getchar();
                        break;
                    case '=':                   //脱括号并接收下一个字符
                        x = chaPop(&optr);
                        ch = getchar();
                        break;
                    case '>':                   //退栈并将运算结果入栈
                        the = chaPop(&optr);
                        numb = numPop(&opnd);
                        numa = numPop(&opnd);
                        numPush(&opnd,Operate(numa,the,numb));
                        tempTreeNode.flag = isCha;
                        tempTreeNode.useUnion.cha = the;
                        treeNode_1 = biTreeNodePop(&binaryTree);
                        treeNode_2 = biTreeNodePop(&binaryTree);
                        biTreeNodePush(&binaryTree_0,*treeNode_1);//弹出的内容转存到另一个节点栈里,避免覆盖
                        biTreeNodePush(&binaryTree_0,*treeNode_2);//弹出的内容转存到另一个节点栈里,避免覆盖
                        tempTreeNode.lchild = biTreeNodePop(&binaryTree_0);
                        tempTreeNode.rchild = biTreeNodePop(&binaryTree_0);
                        recoverPtr(&binaryTree_0);//恢复副本栈里的指针指向
                        biTreeNodePush(&binaryTree,tempTreeNode);
                        break;
                    default:
                        printf("其他字符!
    退出程序!
    ");
                        exit(0);
                        break;
                }
            }
        }
        finTreeNode = biTreeNodePop(&binaryTree);
        printf("
    显示表达式树(广义表)为:
    ");
        outPutBiTree(finTreeNode);
        printf("
    
    二叉树先序遍历:
    ");
        preOrder(finTreeNode);//先序遍历
        printf("
    
    二叉树后序遍历:
    ");
        aftOrder(finTreeNode);
        return numGetTop(opnd);
    }
    int main()
    {
        printf("
    
    计算结果是:%d
    ",doEvaluateExpression());
        return 0;
    }
    

      

    测试结果

    几年前写的代码了,今天整理了下,居然发现个bug:

    作者:Standby一生热爱名山大川、草原沙漠,还有妹子
    出处:http://www.cnblogs.com/standby/

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    数学图形(1.25)cassini曲线
    数学图形(1.24)巴斯加线与蚶线
    数学图形(1.23)太极线
    webpack打包多个入口文件
    cnpm与npm的区别
    入门 Webpack,看这篇就够了
    protocol error, got 'n' as reply type byte + redis如何后台启动
    PHP执行系统外部命令函数:exec()、passthru()、system()、shell_exec()
    CentOS7.0+Zend Guard Loader for PHP 5.6环境搭建
    通过shell脚本进行数据库操作
  • 原文地址:https://www.cnblogs.com/standby/p/4150149.html
Copyright © 2011-2022 走看看