基于二叉树的算术表达式计算与实现
C语言实现一.二叉树操作 二.用栈实现算术表达式求值 课设报告

沈阳理工大学课程设计专用纸
No. 1
题目 一.二叉树操作(1)二.算术表达式求
一、课程设计的目的
本学期我们对《数据结构》这门课程进行了学习。这门课程是一门实践性非常强的 课程,为了让大家更好地理解与运用所学知识,提高动手能力,我们进行了此次课程设 计实习。这次课程设计不但要求学生掌握《数据结构》中的各方面知识,还要求学生具 备一定的 C 语言基础和编程能力。
{ int k; char *temp; if(len<=0) { *T=NULL;
沈阳理工大学
沈阳理工大学课程设计专用纸
No. 5
return; } *T=(BitNode*)malloc(sizeof(BitNode)); (*T)->data=*pre; for(temp=in;temp<in+len;temp++)
int h,lh,rh; if(T==NULL)
h=0; else {
lh=Depth(T->lchild); rh=Depth(T->rchild); if(lh>=rh)
h=lh+1; else
h=rh+1; } return h; }
沈阳理工大学
沈阳理工大学课程设计专用纸
No. 6
4、运行结果 先输入一棵树的先序遍历序列和中序遍历序列,然后构造出这颗二叉树,并输
(2)题目二的内容和要求: 1、算术表达式由操作数、运算符和界限符组成。操作数是正整数,运算符为 加减乘除,界限符有左右括号和表达式起始 2、将一个表达式的中缀形式转化为相应的后缀形式 3、依据后缀表达式计算表达式的值
沈阳理工大学
沈阳理工大学课程设计专用纸
实验五 二叉树的应用----表达式求值

浙江大学城市学院实验报告课程名称python高级程序设计实验项目名称实验五二叉树的应用----表达式求值实验成绩指导老师(签名)日期一.实验目的和要求1、掌握二叉树的链式存储结构;2、掌握在二叉链表上的二叉树的基本操作;3、掌握二叉树的简单应用----表达式树的操作。
二.实验内容1、在实验四中,已经实现了对一个中缀表达式可以用栈转换成后缀表达式,并可对后缀表达式进行求值计算的方法。
另一种思路是可以利用二叉树建立表达式树,通过对该表达式树进行求值计算,本实验实现:输入一个中缀表达式,建立该表达式的二叉树,然后对该二叉树进行表达式值的计算。
如一个中缀达式(6+2)*5 的二叉树表示为如下所示时,该二叉树的后序遍历62+5*正好就是后缀表达式。
设一般数学表达式的运算符包括+、-、*、/ 四种,当然允许(),且()优先级高。
为方便实现,设定输入的表达式只允许个位整数。
要求设计一个完整的程序,对输入的一个日常的中缀表达式,实现以下功能:⏹建立对应的二叉树⏹输出该二叉树的前序序列、中序序列、后序序列⏹求该二叉树的高度⏹求该二叉树的结点总数⏹求该二叉树的叶子结点数⏹计算该二叉树的表达式值分析:(1)表达式树的构建方法:●构建表达式树的方法之一:直接根据输入的中缀表达式构建对于任意一个算术中缀表达式,都可用二叉树来表示。
表达式对应的二叉树创建后,利用二叉树的遍历等操作,很容易实现二叉树的求值运算。
因此问题的关键就是如何创建表达式树。
对于一个中缀表达式来说,其表达式对应的表达式树中叶子结点均为操作数,分支结点均为运算符。
由于创建的表达式树需要准确的表达运算次序,因此,在扫描表达式创建表达式树的过程中,当遇到运算符时不能直接创建结点,而应将其与前面的运算符进行优先级比较,根据比较结果进行处理。
这种处理方式在实验四中以采用过,可以借助一个运算符栈,来暂存已经扫描到的还未处理的运算符。
根据表达式树与表达式对应关系的递归定义,每两个操作数和一个运算符就可以建立一棵表达式二叉树,而该二叉树又可以作为另一个运算符结点的一棵子树。
基于二叉树结构的表达式求值算法

实验报告课程名称: 程序设计与数据结构 指导老师: ljq 成绩: 实验名称:基于二叉树结构的表达式求值算法 实验类型: 上机 同组学生姓名:一、实验目的和要求(必填)三、代码缺陷及修正记录五、讨论、心得二、实验内容和代码(必填) 四、实验结果与分析(必填)一、实验目的和要求1. 掌握编程工具的使用2. 掌握二叉树数据结构在计算机上的实现3. 掌握通过计算机编程解决问题的基本方法二、实验内容和代码1.实验内容:● 编程实现基于二叉树结构的表达式求值算法● 表达式包含加减乘除四则运算以及至少一层括弧运算● 首先将输入的原表达式转换成二叉树结构,然后采用二叉树的后序递归遍历方法求得表达式的值● 将所有实验内容合并到一个工程,增加交互操作和循环处理(持续)2.代码1.头文件expnbitree .h装订 线1 2 3 4 5 6 7 8 91011121314151617181920212223 #include<stdio.h>#include<string.h>#include<stdlib.h>#define EXP_LEN 100 //定义表达式的最大长度#define DATA_LEN 20 //定义每个操作数的最大长度typedef struct BiTNode{int dflag; //标志域,值为1,data[]存放操作运算符;值为0,data[]存放操作数char data[DATA_LEN + 1]; //数据域,存放:操作运算符或操作数struct BiTNode *lchild, *rchild; //分别指向结点的左、右子树}BiTNode, *BiTree; //定义二叉树结点及二叉树类型指针int CreateBiTree(BiTree &bt, char *p, int len);//创建二叉树,并用bt返回树的根地址,p为表达式的首地址,l为表达式的长度int Calculate(BiTree bt, double &rst);//计算表达式的值,bt为据表达式创建的二叉树,用rst返回表达式的值int PreOrderTraverse(BiTree bt);//先序遍历二叉树bt,输出先序遍历序列int InOrderTraverse(BiTree bt); //中序遍历二叉树bt,输出中序遍历序列int PostOrderTraverse(BiTree bt); //后序遍历二叉树bt,输出后序遍历序列int DestroyBiTree(BiTree &bt); //销毁二叉树//二叉树结构的表达式求解算法入口void expnbitree();2.源文件expntree.c1 2 3 4 5 6 7 8 910111213141516 #include<stdio.h>#include<string.h>#include<stdlib.h>#include"expnbitree.h"//ExpnBiTree实现子程序入口void expnbitree(){int n, len, i; //n标志量,值为0,退出程序;len存储表达式的长度;i一般变量char expn[EXP_LEN + 1]; //存放表达式double rst; //存放表达式计算结果BiTree bt = NULL; //声明一个二叉树gets_s(expn);do{1718192021222324252627282930313233343536373839404142434445464748495051525354555657585960 i = 0;printf("请输入合法的表达式:\n");gets_s(expn);for (i = 0, len = 0; expn[i] != '\0'; i++) //去掉表达式中的空格,并计算表达式的长度if (expn[i] != ' ')expn[len++] = expn[i];expn[len] = '\0';printf("正在构建二叉树……\n");if (CreateBiTree(bt, expn, len))printf("二叉树构建成功!\n");else{ //销毁未成功建立的二叉树,释放动态申请的内存printf("二叉树构建失败!\n");printf("将销毁二叉树…………");if (DestroyBiTree(bt))printf("二叉树销毁成功!\n");else {printf("二叉树销毁失败!\n");exit(0);}continue;}printf("输出表达式的先序遍历序列……:\n");PreOrderTraverse(bt);printf("\n");printf("输出表达式的中序遍历序列……:\n");InOrderTraverse(bt);printf("\n");printf("输出表达式的后序遍历序列……:\n");PostOrderTraverse(bt);printf("\n");printf("计算表达式的值……:\n");if (Calculate(bt, rst))printf("%g\n", rst);elseprintf("计算表达式的值失败!\n");printf("即将销毁二叉树…………");if (DestroyBiTree(bt))printf("二叉树销毁成功!\n");else {printf("二叉树销毁失败!\n");exit(0);}printf("如果要继续计算下一个表达式,请输入1,否则,返回上一级:\n ");616263646566676869707172737475767778798081828384858687888990919293949596979899 100 101 102 103 104scanf_s("%d", &n);getchar();} while (n==1);}//创建二叉树int CreateBiTree(BiTree &bt, char *p, int len){int i = 0, lnum = 0, rpst1 = -1, rpst2 = -1, pn = 0;//lnum记录"("的未成对个数;//rpst1/rpst2记录表达式中优先级最低的("*"、"/")/("+"、"-")的位置;//pn记录操作数中"."的个数,以判断输入操作数是否合法if (len == 0)return 1;if (!(bt = (BiTree)malloc(sizeof(BiTNode)))) {printf("内存申请失败\n");return 0;}else{//初始化bt->lchild = bt->rchild = NULL;memset(bt->data, '\0', sizeof(bt->data));//memset是计算机中C/C++语言函数——memset(void*s,int ch,size_t n);//将s所指向的某一块内存中的后n个字节的内容全部设置为ch指定的ASCII值,//第一个值为指定的内存地址,块的大小由第三个参数指定,这个函数通常为新申请的内存做初始化工作,其返回值为s。
基于二叉树的表达式求值算法实验报告

基于二叉树的表达式求值算法实验报告一、实验目的1. 学习基于二叉树的表达式求值算法。
2. 掌握二叉树的遍历方法和递归算法。
3. 设计并实现基于二叉树的表达式求值程序。
二、实验环境操作系统:Windows 10开发环境:Visual Studio Code 1.57.1编程语言:C++三、算法描述1. 表达式转二叉树将中缀表达式转换为二叉树的过程可以通过递归算法实现。
具体步骤如下:(1)如果表达式只有一个数字,那么将其作为叶子节点返回。
(2)如果表达式包含多个操作符,则以操作符优先级最低的操作符为根节点,将表达式分成两部分,分别递归处理左子树和右子树。
(3)如果表达式中有括号,则将括号中的表达式作为一棵子树递归处理。
2. 表达式求值二叉树求值的过程可以通过递归算法实现。
对于一个二叉树节点,分别计算其左子树和右子树的值,并根据节点的操作符计算节点的值。
具体步骤如下:(1)如果节点是叶子节点,则其值为对应数字。
(2)如果节点是加法节点,则将左右子树的值相加。
(3)如果节点是减法节点,则将左子树的值减去右子树的值。
(4)如果节点是乘法节点,则将左右子树的值相乘。
(5)如果节点是除法节点,则将左子树的值除以右子树的值。
四、实验步骤1. 定义二叉树节点结构体c++struct node {char oper; 节点的操作符double val; 节点的值node* left; 左子树节点node* right; 右子树节点};2. 实现表达式转二叉树函数c++node* expressionToTree(string exp) { int len = exp.length();node* root = NULL;如果表达式是一个数字if (len == 1) {root = new node;root->oper = '#';root->val = exp[0] - '0';root->left = NULL;root->right = NULL;return root;}如果表达式包含多个操作符int pos = 0, priority = 0;for (int i = 0; i < len; i++) {if (exp[i] == '(') {priority += 10;continue;}if (exp[i] == ')') {priority -= 10;continue;}if (exp[i] == '+' exp[i] == '-') {if (priority <= 1) {root = new node;root->oper = exp[i];root->left = expressionT oTree(exp.substr(pos, i - pos));root->right = expressionToTree(exp.substr(i + 1));return root;}}if (exp[i] == '*' exp[i] == '/') {if (priority <= 2) {root = new node;root->oper = exp[i];root->left = expressionT oTree(exp.substr(pos, i - pos));root->right = expressionToTree(exp.substr(i + 1));return root;}}}return root;}3. 实现表达式求值函数c++double evaluate(node* root) {if (root == NULL) return 0.0;if (root->left == NULL && root->right == NULL) return root->val;double left_val = evaluate(root->left), right_val =evaluate(root->right);switch (root->oper) {case '+': return left_val + right_val;case '-': return left_val - right_val;case '*': return left_val * right_val;case '/': return left_val / right_val;default: return 0.0;}}4. 测试程序c++int main() {string exp = "((5-2)*(3+4))/7";node* root = expressionToTree(exp);cout << exp << " = " << evaluate(root) << endl; 输出结果为3 return 0;}五、实验结果分析本实验设计并实现了基于二叉树的表达式求值程序。
实现二叉树的各种基本运算的算法

实现二叉树的各种基本运算的算法1.二叉树的定义及概述二叉树是一种重要的数据结构,它是由节点组成的序列,每个节点最多有两个子节点。
二叉树的根节点是唯一的,且每个节点都有一个“父节点”,除了根节点外,每个子节点称作“左孩子”和“右孩子”。
二叉树的组成部分是节点,每个节点包括一个数据元素和左右孩子指针。
通过这些指针构成的树形结构,可以便捷地进行数据存储和操作。
本文将介绍二叉树的各种基本运算及实现方法。
2.二叉树的遍历二叉树的遍历分为三种:前序遍历、中序遍历和后序遍历。
前序遍历:按照“根节点-左孩子-右孩子”的顺序遍历二叉树。
中序遍历:按照“左孩子-根节点-右孩子”的顺序遍历二叉树。
后序遍历:按照“左孩子-右孩子-根节点”的顺序遍历二叉树。
3.二叉树的建立二叉树的建立有三种方法:链式存储法、顺序存储法和扩展二叉树。
链式存储法:链式存储法是用链表来表示二叉树的方法,每个节点包括数据域和左右孩子指针域。
链式存储法建立二叉树比较容易,操作起来也比较方便。
顺序存储法:顺序存储法是用数组来表示二叉树的方法,便于存取、操作和查找。
但是顺序存储法的空间利用率不高,只有满二叉树才能利用完全。
扩展二叉树:是指二叉树中所有的空节点都必须存储起来,以构成一颗可以存储不满的二叉树。
由于扩展二叉树浪费了大量的空间,因此很少使用。
4.二叉树的查找二叉树的查找分为两种:层序遍历和二叉排序树的查找。
层序遍历:是一种广度优先搜索的方式来遍历二叉树。
层序遍历可以找到二叉树中从根节点到任意节点的路径,具有较高的效率。
层序遍历可以使用队列来实现。
二叉排序树的查找:是指在一颗二叉排序树中查找某个元素的算法。
二叉排序树(BST)是一颗二叉树,其中每个节点的值都比它的左子节点大,比它的右子节点小。
通过对BST的查找操作,可以将查找的效率高效地进行。
5.二叉树的删除在二叉树中删除节点有两种情况:删除叶子节点和删除非叶子节点。
下面给出二叉树的删除基本操作。
二叉树应用——计算表达式

由于时间比较匆忙,只实现了计算单个数字的,计算有十位或者更高位的还没去实现,之前用栈做的就可以,这里用二叉树做的,一开始把数据定为char类型,所以后来也就没去改它,就先实现了只有个位数的情况下的表达式的计算,更高位的表达式的计算,就是将数据的类型定位string类型,然后在数字组装和压栈的时候改些东西就好,这次由于重点是通过输入一个表达式,并建立起相对应的表达树,所以那里不想去深究。
下面是代码,运算符号的优先级的判断,是用了栈的的结构特点,下一篇日记会贴出,只有栈和数组实现的表达式的计算,那个可以计算高位。
文件“tree.h”view plain1.#include<iostream>2.#include<string>3.#include<ctype.h>ing namespace std;5.6.template<class T>7.class My_stack;8.9.template<class T>10.class Node //结点类11.{12.private:13. T data;14. Node<T> *next;15.public:16. Node()17. {18. next=NULL;19. }20. Node(T d)21. {22. data=d;23. next=NULL;24. }25.friend My_stack<T>;26.};27.28.template<class T>29.class My_stack30.{31.private:32. Node<T> *head;33.public:34. My_stack()35. {36. head=new Node<T>();37. }38.39. ~My_stack()40. {41. clean();42.delete head;43. }44.45.bool empty() const46. {47.return (head->next==0);48. }49.50.int size() const51. {52.int length=0;53. Node<T> *p=head->next;54.while(p)55. {56. length++;57. p=p->next;58. }59.return length;60. }61.62.void push(T d) //入栈63. {64. Node<T> *p=new Node<T>(d);65. p->next=head->next;66. head->next=p;67. }68.69. T top() //返回栈顶元素70. {71.if(empty())72. {73. cout<<"stack is empty."<<endl;74. exit(1);75. }76. Node<T> *p=head->next;77. T temp=p->data;78.return temp;79. }80.81.void pop() //弹出栈顶元素82. {83. Node<T> *p=head->next;84. head->next=p->next;85.delete p;86. }87.88.void clean() //清除整个栈89. {90. Node<T> *p=head->next;91.while(p)92. {93. head->next=p->next;94.delete p;95. head->next=p;96. }97. }98.};99.100.class BinTree;101.102.class BinNode103.{104.private:105.char data;106. BinNode *lchild;107. BinNode *rchild;108.friend BinTree;109.};110.111.class BinTree112.{113.private:114. BinNode *root;115.int pos;116.char str[255];117.public:118. BinTree()119. {120. root=0;121. pos=0;122. str[0]='\0';123. }124.125. BinNode *Get_Root()126. {127.return root;128. }129.130.char *Get_str()131. {132. str[pos]='\0';133.return str;134. }135.136.void Create_Expression_Tree(BinNode *&r) //建表达树137. {138. My_stack<char> digit;//暂存数字139. My_stack<char> opetor;//暂存操作符140. My_stack<BinNode *> node;//暂存结点141.142.char str[255];143. cout<<"输入表达式:";144. cin>>str;145.int i=0;146.char a,b;147. BinNode *p1,*p2,*p3;148.149.while(str[i]!='\0')150. {151.if(isdigit(str[i]))152. {153. digit.push(str[i]);154. }155.else156. {157.switch(str[i])158. {159.case'(': opetor.push(str[i]); break;160.case'*':161.case'/':162.if( !opetor.empty() && ( opetor.top()=='*' || opetor.to p()=='/' ) )163. {164. p1=new BinNode;165.if(!opetor.empty())166. {167. p1->data=opetor.top();168. opetor.pop();169. }170.else171. cout<<"operator stack is empty"<<endl;172.if(!digit.empty()) //当数字栈中还有数字时173. {174. a=digit.top();175. digit.pop();176. p2=new BinNode;177. p2->data=a;178. p2->lchild=p2->rchild=0;179.if(!digit.empty())180. {181. b=digit.top();182. digit.pop();183. p3=new BinNode;184. p3->data=b;185. p3->lchild=p3->rchild=0;186. p1->lchild=p3;187. p1->rchild=p2;188. }189.else190. {191.if(!node.empty())192. {193. p3=new BinNode;194. p3=node.top();195. node.pop();196. }197. p1->lchild=p3;198. p1->rchild=p2;199. }200. node.push(p1);201. }202.else//当数字栈为空时,运算符号是作为两个式子运算结果的运算203. {204. p2=node.top();205. node.pop();206. p3=node.top();207. node.pop();208. p1->lchild=p3;209. p1->rchild=p2;210. node.push(p1);211. }212. opetor.push(str[i]);213. }214.else215. opetor.push(str[i]);216.break;217.case'+':218.case'-':219.while( (!opetor.empty()) && (opetor.top()!='(') )//加减的运算优先级最低,在他之前的所以运算符号都要出栈220. {221. p1=new BinNode;222. p1->data=opetor.top();223. opetor.pop();224.if(!digit.empty())225. {226. a=digit.top();227. digit.pop();228. p2=new BinNode;229. p2->data=a;230. p2->lchild=p2->rchild=0;231.if( !digit.empty() )232. {233. b=digit.top();234. digit.pop();235. p3=new BinNode;236. p3->data=b;237. p3->lchild=p3->rchild=0;238. p1->lchild=p3;239. p1->rchild=p2;240. }241.else242. {243.if(!node.empty())244. {245. p3=new BinNode;246. p3=node.top();247. node.pop();248. }249. p1->lchild=p3;250. p1->rchild=p2;251. }252. node.push(p1);253. }254.else255. {256. p2=node.top();257. node.pop();258. p3=node.top();259. node.pop();260. p1->lchild=p3;261. p1->rchild=p2;262. node.push(p1);263. }264. }265. opetor.push(str[i]);266.break;267.case')':268.while( !opetor.empty() && opetor.top()!='(' ) 269. {270. p1=new BinNode;271. p1->data=opetor.top();272. opetor.pop();273.if(!digit.empty())274. {275. a=digit.top();276. digit.pop();277. p2=new BinNode;278. p2->data=a;279. p2->lchild=p2->rchild=0;280.if(!digit.empty())281. {282. b=digit.top();283. digit.pop();284. p3=new BinNode;285. p3->data=b;286. p3->lchild=p3->rchild=0;287. p1->lchild=p3;288. p1->rchild=p2;289. }290.else291. {292.if(!node.empty())293. {294. p3=new BinNode;295. p3=node.top();296. node.pop();297. }298. p1->lchild=p3;299. p1->rchild=p2;300. }301. node.push(p1);302. }303. }304.if(!opetor.empty())305. opetor.pop();306. }307. }308. i++;309. }310.while(!opetor.empty()) //表达式扫描完以后,将剩下的运算符号栈的元素,一一取出作为双亲结点进行继续建树311. {312. p1=new BinNode;313. p1->data=opetor.top();314. opetor.pop();315.if(!digit.empty())316. {317. a=digit.top();318. digit.pop();319. p2=new BinNode;320. p2->data=a;321. p2->lchild=p2->rchild=0;322.if(!digit.empty())323. {324. b=digit.top();325. digit.pop();326. p3=new BinNode;327. p3->data=b;328. p3->lchild=p3->rchild=0;329. p1->lchild=p3;330. p1->rchild=p2;331. node.push(p1);332. }333.else334. {335.if(!node.empty())336. {337. p3=new BinNode;338. p3=node.top();339. node.pop();340. }341. p1->lchild=p3;342. p1->rchild=p2;343. node.push(p1);344. }345. }346.else347. {348. p2=new BinNode;349. p3=new BinNode;350. p2=node.top();351. node.pop();352. p3=node.top();353. node.pop();354. p1->lchild=p3;355. p1->rchild=p2;356. r=p1;357. }358. }359.if(node.size()==1)//运算符号栈为空后,如果node栈只剩下一个元素,那么它就是根节点360. {361. r=node.top();362. node.pop();363. }364. root=r;365. cout<<"建树完成"<<endl;366. }367.368.void PostOrder_Traverse(BinNode *p) //将中缀表达式转为后缀表达式369. {370.if(p)371. {372. PostOrder_Traverse(p->lchild);373. PostOrder_Traverse(p->rchild);374. str[pos]=p->data;375. pos++;376. }377. }378.379.void Count(char *str)380. {381. My_stack<int> s;//暂存中间结果382. cout<<"__计算表达式__"<<endl; 383.int i=0,a,b;384.while(str[i]!='\0')385. {386.if(isdigit(str[i])) 387. {388.int q=str[i]-'0'; 389. s.push(q);390. }391.else392. {393.switch(str[i])394. {395.case'+':396.if(!s.empty()) 397. {398. a=s.top(); 399. s.pop(); 400. b=s.top(); 401. s.pop(); 402. a=a+b;403. s.push(a); 404. }405.break;406.case'-':407.if(!s.empty()) 408. {409. a=s.top(); 410. s.pop(); 411. b=s.top(); 412. s.pop(); 413. a=b-a;414. s.push(a); 415. }416.break;417.case'*':418.if(!s.empty()) 419. {420. a=s.top(); 421. s.pop(); 422. b=s.top();423. s.pop();424. a=a*b;425. s.push(a);426. }427.break;428.case'/':429.if(!s.empty())430. {431. a=s.top();432. s.pop();433. b=s.top();434. s.pop();435. a=b/a;436. s.push(a);437. }438. }//end_switch439. }//end_else440. i++;441. }//end_while442. a=s.top();443. s.pop();444. cout<<"计算结果为:"<<a<<endl;445. }446.447.};测试函数"main.cpp"view plain1.#include"tree.h"2.3.int main()4.{5. BinNode *root;6. BinTree tree;7.8. root=tree.Get_Root();9. tree.Create_Expression_Tree(root);10.11.char *str;12. tree.PostOrder_Traverse(root);13.14. str=tree.Get_str();15.int i=0;16.while(str[i]!='\0')17. {18. cout<<str[i]<<' ';19. i++;20. }21. cout<<endl;22.23. tree.Count(str);24.25.return 0;26.}输入6+5*9-7/(3+4)生成的二叉树如下所示:输出结果:view plain1.输入表达式:6+5*9-7/(3+4)2.建树完成3. 5 9 * 6 + 3 4 + 7 / -4.__计算表达式__5.计算结果为:506.Press any key to continue最近也领悟到,当你调试一段比较长的代码时,如果你静下心来,你会发现,你为了跟踪某一段代码,可以想出很多很奇怪又很简单的方法,当错误都清理完后,那种成就感也是不言而喻的。
任务书算术表达式与二叉树

附件4:北京理工大学珠海学院课程设计任务书20 ~20 学年第学期学生姓名:专业班级:指导教师:工作部门:一、课程设计题目算术表达式与二叉树二、课程设计内容(含技术指标)【问题描述】一个表达式和一棵二叉树之间,存在着自然的对应关系。
写一个程序,实现基于二叉树表示的算术表达式的操作。
【任务要求】假设算术表达式Expression内可以含有变量(a~z)、常量(0~9)和二元运算符(+,-,*,/,^(乘幂))。
实现以下操作:ReadExpre(E)—以字符序列的形式输入语法正确的前缀表达式并构造表达式E。
WriteExpre(E)—用带括弧的中缀表达式输出表达式E。
Assign(V,c)—实现对变量V的赋值(V=c),变量的初值为0。
Value(E)—对算术表达式E求值。
CompoundExpr(P,E1,E2)--构造一个新的复合表达式(E1)P (E2)【测试数据】分别输入0;a;-91;+a*bc;+*5^x2*8x;+++*3^x3*2^x2x6并输出。
每当输入一个表达式后,对其中的变量赋值,然后对表达式求值。
三、进度安排1.初步设计:写出初步设计思路,进行修改完善,并进行初步设计。
2.详细设计:根据确定的设计思想,进一步完善初步设计内容,按要求编写出数据结构类型定义、各算法程序、主函数。
编译分析调试错误。
3.测试分析:设计几组数据进行测试分析,查找存在的设计缺陷,完善程序。
4.报告撰写:根据上面设计过程和结果,按照要求写出设计报告。
5.答辩考核验收:教师按组(人)检查验收,并提出相关问题,以便检验设计完成情况。
四、基本要求1.在设计时,要严格按照题意要求独立进行设计,不能随意更改。
若确因条件所限,必须要改变课题要求时,应在征得指导教师同意的前提下进行。
2.在设计完成后,应当场运行和答辩,由指导教师验收,只有在验收合格后才能算设计部分的结束。
3.设计结束后要写出课程设计报告,以作为整个课程设计评分的书面依据和存档材料。
二叉树的应用-代数表达式实现实验报告

软件技术基础实验五----- 二叉树的应用-代数表达式实现班级:电信0901学号:0703090106姓名:蒋玮珂实验五二叉树的应用-代数表达式实现(1)实验题目:编写一个程序,用二叉树表示代数表达式,二叉树的每个结点包括一个运算符或操作数,代数表达式中只包含+、-、*、/和整数且没有错误,要求按照四则运算法则构造二叉树,然后由对应的二叉树计算对应的表达式的值。
(2)实验目的:1.掌握二叉树的数据类型描述及特点。
2.掌握二叉树的存储结构(二叉链表)的建立算法。
3.掌握二叉链表上二叉树的基本运算的实现。
(3)调试通过并正确执行给定功能要求的实验代码:#include "stdafx.h"#include<iostream.h>#include<fstream.h>typedef struct bitree{int data;bitree * lchild;bitree * rchild;}bitree;bitree * createtree(int b[],int i,int j){bitree * p;int k,plus=0,posi=0;if(i==j){p=new bitree;p->data=b[i];p->lchild=p->rchild=NULL;return p;}//i!=jfor(k=i;k<=j;k++){if((b[k]==43)||(b[k]==45)){plus++;posi=k;}}//没有+或-if(!plus)for(k=i;k<=j;k++)if((b[k]==42)||(b[k]==47)){plus++;posi=k;}//还有符号存在递归if(plus){p=new bitree;p->data=b[posi];p->lchild=createtree(b,i,posi-1);p->rchild=createtree(b,posi+1,j);return p;}elsereturn NULL;}double comp(bitree *root){double v1,v2;if(!root)return 0;if ((!root->lchild)&&(!root->rchild))return root->data;v1=comp(root->lchild);v2=comp(root->rchild);switch(root->data){case 43: return v1+v2;case 45: return v1-v2;case 42: return v1*v2;case 47: return v1/v2;default:return 0;}}void DispBTNode(bitree *root){if(root){cout<<root->data;if(root->lchild||root->rchild){cout<<'(';DispBTNode(root->lchild);cout<<',';DispBTNode(root->rchild);cout<<')';}}}void main(){char a[100];int b[100],c=0;int i,j=0,n;bitree * root;double y;ifstream infile("e:\\Program Files\\MSDev98\\MyProjects\\file1.txt");ifstream ifile("e:\\Program Files\\MSDev98\\MyProjects\\file2.txt");ofstream outfile("e:\\Program Files\\MSDev98\\MyProjects\\file3.txt");infile>>n;for(i=0;i<n;i++){ifile>>a[i];}a[i]='\0';for(i=0;i<n;i++){if(a[i]!=0){if((a[i]>=48)&&(a[i]<=57)){if((a[i-1]>=48)&&(a[i-1]<=57))c=c*10+(a[i]-48);elsec=a[i]-48;}else{b[j]=c;j++;b[j]=a[i];j++;}}}b[j]=c;j++;b[j]='\0';for(i=0;i<j;i++){outfile<<b[i]<<endl;}root=createtree(b,0,j-1);y=comp(root);outfile<<y<<endl;DispBTNode(root);infile.close();ifile.close();outfile.close();}(4)实验结果截图说明:(1)file1输入的为代数式的符号个数,一个数字和一个符号都算1个(2)file2输入的为代数式,式子中不能出现43 42 45 47 这几个危险数字(3)file3为输出的结果,43为加,45为减,42为乘,47为除。
二叉树与算术表达式

目录一、系统开发的背景 (1)二、系统分析与设计 (1)(一)系统功能要求 (1)(二)系统模块结构设计 (1)三、系统的设计与实现 (1)(一)输入和存储表达式:I NPUT_E XPR()、R EAD E XPR() (1)(二)输出中缀表达式W RITE E XPER() (3)四、系统测试 (4)(一)测试I NPUT_E XPR()、R EAD E XPR() (4)(二)测试W RITE E XPER() (4)五、总结 (4)六、附件(代码、部分图表) (5)二叉树与算术表达式一、系统开发的背景为了方便求出一个表达式的值,因此设计这个算法完成这个功能。
二、 系统分析与设计(一)系统功能要求1、 ReadExpre(E)—以字符序列的形式输入语法正确的前缀表达式并构造表达式E 。
2、 WriteExpre(E)—用带括弧的中缀表达式输出表达式E 。
(二)系统模块结构设计通过对系统功能的分析,算术表达式系统功能如图1所示。
图1 二叉树与算术表达式功能图通过上图的功能分析,把整个系统划分为2个模块: 1、 输入和存储表达式,通过Input_Expr ()函数来实现; 2、 输出中缀表达式,通过WriteExpr ()函数来实现;三、 系统的设计与实现(一)输入和存储表达式:Input_Expr ()、ReadExpr( )分析:用Input Expr ()进行数据的录入,再通过ReadExpr()将之前录入的数据存储进二叉树。
该模块具体代码如下:Status Input_Expr(char *string,int flag){if(flag==0)printf("\n请输入正确的前缀表示式:");else printf("\n请以表达式的原书写形式输入正确表示式:");flushall();gets(string);if(strlen(string)==1)if(string[0]=='+'||string[0]=='-'||string[0]=='*'||string[0]=='/'||string[0]=='^'){ printf("\n表达式只有一个字符,为运算符,错误!");return 0;}elseif((string[0]>='0'&&string[0]<'9')||(string[0]>='a'&&string[0]<='z')||(string[0]>='A'&&string[0]<='Z ')){ printf("\n表达式只有一个字符!");return 1;}else {printf("\n输入的字符不是运算符也不是变量常量,错误!");return 0;} return 1;}Status ReadExpr(BiTree *E,char *exprstring){SqStack S;int i,len;BiTree p,q;(*E)=(BiTree)malloc(sizeof(BiTNode));(*E)->lchild=NULL;(*E)->rchild=NULL;len=strlen(exprstring);if(len==1)ErChaShu(E,exprstring,0);else{ErChaShu(E,exprstring,0);InitStack(&S);q=(*E);Push(&S,q);Push(&S,q);for(i=1;i<len&&!StackEmpty(S);i++){p=(BiTree)malloc(sizeof(BiTNode));ErChaShu(&p,exprstring,i);p->lchild=NULL;p->rchild=NULL;if(exprstring[i]=='+'||exprstring[i]=='-'||exprstring[i]=='*'||exprstring[i]=='/'||exprstring[i] =='^'){if(!q->lchild) {q->lchild=p;Push(&S,p);q=p;}else {q->rchild=p;Push(&S,p);q=p;}}else{if(!q->lchild) {q->lchild=p;Pop(&S,&q);}else {q->rchild=p;Pop(&S,&q);}}}if(StackEmpty(S)&&i>=len)return 1;else{printf("\n输入的表达式有误!");return 0;}}}注:该流程图见附件。
算术表达式与二叉树

目录一、系统开发的背景 (1)二、系统分析与设计 (1)(一)系统功能要求 (1)(二)系统模块结构设计 (1)三、系统的设计与实现 (3)(一)二叉树的遍历 (3)(二)算术表达式求值 (5)四、系统测试 (9)(一)测试二叉树遍历函数 (9)(二)测试算术表达式求值函数 (10)五、总结 (10)六、附件(代码、部分图表) (10)(一)程序代码 (10)(二)实验截图 (15)算术表达式与二叉树一、系统开发的背景为了方便进行基本的算术运算,减轻对数字较大的数操作时所带来的麻烦,及其在运算过程中错误的避免。
因此设计算术表达式与二叉树的程序来解决此问题。
二、系统分析与设计(一)系统功能要求由于一个表达式和一棵二叉树之间,存在着自然的对应关系。
遍写一个程序,实现基于二叉树表示的算术表达式的操作。
算术表达式内可以含有变量(a~z)、常量(0~9)和二元运算符(+,-,*,/,^(乘幂))。
具体实现以下操作:1以字符序列的形式输入语法正确的前缀表达式并构造表达式。
2用带括弧的中缀表达式输出表达式。
3实现对变量V的赋值(V=c),变量的初值为0。
4对算术表达式E求值。
(二)系统模块结构设计通过对系统功能的分析,基于二叉树表示的算术表达式的功能如图(1)所示。
图1:基于二叉树表示的算术表达式的功能图通过上图的功能分析,把整个系统划分为主要的两大个模块:1、将语法正确的前缀表达式用二叉树的遍历转换成相应的遍历序列,必要时可以求出此二叉树的结点数及其树的深度。
该模块借助函数BiTree Create(BiTree T)创建二叉树,void Preorder(BiTree T) 先序遍历, void InOrder(BiTree T)中序遍历,void PostOrder(BiTree T)后序遍历,int Sumleaf(BiTree T)统计叶结点的数目,int Depth(BiTree T)二叉树的深度6个函数联合来实现;2、计算中序遍历所得的算术表达式的值。
c语言基于二叉树的表达式求值算法

c语言基于二叉树的表达式求值算法C语言中,基于二叉树的表达式求值算法主要包括两部分:中缀表达式转换为后缀表达式和后缀表达式求值。
1.中缀表达式转换为后缀表达式中缀表达式是我们常见的数学表达方式,例如3 + 4 * 2 - 5。
为了方便计算机求值,我们需要将中缀表达式转换为后缀表达式,也叫做逆波兰表达式。
转换的过程使用栈数据结构来实现。
具体算法如下:1.定义一个栈和一个结果字符串,栈用于存储操作符,结果字符串用于保存后缀表达式。
2.从左到右遍历中缀表达式的每一个字符。
3.如果当前字符是数字,直接将其加入结果字符串。
4.如果当前字符是左括号"(",将其入栈。
5.如果当前字符是右括号")",则依次将栈顶的操作符弹出并加入结果字符串,直到遇到左括号为止,同时将左括号从栈中弹出。
6.如果当前字符是操作符,需要将栈中优先级比当前操作符高或者相等的操作符弹出并加入结果字符串,然后将当前操作符入栈。
7.遍历完所有字符后,将栈中剩余的操作符依次弹出并加入结果字符串。
8.最终结果字符串就是后缀表达式。
例如,对于中缀表达式3 + 4 * 2 - 5,转换为后缀表达式为3 4 2 * + 5 -2.后缀表达式求值后缀表达式求值算法使用栈数据结构来实现。
具体算法如下:1.定义一个栈,用于存储操作数。
2.从左到右遍历后缀表达式的每一个字符。
3.如果当前字符是数字,则将其转换为对应的整数并入栈。
4.如果当前字符是操作符,则从栈中弹出两个操作数,先弹出的作为右操作数,后弹出的作为左操作数,根据操作符进行运算,得到结果后入栈。
5.遍历完所有字符后,栈顶的数字即为最终的结果。
例如,对于后缀表达式3 4 2 * + 5 -,求值的过程如下:1.入栈3。
2.入栈4。
3.入栈2。
4.弹出2和4,计算4 * 2 = 8,将8入栈。
5.弹出8和3,计算3 + 8 = 11,将11入栈。
6.入栈5。
7.弹出5和11,计算11 - 5 = 6,得到最终结果。
简单算术表达式的二叉树的构建和求值

一、概述二、算术表达式的二叉树表示1. 什么是二叉树2. 算术表达式的二叉树表示方法三、算术表达式二叉树的构建1. 中缀表达式转换为后缀表达式2. 后缀表达式构建二叉树四、算术表达式二叉树的求值五、应用举例六、总结一、概述在数学和计算机科学中,处理算术表达式是一个常见的问题。
在计算机中,算术表达式通常以中缀、前缀或后缀的形式出现,其中中缀表达式最为常见。
而采用二叉树来表示和求解算术表达式,是一种常见且高效的方法。
二、算术表达式的二叉树表示1. 什么是二叉树二叉树是一种树形数据结构,它的每个节点最多只能有两个子节点,分别是左子节点和右子节点。
二叉树可以为空,也可以是非空的。
2. 算术表达式的二叉树表示方法在二叉树中,每个节点要么是操作符,要么是操作数。
操作符节点的左子节点和右子节点分别表示运算符的两个操作数,而操作数节点则不包含任何子节点。
通过这种方式,可以将算术表达式表示为一个二叉树结构。
三、算术表达式二叉树的构建1. 中缀表达式转换为后缀表达式为了构建算术表达式的二叉树,首先需要将中缀表达式转换为后缀表达式。
中缀表达式是人们常见的形式,例如"2 + 3 * 5",而后缀表达式则更适合计算机处理,例如"2 3 5 * +"。
将中缀转后缀的算法即为中缀表达式的后缀转换法则。
2. 后缀表达式构建二叉树构建二叉树的过程通常采用栈来辅助完成。
从左到右扫描后缀表达式,对于每个元素,如果是操作数,则入栈;如果是操作符,则弹出栈顶两个元素作为其左右子节点,然后将操作符节点入栈。
最终栈中只剩一个节点,即为构建的二叉树的根节点。
四、算术表达式二叉树的求值算术表达式二叉树的求值是递归进行的。
对于二叉树的每个节点,如果是操作符节点,则递归求解其左右子节点的值,并进行相应的操作;如果是操作数节点,则直接返回其值。
最终得到根节点的值,即为整个算术表达式的值。
五、应用举例以中缀表达式"2 + 3 * 5"为例,首先将其转换为后缀表达式"2 3 5 * +",然后根据后缀表达式构建二叉树,最终求得二叉树的根节点即为算术表达式的值。
主要完成利用二叉树求解表达式值的代码编写。 -回复

主要完成利用二叉树求解表达式值的代码编写。
-回复如何利用二叉树求解表达式值的问题。
在本文中,我们将详细讨论如何使用二叉树数据结构来解析和计算表达式的值。
首先,让我们更深入地了解什么是表达式以及它与二叉树的关系。
表达式是由操作数和运算符组成的数学表达式,例如1 + 2 * 3。
这个表达式中的操作数包括1、2 和3,而运算符包括+ 和*。
在我们的例子中,+ 运算符的优先级较低,因此需要先计算乘法运算,然后再进行加法运算。
这意味着结果应该是1 + (2 * 3) = 7。
通过采用二叉树数据结构,我们可以轻松地实现对表达式的求解过程。
我们将在二叉树节点中存储运算符和操作数,并使用左右子节点来表示运算的顺序。
接下来,我们将详细回答如何使用二叉树求解表达式值的问题。
第一步:将表达式转换为二叉树结构我们需要首先将表达式转换为一个二叉树。
为了实现这一步骤,我们可以使用递归算法。
该算法的基本思路是找到具有最低优先级运算符的位置,然后将其作为根节点创建一个新的二叉树。
左子节点将是递归应用于运算符之前的子表达式,而右子节点则是递归应用于运算符之后的子表达式。
以前面的例子1 + 2 * 3 为例,我们可以按照以下步骤创建二叉树:1. 找到最低优先级运算符*,将其作为根节点创建一个新的二叉树。
2. * 运算符之前的子表达式为2,将其作为左子节点。
3. * 运算符之后的子表达式为3,将其作为右子节点。
这样,我们就得到了以下二叉树结构:*/ \2 3接下来,我们需要递归地重复这个过程,直到我们得到一个只包含操作数的叶子节点为止。
在这个例子中,我们得到了以下完整的二叉树结构:+/ \1 */ \2 3第二步:遍历二叉树并计算表达式值一旦我们创建了二叉树,我们就可以使用树遍历算法来计算表达式的值。
我们将使用后序遍历的方式,首先计算左子树的值,然后计算右子树的值,最后应用根运算符。
对于叶子节点,我们只需要返回该节点的值。
对于运算符节点,我们需要递归地计算左右子树的值,然后应用相应的运算符。
二叉树基本运算算法的实现

二叉树基本运算算法的实现
二叉树是一种常见的数据结构,基本运算算法包括二叉树的遍历、查找、插入、删除等操作。
下面是这些算法的实现:
1. 二叉树遍历:二叉树遍历有三种方式,分别是前序遍历、中序遍历和后序遍历。
其中,前序遍历先访问根节点,再访问左子树和右子树;中序遍历先访问左子树,再访问根节点和右子树;后序遍历先访问左子树,再访问右子树和根节点。
遍历可以使用递归算法或栈实现。
2. 二叉树查找:二叉树查找可以使用递归算法或循环算法实现。
递归算法通过比较节点值实现查找,如果查找值小于当前节点值,则在左子树中查找,否则在右子树中查找。
循环算法使用二叉树的特性,比较查找值和当前节点值的大小,根据大小关系不断移动到左子树或右子树中进行查找,直到找到目标节点或遍历到叶子节点为止。
3. 二叉树插入:二叉树插入需要先查找到插入位置,然后在该位置插入一个新节点。
插入操作可以使用递归算法或循环算法实现。
4. 二叉树删除:二叉树删除分为三种情况:删除叶子节点、删除只有一个孩子的节点和删除有两个孩子的节点。
删除叶子节点很简单,只需要将其父节点的指针设为NULL即可。
删除只有一个孩子的节点需要将父节点的指针指向该节点的
孩子节点。
删除有两个孩子的节点需要找到该节点的后继节点(或前驱节点),将后继节点的值复制到该节点中,然后删除后继节点。
上述算法的实现需要根据具体的编程语言进行调整和实现。
二叉树基本运算算法的实现

二叉树基本运算算法的实现二叉树是一种常见的数据结构,它由节点和边组成,每个节点最多有两个子节点,分别称为左子节点和右子节点。
二叉树的基本运算算法包括创建二叉树、遍历二叉树、查找二叉树中的节点、插入节点、删除节点等操作。
一、创建二叉树创建二叉树的方法有多种,其中最常用的是递归法。
递归法的基本思路是先创建根节点,然后递归地创建左子树和右子树。
具体实现如下:```pythonclass TreeNode:def __init__(self, val=0, left=None, right=None):self.val = valself.left = leftself.right = rightdef create_tree(nums):if not nums:return Nonemid = len(nums) // 2root = TreeNode(nums[mid])root.left = create_tree(nums[:mid])root.right = create_tree(nums[mid+1:])return root```上述代码中,create_tree函数接收一个有序数组nums作为参数,返回一个二叉树的根节点。
首先判断nums是否为空,如果为空则返回None。
否则,找到nums的中间位置mid,将nums[mid]作为根节点的值,然后递归地创建左子树和右子树,最后返回根节点。
二、遍历二叉树遍历二叉树是指按照一定的顺序访问二叉树中的所有节点。
常用的遍历方法有三种:前序遍历、中序遍历和后序遍历。
其中,前序遍历的顺序是先访问根节点,然后访问左子树,最后访问右子树;中序遍历的顺序是先访问左子树,然后访问根节点,最后访问右子树;后序遍历的顺序是先访问左子树,然后访问右子树,最后访问根节点。
下面是三种遍历方法的实现:```pythondef preorder_traversal(root):if not root:return []res = []stack = [root]while stack:node = stack.pop()res.append(node.val)if node.right:stack.append(node.right) if node.left:stack.append(node.left) return resdef inorder_traversal(root):if not root:return []res = []stack = []node = rootwhile stack or node:while node:stack.append(node)node = node.leftnode = stack.pop()res.append(node.val)node = node.rightreturn resdef postorder_traversal(root):if not root:return []res = []stack = [root]while stack:node = stack.pop()res.append(node.val)if node.left:stack.append(node.left)if node.right:stack.append(node.right)return res[::-1]```上述代码中,preorder_traversal函数实现了前序遍历,inorder_traversal函数实现了中序遍历,postorder_traversal函数实现了后序遍历。
利用二叉树以及栈对算术表达式实现四则运算等计算功能代码

#include <iostream>#include <string>#include <sstream>#include <stack>#include <cmath>using namespace std;bool IsOperator(string mystring) //判断字符串是否是运算符{if(mystring == "-"||mystring == "+"||mystring == "*"||mystring == "/"||mystring == "^"||mystring == "%")return true;elsereturn false;}bool IsOperator(char ops) //判断一个字符是否是运算符{if(ops == '+'||ops== '-'||ops== '*'||ops== '/'||ops== '^'||ops== '%'||ops=='('||ops==')') return true;elsereturn false;}bool IsOperand(char ch) //判断是否是数字{if (((ch>='0')&&(ch<='9'))||(ch=='.'))return true;elsereturn false;}bool isok(string exp) //判断输入是否正确{char check;int error=0,lb=0,rb=0,numofoperand=0,numofoperator=0;for(int m=0;m<exp.size();m++){check=exp[m];if(IsOperand(check)){if(check=='.'){if(!(exp[m-1]>='0'&&exp[m-1]<='9')&&(exp[m+1]>='0'&&exp[m+1]<='9'))error++;cout<<"浮点型数据输入有误!!!"<<endl;}}numofoperand++;}else if(IsOperator(check)){if(check==')'){rb++;if(rb>lb){error++;cout<<"右括号不可能大于左括号!!!"<<endl;}if(IsOperator(exp[m+1])&&(exp[m+1]=='+'||exp[m+1]=='-'||exp[m+1]=='*'||exp[m+1]=='/'||e xp[m+1]=='^'||exp[m+1]==')'||exp[m+1]=='%')){numofoperator++;m++;if(exp[m]==')')rb++;}else if(IsOperator(exp[m+1])||IsOperand(exp[m+1])){error++;cout<<"右括号后不可能直接跟数据或左括号!!!"<<endl;}}else if(check=='('){lb++;if(IsOperator(exp[m+1])&&exp[m+1]=='('){m++;lb++;}else if(IsOperator(exp[m+1])){error++;cout<<"左括号后运算符只能跟左括号!!!"<<endl;}else{numofoperator++;if(IsOperator(exp[m+1])&&exp[m+1]=='('){m++;lb++;}else if(IsOperator(exp[m+1])){error++;cout<<"非括号的运算符不能直接接非括号运算符!!!"<<endl;}}}else{error++;cout<<check<<"为非法字符!!!"<<endl;}}if((error==0)&&(lb==rb)&&(numofoperand!=0)&&(numofoperator!=0))return true;elsereturn false;}bool addition(char OperatorA,char OperatorB) //A=B返回TRUE.{if(OperatorA==OperatorB||(OperatorA=='*'&&OperatorB=='/')||(OperatorA=='/'&&Operator B=='*')||(OperatorA=='+'&&OperatorB=='-')||(OperatorA=='-'&&OperatorB=='+')) return true;elsereturn false;}bool TakesPrecedence(char OperatorA,char OperatorB) //按照优先级用if从最优至最后从上至下排列,从而达到比较A与B的优先级{if(OperatorA=='(')return false;else if(OperatorB=='(')return false;else if(OperatorB==')')return true;else if(addition(OperatorA,OperatorB))return false;else if((OperatorA=='^')&&(OperatorB=='^'))return false;else if(OperatorA=='^')return true;else if(OperatorB=='^')return false;else if((OperatorA=='%')&&(OperatorB=='%'))return false;else if(OperatorA=='%')return true;else if(OperatorB=='%')return false;else if((OperatorA=='*')||(OperatorA=='/'))return true;else if((OperatorB=='*')||(OperatorB=='/'))return false;else if((OperatorA=='+')||(OperatorA=='-'))return true;elsereturn true;}//****************************************************************************//class BinNode{public:string data;BinNode *left_child;BinNode *right_child;BinNode(string k) //构造函数{data=k;left_child=NULL;right_child=NULL;}};class binary_tree{public:BinNode *root; //根节点binary_tree(void){root=NULL;} //构造函数void print(void){print(root);}void print(BinNode *p){if(p!=NULL){print(p->left_child);print(p->right_child);cout<<p->data<<" ";}}void evaluate(void){evaluate(root);}bool evaluate(BinNode *prt) //计算二叉树一个节点{if(IsOperator(prt->data)&&!IsOperator(prt->left_child->data)&&!IsOperator(prt->right_chil d->data)){float num=0;float num1=atof(prt->left_child->data.c_str());float num2=atof(prt->right_child->data.c_str());if(prt->data=="+")num=num1+num2;else if(prt->data=="-")num=num1-num2;else if(prt->data=="*")num=num1*num2;else if(prt->data=="/"){if(num2==0.0){cout<<"除数为零!!!运算出错";return 0;}elsenum=num1/num2;}else if(prt->data=="^")num=pow(num1,num2);else if(prt->data=="%"){if(num2==0.0){cout<<"除数为零!!!运算出错";return 0;}elsenum=(long)num1%(long)num2;}stringstream bob;bob<<num;string suzzy(bob.str());prt->data=suzzy;prt->left_child=NULL;prt->right_child=NULL;}else if(prt->left_child==NULL&&prt->right_child==NULL);else{evaluate(prt->left_child);evaluate(prt->right_child);evaluate(prt);}return 1;}void clear_help(void){clear_help(root);}void clear_help(BinNode *rt){if(rt!=NULL){clear_help(rt->left_child);clear_help(rt->right_child);delete rt;}}};BinNode *build_node(string x){BinNode *new_node;new_node=new BinNode(x);return (new_node);}void copy(BinNode *&r1,BinNode* r2)//请注意这里的*&!!!{if(r2==NULL)r1=NULL;else{r1=build_node(r2->data);copy(r1->left_child,r2->left_child);copy(r1->right_child,r2->right_child);}}/****************************************************************************/int main(){binary_tree etree;stack<binary_tree> NodeStack;stack<char> OpStack;string infix;char choice='y';char c;while(choice=='y'||choice=='Y'){cout<<endl<<"Introduce the Expression:"<<endl;getline(cin,infix);for(int j=0;j<infix.size();j++){if(infix[j]==' '){infix.erase(j,1);j--;}}cout<<" 华丽的分割线"<<endl<<"-----------------------------"<<endl;cout<<"Expression: "<<infix<<endl;if(isok(infix)){for(int i=0;i<infix.size();i++){c=infix[i];if(i==0 && c=='-') //若开始为负,则把零压入运算数栈,把'-'压入运算符栈{binary_tree temp;temp.root=build_node("0");NodeStack.push(temp);OpStack.push('-');}elseif(IsOperand(c)){string tempstring="";tempstring=tempstring+c;while(i+1<infix.size()&&IsOperand(infix[i+1])){tempstring+=infix[++i];}binary_tree temp;temp.root=build_node(tempstring);NodeStack.push(temp);}else if(c=='+'||c=='-'||c=='/'||c=='*'||c=='^'||c=='%'){if(OpStack.empty())OpStack.push(c);else if(OpStack.top()=='(')OpStack.push(c);else if(TakesPrecedence(c,OpStack.top()))OpStack.push(c);else{while(!OpStack.empty()&&(TakesPrecedence(OpStack.top(),c)||addition(OpStack.top(),c))){binary_tree temp_tree;string thisstring="";thisstring=thisstring+OpStack.top();OpStack.pop();etree.root=build_node(thisstring);copy(temp_tree.root,NodeStack.top().root);NodeStack.pop();etree.root->right_child=temp_tree.root;temp_tree.root=NULL;copy(temp_tree.root,NodeStack.top().root);etree.root->left_child=temp_tree.root;NodeStack.pop();temp_tree.root=NULL;copy(temp_tree.root,etree.root);NodeStack.push(temp_tree);etree.root=NULL;}OpStack.push(c);}}if(c=='(') //若中间遇到括号,则判断下一位是否为'-' {OpStack.push(c);if(infix[i+1]=='-'){binary_tree temp;temp.root=build_node("0");NodeStack.push(temp);OpStack.push('-');++i;}}else if(c==')'){while(OpStack.top()!='('){binary_tree temp_tree;string thisstring="";thisstring=thisstring+OpStack.top();OpStack.pop();etree.root=build_node(thisstring);copy(temp_tree.root,NodeStack.top().root);NodeStack.pop();etree.root->right_child=temp_tree.root;temp_tree.root=NULL;copy(temp_tree.root,NodeStack.top().root);etree.root->left_child=temp_tree.root;NodeStack.pop();temp_tree.root=NULL;copy(temp_tree.root,etree.root);NodeStack.push(temp_tree);etree.root=NULL;}OpStack.pop();}}while(!OpStack.empty()){binary_tree temp_tree;string thisstring="";thisstring=thisstring+OpStack.top();OpStack.pop();etree.root=build_node(thisstring);copy(temp_tree.root,NodeStack.top().root);NodeStack.pop();etree.root->right_child=temp_tree.root;temp_tree.root=NULL;copy(temp_tree.root,NodeStack.top().root);etree.root->left_child=temp_tree.root;NodeStack.pop();temp_tree.root=NULL;copy(temp_tree.root,etree.root);NodeStack.push(temp_tree);if(!OpStack.empty())etree.root=NULL;}cout<<"Postfix traversal:";etree.print();cout<<endl;etree.evaluate();cout<<"The result is:"<<etree.root->data<<endl;cout<<"------------------------------------------------"<<endl;cout<<endl<<"Run Program again? Enter<y/n>:";cin>>choice;getchar();}else{cout<<"**************************"<<endl;cout<<"ERROR: Invalid Exprssion"<<endl;cout<<endl<<"Run Program again? Enter<y/n>:";cin>>choice;getchar();}}return 0;}。
基于二叉树的表达式求值算法

基于二叉树的表达式求值算法二叉树的表达式求值算法可以使用递归来实现,具体步骤如下:1. 若该节点为数字节点,则直接返回节点的值;2. 若该节点为操作符节点,则递归计算其左右子树的值,并根据操作符进行计算,最终返回计算结果。
所以,我们可以先构建一个二叉树,然后对二叉树进行递归遍历,实现表达式的求值。
具体实现如下:pythonclass TreeNode:def __init__(self, val):self.val = valself.left = Noneself.right = Nonedef evaluate(root: TreeNode) -> int:"""对二叉树进行递归遍历,实现表达式的求值"""# 如果当前节点为数字,直接返回节点的值if not root.left and not root.right:return int(root.val)# 递归计算左子树的值和右子树的值left_val = evaluate(root.left)right_val = evaluate(root.right)# 根据运算符计算当前节点的值if root.val == '+':return left_val + right_valelif root.val == '-':return left_val - right_valelif root.val == '*':return left_val * right_valelse:return left_val right_val这里假设输入的二叉树是合法的,即括号、运算符和操作数的顺序都正确,不需要进行错误处理。
题目设计一个程序实现基于二叉树表示的算术表达式的操作。

题目:设计一个程序实现基于二叉树表示的算术表达式的操作。
一、需求分析1、以二叉树为基本模型,构建了表达式二叉树。
算术表达式的合法输入数据包括变量(,a~z)、常量(0-9)和二元运算符(+,-,*,/,^(乘幂)),一元运算符(sin,cos,tan)。
演示程序以人机对话的方式执行,即在计算机上显示提示信息后,由用户在键盘上输入对应的数据或命令,程序将执行相应的操作并显示下一步信息。
表达式的输出主要是用带括号的中缀表示式输出调用函数InorderExp( ExpTree E, Status ( * Visit )( ExpTree e ) );2、程序的目的实现算术表达式在计算机里的树形存储,实现基本的运算(+,-,*,/,^(乘幂))sin,cos,tan),求偏导,常数合并。
3、测试数据(附后)。
提供两种方式的测试:一种是自动测试,即程序调用test文件夹data.txt文件里的测试数据,另一种方式是手动测试,即按程序提示一步一步输入测试。
除了满足要求的0; a; -91; +a*bc; +*5^x2*8x; +++*3^x3*2^x2x6,还有几十组数据测试。
每当输入一个表达式后,程序提示用户赋值,再对表达式求值。
为了方便用户,我在程序中用数组保存着一些测试数据,以供测试用。
二、概要设计1.以字符串保存输入的字符序列。
2.提示用户赋值的同时将数据取出建立二叉树。
3.用后根遍历的次序用递归函数对表达式求值,求值时进行相应的转化,将运算数的字符形式转换成整数形式。
4.用中缀表达式输出表达式时,适当添加括号,以正确反映运算的优先次序。
5.抽象数据类型的定义:1)、存放表达式的结构类型,是以二叉树为基本原型。
typedef enum{ OPER, V AR, ORD }ElemTag;//运算符,变量,常量typedef struct ExpNode{ElemTag tag; //标记union{char expr[4]; //存放运算符名struct{char var; //存放变量名int val; //存放变量的值,初始值为0}vary; //存放变量int ordina; //存放常量值};struct ExpNode *lchild, *rchild; /* 左右孩子指针*/} *ExpTree; /* 二叉树的二叉链表存储表示*/基本操作:int Random( int nMin, int nMax );//返回nMin到nMax之间的随机数void FindVary( char * c, char * e );//找出表达式中的变量Status ArrayCreateExp( ExpTree &E, char *ch, int &i );//从ch数组中读取字符串,构造表达式void CreateExp( ExpTree &E, char *ch, int &i ) ;//Status InputCreateExp( ExpTree &E );//从键盘先序输入来构造表达式树TStatus Visit( ExpTree e );//输出e的内容void InorderExp( ExpTree E, Status ( * Visit )( ExpTree e ) );//输出中序表达式用带括号的中缀表示式输出Status Assign( ExpTree E, char v, float c ) ;//对表达式内的所有v,赋值cfloat Value( ExpTree E );//计算表达式的值ExpTree Compound( char p, ExpTree e1, ExpTree e2 );//5.构造一个新的复合表达式(E1)P(E2)Status Diff( ExpTree &E, char V );//求表达式E对变量V的导数void MergeConst( ExpTree E );//合并表达式种所有常数运算Status PreOrderTraverse( ExpTree E, Status ( * Visit )( ExpTree e ) ); //波兰式输出Status PostOrderTraverse( ExpTree E, Status ( * Visit )( ExpTree e ) ); //逆波兰式输出2)、队列typedef char QElemType;typedef struct QNode{QElemType data;struct QNode *next;}QNode, *QuePtr;typedef struct{QuePtr front;QuePtr rear;}Queue;基本操作:Status InitQueue( Queue &Q );//构造一个空队列Status DestroyQueue( Queue &Q );//销毁队列Status QueueEmpty( Queue Q );//判空Status EnQueue( Queue &Q, QElemType e );//插入元素e为Q的新的队尾元素Status DeQueue( Queue &Q, QElemType &e );//删除队头元素,用e返回其值,并返回OK,否则返回ERROR;3)、栈typedef struct{SElemType *base;SElemType *top;int stacksize;}SqStack;基本操作:Status InitStack( SqStack &S );Status StackEmpty( SqStack S );Status Push( SqStack &S, SElemType e );Status Pop( SqStack &S, SElemType &e );SElemType Top( SqStack S );6、主程序:void main(){while(1){ 接受命令处理命令;Switch(){case: 1.以数组形式输入前缀表示式函数构造表达式.case: 2.以字符序列输入前缀表示式函数构造表达式.case: 3.实现对变量V的赋值(V=c).case: 4.对算术表达式E求值.\n");case: 5.构造一个新的复合表示式(E1)P(E2).case: 6.求偏导函数Diff(E,V)case: 7.对三角函数的测试.case: 8.常数合并.case: 0.结束}}三、详细设计1、存放表达式的结构类型,是以二叉树为基本原型。
巧妙地用二叉树完成算式计算算法计算器,二叉树,C++,独辟蹊径

巧妙地⽤⼆叉树完成算式计算算法计算器,⼆叉树,C++,独辟蹊径#01、引⾔,我们知道算式计算的问题是栈⾥⾯⼀个⾮常经典的题⽬。
但是⽤栈来实现是⼀个⾮常⿇烦的过程,第⼀要解决算式判断,是否为符合规则的算式,第⼆要由中最表达式转化为后缀表达式。
这两个部分是栈实现计算算式表达式的⽐较复杂的地⽅。
不仅如此,栈实现⾥⾯的各种运算符的优先级,各种条件判断,可以说是⿇烦的要命。
但是,实际上有⼀种数据结构⽐栈更适合解决这类问题。
可以说是得天独厚的优势。
对,就是⼆叉树。
例如⼀个表达式:1+2*3-4/5我们构造这样⼀个⼆叉树当构造这样⼀个⼆叉树之后,解决表达式的值的⽅法,也就浮出⽔⾯了,把2和3相乘,存到*的节点中,然后再和1相加,存到+的节点中.....最后根节点-节点中存放的就是最后的计算结果。
就是叶⼦节点执⾏其双亲节点的运算,结果存到双亲节点中。
#02、选⼆叉树作为算法的存储结构有什么好处。
这主要有两个⽅⾯的好处,这也是针对于栈算法的两个⿇烦的地⽅。
<1>//免除了算式表达式的检查过程。
为什么能免除检查,表达式的规范性呢?并不是不需要检查,⽽是检查的过程就包含在创建⼆叉树的过程。
认真分析这棵⼆叉树,我们会发现,所有的叶⼦节点必须是操作数节点,⽽所有的⾮叶⼦节点必须是运算符节点,否则表达式的结构⼀点不正确,创建⼆叉树的过程就可以对表达式经⾏检查。
表达式是否正确也只取决于两个⽅⾯,第⼀、表达式的结构是否正确,⽐如不能出现2*+6这样的表达式,第⼆、表达式的数据是否正确,例如不能出现1+2.2.3这样的表达式,2.2.3不是⼀个符合规则的数据。
⽽数据的检查,也可以在给叶⼦节点赋值的时候检查。
所以避免的单独经⾏表达式检查的繁琐。
<2>//不需要转化为后缀表达式再经⾏表达式结果的计算,这也是得益于⼆叉树这种结构的天然优势,⾃我感觉就完全是为这种算法题设计的,天造地设嘛!#03、算法实现0x001、数据结构的定义:1#define Maxsize 1002//定义数据元素类型3 typedef char elemtype;4//定义⼆叉树数据变量5 typedef union6 {7char Operator;8double date;9 }perdate;10//定义⼆叉树链式存储结构11 typedef struct node12 {13 perdate DATE;//⽤union类型存运算符或操作数14struct node *lchild;15struct node *rchild;16 }btnode; 1struct op2 {3char opration;4int index;//括号层数//当这个index被标记为-1时,就不会再次被查找到5int locate;//op的位置6 };⽤union定义⼀个perdate类型,⽤来分别记录操作数和运算符。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
&x ) Is ) {
it p s = 0z n o l B N T o d e { 1c h ild =
gt o et+x l ps) e d(r is , O1; N s ) B N e* o T O r t= gt oe t ps, d o e d (r ol N s+ I s) x 1; )
d t SrCU ,t r r e o sl i s f r c n et g aa tU tr e e h e ae sl m o t n o ov r i d uo n
a i me i e pes n t b a y t e . T i p p r d c s s r h t x rs 0 i re t c  ̄ n r h a e i us s s e
/^\ \
() +2 -)4 b 5 ( 32
igtr ryro- ot f e i i ( t > pr ( P ot o ) > gtr fyn e > pr e ii (o - ot) P ot d ) {
n o d e — — >lhl =r o ; c id o t n o d e — —
{ p s+ 1 o = ;
基于二叉树的算术表达 式计算 与实现
E a u to f a i me i e p e so a e n b n r r e v l a in o r h t t c x r s i n b s d o i a y te
r u n NU L e r L ; t } eefc= \ ’ IUT NU L l ( =’0)  ̄ I L ; s h L I
/^ \
1 + 1 1
/\
r5 i 女
w i( oe gt oe t ps ,I1 hl(d = e d (r olp S en N s+ 3 ) ) ) {
/\
—
/\
I一
2 r 3 2
、 、 ,
4
2 、
、
4、
/^\ \
5
,
D :1 .9 9 ji n 10 - 9 2 2 1 .3 1 5 OI 0 36 / . s .0 1 8 7 .0 2 1 .3 s
ቤተ መጻሕፍቲ ባይዱ
基金项 目:高职高专计算机类专业2 1年度规划课题 (Z 9 12 ) 02 J W50 16资助 1 1
c a Te(r 1 ps; r t re t , o) ee s+ } e e c = )) l h =。 s ’
、
} B o e *rae e(h r *t, it TN d cetTrec a s r n
结构 ,原 因在 于 只要以 不 同顺序遍 历 此树就 能够生成表达 式的不 同表示 。 表达式 树具有以 下特点 :1 )操作数都 是 叶子结点 ;2 )运算 符都是 内部结 点。 从 图 1 看 出 ,操 作符 和 操 作数 都 变成 可 了树 中的结 点。对 操作 数是 多位 数的 情况 , 为方 便处 理 ,在结 点的 定义 上 ,内部结 点 以 ot ̄存操作符 ,而叶子结 点以dt保存操 作 pr { aa 数 ,各结 点均 以l i ;rh d 别指 向结 点 c l ̄ ci分 h dN l 的左右子树 。表 达式树的构建 步骤如下 :
B N T o d e } r c h ild =
gt o et+ ol t ̄ ) e d(r ps ,xs , N s 1
r ot >l hid : lhid; o - c l c l
r o ->rh l = r h l ot ci d ci d; B No e * o e T d n d ;
() —+ + I a 52 4 1
图1表达式树
i cr n f porm n aga e n f f y i l n on g o rga mi l ug sad oe o tpa Ni g n l c
a pc t n n t n e o te t c p l i i a c s f h sa k. I h c us o i o a s n e t o re f
树 ;数 据 结 构
Ab va t s c Ar h t e p e s n sa k a d i r t e a e i me i x r s i , t c n bn y r e r t c o a f n a n a c n e t i t d ig a a tu t r . u d me t l o c p s n s u y n d t s r c u e Ev l t g r h ei × 『 0 i n f a i p ol s a a i ai m t e D u n t c 删 n s e o b s rb m o c e
r  ̄ / 1 p; e 7
陈海珠 郑卉
重 庆 电子 工 程 职 业 学 院 软 件 工 程 系 4 1 3 O51 摘 要 算 术表达 式 、栈 的操作 、二 叉树 的遍 历这 几 个概 念是 数据 结构 教 学 中的基 本 内容。算 术 表达 式 求值是 程序 设计 语 言编译 中的一个 最 基 本问题 ,也 是 栈应 用的一 个典 型例 子 。在 数据 结 构 中没有 解决 表达 式与二 叉树 之 间的 相 互转换 关 系。 本文 旨在研 究表 达 式向二 叉 树 的转换 ,即扫描 输 入的算 术 表达 式 ,生 成 表达 式 的二 叉树 ,再 以先序 遍历 此二 叉树 求 取 表达 式的 值 。为 由一 种算 术 表达 式得 出后 缀 、前 缀两种 表达 式提 供 了一种 新 思路 ; 同 时 以更 简便 的方 式实现 了算术 表达 式、二 叉 树 这 两者 之间的转换 。 关键 词 算 术 表 达 式 ;表 达 式树 ;二 叉 树 的 遍 历 ;