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("没有足够空间!\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语言实现二叉树的建立、遍历以及表达式的计算的更多相关文章
- c语言_二叉树的建立以及3种递归
二叉树c语言的实现 二叉树的建立 二叉树的数据结构 typedef struct node{ int data; struct node* left; struct node* ri ...
- C语言实现二叉树的创建&遍历
算法思想(重点是递归的使用) 利用扩展先序遍历序列创建二叉链表 采用类似先序遍历的递归算法,首先读入当前根结点的数据,如果是'.'则将当前 树根置为空,否则申请一个新结点,存入当前根结点的数据,分别 ...
- C语言二叉树的建立与遍历
二叉树的建立和遍历都要用到递归,先暂时保存一下代码,其中主要是理解递归的思想,其它的就都好理解了.这里是三种遍历方式,其实理解一种,其它的几个就都理解了,就是打印出来的顺序不一样而已.建立和遍历的方式 ...
- 二叉树的建立与遍历(c语言)入门
树其实在本质上就是一对多,链表就是一对一. 二叉树的建立: 这里的代码采用的是最粗暴的创建方法,无实际用处.但初次学习二叉树可以通过这个创建方法更好的理解二叉树. 二叉树的遍历: 遍历在大体上分为递归 ...
- C++编程练习(8)----“二叉树的建立以及二叉树的三种遍历方式“(前序遍历、中序遍历、后续遍历)
树 利用顺序存储和链式存储的特点,可以实现树的存储结构的表示,具体表示法有很多种. 1)双亲表示法:在每个结点中,附设一个指示器指示其双亲结点在数组中的位置. 2)孩子表示法:把每个结点的孩子排列起来 ...
- 二叉树的建立以及遍历的多种实现(python版)
二叉树是很重要的数据结构,在面试还是日常开发中都是很重要的角色. 首先是建立树的过程,对比C或是C++的实现来讲,其涉及到了较为复杂的指针操作,但是在面向对象的语言中,就不需要考虑指针, 内存等.首先 ...
- 一步一步写数据结构(二叉树的建立和遍历,c++)
简述: 二叉树是十分重要的数据结构,主要用来存放数据,并且方便查找等操作,在很多地方有广泛的应用. 二叉树有很多种类,比如线索二叉树,二叉排序树,平衡二叉树等,本文写的是最基础最简单的二叉树. 思路: ...
- 二叉树的建立&&前中后遍历(递归实现)&&层次遍历
下面代码包含了二叉树的建立过程,以及三种遍历方法了递归实现,代码中还利用队列实现了层次遍历. import java.util.LinkedList; import java.util.Queue; ...
- 二叉树中序遍历 (C语言实现)
在计算机科学中,树是一种重要的非线性数据结构,直观地看,它是数据元素(在树中称为结点)按分支关系组织起来的结构.二叉树是每个节点最多有两个子树的有序树.通常子树被称作“左子树”(left subtre ...
随机推荐
- vim鼠标模式打开与关闭
开启鼠标模式 :set mouse=x, x取值如下, 例如:set mouse=a, 开启所有模式的mouse支持 n 普通模式 v 可视模式 i 插入模式 c 命令行模式 ...
- GIL全局解释器锁+GIL全局解释器锁vs互斥锁+定时器+线程queue+进程池与线程池(同步与异步)
以多线程为例写个互斥锁 from threading import Thread ,Lockimport timemutex = Lock() n = 100 def task(): global n ...
- 配合es5.8的使用,升级sb版本到2.X,遇到一个问题
问题:Failed to bind properties under 'spring.redis.jedis.pool.max-wait' to java.time.Duration: Propert ...
- mysql 分页数据错乱
最近在使用mysql 分页查询数据的时候发现返回的数据与预期的不一样,显示数据重复错乱. 在官方文档 有这样一句话 If multiple rows have identical values in ...
- LightOJ 1030 【概率DP求期望】
借鉴自:https://www.cnblogs.com/keyboarder-zsq/p/6216762.html 题意:n个格子,每个格子有一个值.从1开始,每次扔6个面的骰子,扔出几点就往前几步, ...
- 最小费用最大流spfa
#include <iostream> #include <cstring> #include <cstdio> #include <queue> #d ...
- IDEA常见设置
对于eclipse实在忍无可忍,各种功能各种bug..换回IDEA IDEA常见问题(其实不是问题,代码规范而已) 1.解决无限 This file is indented with tabs ins ...
- 1.Zabbix报错信息:It probably means that the systems requires more physical memory.
点击返回:自学Zabbix之路 1.Zabbix报错信息:It probably means that the systems requires more physical memory. 1.报错信 ...
- 自学Zabbix8.1 Regular expressions 正则表达式
点击返回:自学Zabbix之路 点击返回:自学Zabbix4.0之路 点击返回:自学zabbix集锦 自学Zabbix8.1 Regular expressions 正则表达式 1. 配置 点击Adm ...
- 学习 Spring Boot:(二十九)Spring Boot Junit 单元测试
前言 JUnit 是一个回归测试框架,被开发者用于实施对应用程序的单元测试,加快程序编制速度,同时提高编码的质量. JUnit 测试框架具有以下重要特性: 测试工具 测试套件 测试运行器 测试分类 了 ...