C语言实现二叉树的建立、遍历和计算表达式的值(代码已调通,直接可运行)

C语言实现二叉树的建立、遍历和计算表达式的值(代码已调通,直接可运行)

注意:程序控制台输入需要在英文状态下输入表达式和终止符,否则会出现非法输入而终止程序

程序案例图

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <ctype.h>
#include<math.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("没有足够空间!\n退出程序!\n");
        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("没有足够空间!\n退出程序!\n");
        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("没有足够空间!\n退出程序!\n");
        exit(0);
    }
    stack2->top = stack2->base;
    stack2->stackSize = StackInitSize;
}
//压入操作符
void chaPush(struct chaStack *stack3,char ch)
{
    if(stack3->top - stack3->base >= stack3->stackSize)
    {
        printf("栈满!\n退出程序!\n");
        exit(0);
    }
    stack3->top->ch = ch;
    stack3->top++;
}
//压入操作数
void numPush(struct numStack *stack4,int number)
{
    if(stack4->top - stack4->base >= stack4->stackSize)
    {
        printf("栈满!\n退出程序!\n");
        exit(0);
    }
    stack4->top->number = number;
    stack4->top++;
}
//压入栈节点
void biTreeNodePush(struct biTreeStack *curBiTree,struct biTreeNode curTreeNode)
{
    if(curBiTree->top - curBiTree->base >= curBiTree->stackSize)
    {
        printf("栈满!\n退出程序!\n");
        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("栈已空!\n退出程序!\n");
         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("栈已空!\n退出程序!\n");
         exit(0);
    }
}
//弹出操作数
int numPop(struct numStack *stack6)
{
    if(stack6->top != stack6->base)
    {
        stack6->top--;
        return stack6->top->number;
    }
    else
    {
        printf("栈已空!\n退出程序!\n");
        exit(0);
    }
}
//运算符栈取顶
char chaGetTop(struct chaStack stack7)
{
    if(stack7.top >= stack7.base)
    {
        stack7.top--;
        return stack7.top->ch;
    }
    else
    {
        printf("栈已空!\n退出程序!\n");
        exit(0);
    }
}
//运算数栈取顶
int numGetTop(struct numStack stack8)
{
    if(stack8.top >= stack8.base)
    {
        stack8.top--;
        return stack8.top->number;
    }
    else
    {
        printf("栈已空!\n退出程序!\n");
        exit(0);
    }
}
//判断并返回算符间的优先关系
char Precede(char ch1,char ch2)
{
    char ch = ' ';
    switch(ch1)
    {
        case '#':
            if('+' == ch2||'-' == ch2||'*' == ch2||'/' == ch2||'(' == ch2)
            {
                ch = '<';
            }
            else if(')' == ch2)
            {
                printf("输入有误!\n退出程序!\n");
                exit(0);
            }
            else if('#' == ch2)
            {
                ch = '=';
            }
        break;
        case ')':
            if('+' == ch2||'-' == ch2||'*' == ch2||'/' == ch2||')' == ch2||'#' == ch2)
            {
                ch = '>';
            }
            else if('(' == ch2)
            {
                printf("输入有误!\n退出程序!\n");
                exit(0);
            }
        break;
        case '(':
            if('+' == ch2||'-' == ch2||'*' == ch2||'/' == ch2||'(' == ch2)
            {
                ch = '<';
            }
            else if(')' == ch2)
            {
                ch = '=';
            }
            else if('#' == ch2)
            {
                printf("输入有误!\n退出程序!\n");
                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("非法输入!\n退出程序!\n");
                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 midOrder(struct biTreeNode *biTree)
{
    if(biTree->lchild != NULL) midOrder(biTree->lchild);
    if(biTree->flag == isNum)
    {
        printf("%d   ",biTree->useUnion.number);
    }
    else if(biTree->flag == isCha)
    {
        printf("%c   ",biTree->useUnion.cha);
    }
    if(biTree->rchild != NULL) midOrder(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("请输入表达式(以#号结束):\n");
    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("其他字符!\n退出程序!\n");
                    exit(0);
                    break;
            }
        }
    }
    finTreeNode = biTreeNodePop(&binaryTree);
    printf("\n显示表达式树(广义表)为:\n");
    outPutBiTree(finTreeNode);
    
    printf("\n\n二叉树先序遍历:\n");
    preOrder(finTreeNode);//先序遍历
    
    printf("\n\n二叉树中序遍历:\n");
    midOrder(finTreeNode);//中序遍历
    
    printf("\n\n二叉树后序遍历:\n");
    aftOrder(finTreeNode);//后序遍历 
    
    return numGetTop(opnd);
}
int main()
{
    printf("\n\n计算结果是:%d\n",doEvaluateExpression()); 
    return 0;
}
  • 5
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值