实现代码

#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("没有足够空间!\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 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");
aftOrder(finTreeNode);
return numGetTop(opnd);
}
int main()
{
printf("\n\n计算结果是:%d\n",doEvaluateExpression());
return 0;
}

  

测试结果

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

C语言实现二叉树的建立、遍历以及表达式的计算的更多相关文章

  1. c语言_二叉树的建立以及3种递归

    二叉树c语言的实现 二叉树的建立 二叉树的数据结构 typedef struct node{    int data;    struct node* left;    struct node* ri ...

  2. C语言实现二叉树的创建&遍历

    算法思想(重点是递归的使用)  利用扩展先序遍历序列创建二叉链表 采用类似先序遍历的递归算法,首先读入当前根结点的数据,如果是'.'则将当前 树根置为空,否则申请一个新结点,存入当前根结点的数据,分别 ...

  3. C语言二叉树的建立与遍历

    二叉树的建立和遍历都要用到递归,先暂时保存一下代码,其中主要是理解递归的思想,其它的就都好理解了.这里是三种遍历方式,其实理解一种,其它的几个就都理解了,就是打印出来的顺序不一样而已.建立和遍历的方式 ...

  4. 二叉树的建立与遍历(c语言)入门

    树其实在本质上就是一对多,链表就是一对一. 二叉树的建立: 这里的代码采用的是最粗暴的创建方法,无实际用处.但初次学习二叉树可以通过这个创建方法更好的理解二叉树. 二叉树的遍历: 遍历在大体上分为递归 ...

  5. C++编程练习(8)----“二叉树的建立以及二叉树的三种遍历方式“(前序遍历、中序遍历、后续遍历)

    树 利用顺序存储和链式存储的特点,可以实现树的存储结构的表示,具体表示法有很多种. 1)双亲表示法:在每个结点中,附设一个指示器指示其双亲结点在数组中的位置. 2)孩子表示法:把每个结点的孩子排列起来 ...

  6. 二叉树的建立以及遍历的多种实现(python版)

    二叉树是很重要的数据结构,在面试还是日常开发中都是很重要的角色. 首先是建立树的过程,对比C或是C++的实现来讲,其涉及到了较为复杂的指针操作,但是在面向对象的语言中,就不需要考虑指针, 内存等.首先 ...

  7. 一步一步写数据结构(二叉树的建立和遍历,c++)

    简述: 二叉树是十分重要的数据结构,主要用来存放数据,并且方便查找等操作,在很多地方有广泛的应用. 二叉树有很多种类,比如线索二叉树,二叉排序树,平衡二叉树等,本文写的是最基础最简单的二叉树. 思路: ...

  8. 二叉树的建立&&前中后遍历(递归实现)&&层次遍历

    下面代码包含了二叉树的建立过程,以及三种遍历方法了递归实现,代码中还利用队列实现了层次遍历. import java.util.LinkedList; import java.util.Queue; ...

  9. 二叉树中序遍历 (C语言实现)

    在计算机科学中,树是一种重要的非线性数据结构,直观地看,它是数据元素(在树中称为结点)按分支关系组织起来的结构.二叉树是每个节点最多有两个子树的有序树.通常子树被称作“左子树”(left subtre ...

随机推荐

  1. 软件工程_6th weeks

    一.上次博客时说的UI,拖拉到现在才展示,完成了“登录,普通匹配,做题界面,做题结果”四项 功能: 二.单元测试工具 1.python单元测试工具   最近因为论文原因一直在用Python,Pytho ...

  2. Jenkins之前置替换脚本内容

    在执行Jenkins任务前,需要修改执行的工程的某个文件中的内容,在前置步骤中编写脚本进行修改. Pre Steps Windows batch script @echo off CHCP setlo ...

  3. 利用caffe自带的Makefile编译自定义so文件

    1.文件目录结构 caffe-root |--include |--example |--modules |--test.h |--test.cpp |--python |--src |--tools ...

  4. MT【6】等比数列和的极限

    评:利用等比数列求和公式给出所求数列,再利用反证法证明唯一性.这种反证方法印象中本科高等代数里讲初等对称多项式时出现过.

  5. android 开启闪光灯小应用

    该程序需要在AndroidManifest.xml添加权限,属性 android:screenOrientation="portrait" android.permission.C ...

  6. android 面试准备基础题

    1.    请描述下Activity的生命周期. 必调用的三个方法:onCreate() --> onStart() --> onResume(),用AAA表示 )父Activity启动子 ...

  7. [luogu3455][POI2007]ZAP-Queries【莫比乌斯反演】

    题目描述 FGD正在破解一段密码,他需要回答很多类似的问题:对于给定的整数a,b和d,有多少正整数对x,y,满足x<=a,y<=b,并且gcd(x,y)=d.作为FGD的同学,FGD希望得 ...

  8. Haproxy Mysql cluster 高可用Mysql集群

    -----client-----------haproxy---------mysql1----------mysql2------192.168.1.250 192.168.1.1 192.168. ...

  9. Java_io体系之RandomAccessFile简介、走进源码及示例——20

    Java_io体系之RandomAccessFile简介.走进源码及示例——20 RandomAccessFile 1.       类功能简介: 文件随机访问流.关心几个特点: 1.他实现的接口不再 ...

  10. [NOI2017]泳池——概率DP+线性递推

    [NOI2017]泳池 实在没有思路啊~~~ luogu题解 1.差分,转化成至多k的概率减去至多k-1的概率.这样就不用记录“有没有出现k”这个信息了 2.n是1e9,感觉要递推然后利用数列的加速技 ...