中缀表达式表示成二叉树
基于二叉树的表达式求值算法实验报告
基于二叉树的表达式求值算法实验报告一、实验目的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层
1、若层次从1开始,则第i层最多有2 i-1个结点 2、高度为h的二叉树最多有2h -1个结点 3、任何一棵二叉树,若叶子结点数为n0,度为2的结点数 为n2,则n0 = n2 + 1
5.2.2 二叉树的性质
二叉树具有下列重要性质: 性质1: 在二叉树的第i层上至多有2i-1个结点(i>=1)。
二叉树的二叉链表存储表示
Elem val(){return data;} void setVal(const Elem e){data=e;} inline BinTreeNode<Elem>* left(){return lchild;} inline BinTreeNode<Elem>* right(){return rchild;} void setLeft(BinTreeNode<Elem>* left){lchild=left;} void setRight(BinTreeNode<Elem>* right){rchild=right;} bool isLeaf()
Elem data; BinTreeNode * lchild; BinTreeNode * rchild; public:
BinTreeNode(){lchild=rchild=NULL;} BinTreeNode(Elem e,BinNodePtr*l=NULL,
BinNodePtr*r=NULL) {data=e; lchild=l; rchild=r;} ~BinTreeNode(){}
n0,度为2的结点数为n2,则n0=n2+1。
noip第十五届(2009年)信息学奥赛初赛试题答案
第十五届(2009年)信息学奥赛初赛试题答案一.单项选择题(共10题,每题1.5分,共计15分,每题有且仅有一个正确答案。
)1 、关于图灵机下面的说法哪个是正确的:答案(C)A)图灵机是世界上最早的电子计算机。
B)由于大量使用磁带操作,图灵机运行速度很慢。
C)图灵机只是一个理论上的计算模型。
D)图灵机是英国人图灵发明的,在二战中为破译德军的密码发挥了重要作用。
最早的计算机是ENIAC图灵机是计算机模型,没有运行速度,更谈不上磁带操作图灵机是英国人阿兰图灵提出的理论,阿兰图灵本人在二战中破译德军密码系统发挥重要作用,而不是图灵机发挥作用。
图灵是英国著名的数学家和逻辑学家,被称为计算机科学之父、人工智能之父,是计算机逻辑的奠基者,提出了“图灵机”和“图灵测试”等重要概念。
人们为纪念其在计算机领域的卓越贡献而设立“图灵奖”。
1936年,阿兰.图灵提出了一种抽象的计算模型── 图灵机(Turing Machine)。
图灵的基本思想是用机器来模拟人们用纸笔进行数学运算的过程,他把这样的过程看作下列两种简单的动作:在纸上写上或擦除某个符号;把注意力从纸的一个位置移动到另一个位置;“图灵机”不是一种具体的机器,而是一种思想模型,可制造一种十分简单但运算能力极强的计算机装置,用来计算所有能想像得到的可计算函数。
装置由一个控制器和一根假设两端无界的工作带(起存储器的作用)组成。
工作带被划分为大小相同的方格,每一格上可书写一个给定字母表上的符号。
控制器可以在带上左右移动,它带有一个读写出一个你期待的结果。
外行人看了会坠入云里雾里,而内行人则称它是“阐明现代电脑原理的开山之作”,并冠以“理想计算机”的名称。
“图灵机”更在电脑史上与“冯·诺依曼机”齐名,被永远载入计算机的发展史中。
回顾20世纪科学技术的辉煌发展时,不能不提及20世纪最杰出的数学家之一的冯·诺依曼(美籍匈牙利人)。
20世纪40年代,冯·诺依曼在参与世界上第一台计算机-ENIAC的研制小组工作时,发现ENIAC有两个致命的缺陷:一是采用十进制运算,逻辑元件多,结构复杂,可靠性低;二是没有内部存贮器,操纵运算的指令分散存贮在许多电路部件内,这些运算部件如同一副积木,解题时必须像搭积木一样用人工把大量运算部件搭配成各种解题的布局,每算一题都要搭配一次,非常麻烦且费时。
算术表达式(例题)-二叉树
最早提出遍历问题的是对存储在计算机中的表达式求值。
例如:(a+b ×(c-d))-e/f 。
表达式用树形来表示,如图8-11-1所示。
运算符在树中放在非终端结点的位置上,操作数放在叶子结点处。
当我们对此二叉树进行先序、中序和后序遍历后,便可得到表达式的前缀、中缀和后缀书写形式:前缀:-+a*b-cd/ef中缀:a+b*c-d-e/f 后缀:abcd-*+ef/-其中,中缀形式是算术表达式的通常形式,只是没有括号。
在计算机内,使用后缀表达式易于求值。
例1 输入一个算术表达式,判断该表达式是否合法,若不合法,给出错误信息;若合法,则输出合法表达式的表达式树。
【算法分析】表达式不合法有三种情况:①左右括号不匹配;②变量名不合法;③运算符两旁无参与运算的变量或数。
分析表达式树可以看到:表达式的根结点及其子树的根结点为运算符,其在树中的顺序是按运算的先后顺序从后到前,表达树的叶子为参与运算的变量或数。
表达式树如图8-11-2处理时,首先找到运算级别最低的运算符“+”作为根结点,继而确定该根结点的左、右子树结点在表达式串中的范围为a 和(b-c)/d ,再在对应的范围内寻找运算级别最低的运算符作为子树的根结点,直到范围内无运算符,则剩余的变量或数为表达式树的叶子。
【算法步骤】① 设数组ex 存放表达式串的各字符,lt 、rt 作为结点的左右指针,变量left 、right 用于存放每次取字符范围的左、右界。
② 设置左界初值为1;右界初值为串长度。
③ 判断左右括号是否匹配,不匹配则认为输入有错误。
④ 在表达式的左右界范围内寻找运算级别最低的运算符,同时判断运算符两旁有否参与运算的变量或数。
若无,则输入表达式不合法;若有,作为当前子树的根结点,设置左子树指针及其左右界值,设置右子树指针及其左右界值。
⑤ 若表达式在左右界范围内无运算符,则为叶子结点,判断变量名或数是否合法。
⑥ 转④,直到表达式字符取完为止。
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、功能,实现前缀表达式转换为中缀表达式,并进行相应的求值和赋值运算,与及构造复合表达式。
4、测试数据,见输出结果。
二、概要设计:实现该程序所要用到的函数:三、详细设计:见源码:1、Expression.h文件的实现#ifndef _EXPRESSION_H_#define _EXPRESSION_H_//-------------------- 树节点类class TreeNode{public:TreeNode(char _data,TreeNode* _left,TreeNode* _right);~TreeNode();char GetData();void SetData(char _data);void SetLeft(TreeNode* _left);void SetRight(TreeNode* _right);TreeNode* GetLeft();TreeNode* GetRight();private:char Data;TreeNode* left,*right;};//-------------------- 二叉树几及表达式类class BinaryTreeAndExpr{public:BinaryTreeAndExpr();~BinaryTreeAndExpr();TreeNode* GetRoot();void SetRoot(TreeNode* _root);void ReadExpr(char* E);void WriteExpr(char* E);void Assign(char v,int c);static int Value(char* E);static BinaryTreeAndExpr* CompoundExpr(char p,char* E1,char* E2);void Release();private:void ReleaseRecursion(TreeNode* &p);void ReadExprRecursion(TreeNode* &p,char* E);void WriteExprRecursion(TreeNode* p,char* E);void AssignRecursion(TreeNode* p,char v,int c);int ValueRecursion(TreeNode* p);int Priority(char c1,char c2);bool IsOperator(char c);int Evaluation(int a,char op,int b);TreeNode* root;int Expr_i,Expr_len;};#endif2、Expression.cpp文件的实现#include<iostream>#include<cmath>#include"Expression.h"using namespace std;//----------------------树节点类成员函数TreeNode::TreeNode(char _data,TreeNode* _left,TreeNode* _right) {Data=_data;left=_left;right=_right;}TreeNode::~TreeNode(){}char TreeNode::GetData(){return Data;}void TreeNode::SetLeft(TreeNode* _left){left=_left;}void TreeNode::SetRight(TreeNode* _right){right=_right;}TreeNode* TreeNode::GetLeft(){return left;}TreeNode* TreeNode::GetRight(){return right;}void TreeNode::SetData(char _data){Data=_data;}//---------------------------- 二叉树几及表达式类成员函数BinaryTreeAndExpr::BinaryTreeAndExpr():root(NULL){Expr_i=Expr_len=0;}BinaryTreeAndExpr::~BinaryTreeAndExpr(){}void BinaryTreeAndExpr::Release(){if(root!=NULL){ReleaseRecursion(root);delete(root);root=NULL;}}void BinaryTreeAndExpr::ReleaseRecursion(TreeNode* &p) {if(p->GetLeft()!=NULL){TreeNode* p1;p1=p->GetLeft();ReleaseRecursion(p1);delete(p1);}else if(p->GetRight()!=NULL){TreeNode*p2;p2=p->GetRight();ReleaseRecursion(p2);delete(p2);}p=NULL;}TreeNode* BinaryTreeAndExpr::GetRoot(){return root;}void BinaryTreeAndExpr::ReadExpr(char* E){if(root!=NULL) {Release();root=NULL;}Expr_i=0;Expr_len=strlen(E);if(Expr_len==0) return ;ReadExprRecursion(root,E);}void BinaryTreeAndExpr::ReadExprRecursion(TreeNode* &p,char* E) {if(Expr_i==Expr_len)return ;p=(TreeNode*)new TreeNode(E[Expr_i++],NULL,NULL);char temp=p->GetData();if(!IsOperator(temp)) return ;else{TreeNode* q1,* q2;ReadExprRecursion(q1,E);p->SetLeft(q1);ReadExprRecursion(q2,E);p->SetRight(q2);}}void BinaryTreeAndExpr::WriteExpr(char* E){if(root==NULL) {E[0]='\0';return ;}WriteExprRecursion(root,E);}void BinaryTreeAndExpr::WriteExprRecursion(TreeNode* p,char* E) {char c1,c2,c3[100],c4[100];if(p->GetLeft()==NULL || p->GetRight()==NULL){E[0]=p->GetData();E[1]='\0';return ;}c1=p->GetLeft()->GetData();c2=p->GetRight()->GetData();if(!IsOperator(c1) && !IsOperator(c2)){E[0]=c1;E[1]=p->GetData();E[2]=c2;E[3]='\0';}else if(IsOperator(c1) && !IsOperator(c2)){WriteExprRecursion(p->GetLeft(),c3);if(Priority(p->GetData(),p->GetLeft()->GetData())>0){E[0]='(';for(int i=0;i<strlen(c3);i++) E[i+1]=c3[i];E[i+1]=')';E[i+2]=p->GetData();E[i+3]=p->GetRight()->GetData();E[i+4]='\0';}else{for(int i=0;i<strlen(c3);i++) E[i]=c3[i];E[i]=p->GetData();E[i+1]=p->GetRight()->GetData();E[i+2]='\0';}}else if(!IsOperator(c1) && IsOperator(c2)){WriteExprRecursion(p->GetRight(),c3);if(Priority(p->GetData(),p->GetRight()->GetData())>0) {E[0]=p->GetLeft()->GetData();E[1]=p->GetData();E[2]='(';for(int i=0;i<strlen(c3);i++) E[i+3]=c3[i];E[i+3]=')';E[i+4]='\0';}else{E[0]=p->GetLeft()->GetData();E[1]=p->GetData();for(int i=0;i<strlen(c3);i++) E[i+2]=c3[i];E[i+2]='\0';}}else{WriteExprRecursion(p->GetLeft(),c3);WriteExprRecursion(p->GetRight(),c4);if(Priority(p->GetData(),p->GetLeft()->GetData())>0){E[0]='(';for(int i=0;i<strlen(c3);i++) E[i+1]=c3[i];E[i+1]=')';E[i+2]='\0';}else{for(int i=0;i<strlen(c3);i++) E[i]=c3[i];E[i]='\0';}int j=strlen(E);E[j]=p->GetData();if(Priority(p->GetData(),p->GetRight()->GetData())>0){E[j+1]='(';for(int i=0;i<strlen(c4);i++) E[j+2+i]=c4[i];E[j+2+i]=')';E[j+3+i]='\0';}else{for(int i=0;i<strlen(c4);i++) E[j+1+i]=c4[i];E[j+1+i]='\0';}}}int BinaryTreeAndExpr::Priority(char c1,char c2){switch(c1){case '+':case '-':return -1;case '*':switch(c2){case '+':case '-':return 1;}return -1;case '/':switch(c2){case '+':case '-':return 1;}return -1;case '^':return 1;}return 0;}bool BinaryTreeAndExpr::IsOperator(char c){return !(c>=97 && c<=122 || c>=48 && c<=57);}void BinaryTreeAndExpr::Assign(char v,int c){AssignRecursion(root,v,c);}void BinaryTreeAndExpr::AssignRecursion(TreeNode* p,char v,int c){if(p!=NULL){if(p->GetData()==v) p->SetData(c+48);AssignRecursion(p->GetLeft(),v,c);AssignRecursion(p->GetRight(),v,c);}}BinaryTreeAndExpr* BinaryTreeAndExpr::CompoundExpr(char p,char* E1,char* E2){BinaryTreeAndExpr BTAE1,BTAE2,*BTAE3;BTAE1.ReadExpr(E1);BTAE2.ReadExpr(E2);TreeNode* q=(TreeNode*)new TreeNode(p,NULL,NULL);q->SetLeft(BTAE1.GetRoot());q->SetRight(BTAE2.GetRoot());BTAE3=(BinaryTreeAndExpr*)new BinaryTreeAndExpr;BTAE3->SetRoot(q);return BTAE3;}void BinaryTreeAndExpr::SetRoot(TreeNode* _root){root=_root;}int BinaryTreeAndExpr::Value(char* E){BinaryTreeAndExpr btae;btae.ReadExpr(E);return btae.ValueRecursion(btae.GetRoot());}int BinaryTreeAndExpr::ValueRecursion(TreeNode* p){char c1,c2;int temp1,temp2;if(p->GetLeft()==NULL || p->GetRight()==NULL){c1=p->GetData();return (c1>=97 && c1<=122)?0:c1-48;}c1=p->GetLeft()->GetData();c2=p->GetRight()->GetData();if(!IsOperator(c1) && !IsOperator(c2)){if(c1>=97 && c1<=122) temp1=0;else temp1=c1-48;if(c2>=97 && c2<=122) temp2=0;else temp2=c2-48;return Evaluation(temp1,p->GetData(),temp2);}else if(IsOperator(c1) && !IsOperator(c2)){temp1=ValueRecursion(p->GetLeft());if(c2>=97 && c2<=122) temp2=0;else temp2=c2-48;return Evaluation(temp1,p->GetData(),temp2);}else if(!IsOperator(c1) && IsOperator(c2)){temp2=ValueRecursion(p->GetRight());if(c1>=97 && c1<=122) temp1=0;else temp1=c1-48;return Evaluation(temp1,p->GetData(),temp2);}else{temp1=ValueRecursion(p->GetLeft());temp2=ValueRecursion(p->GetRight());return Evaluation(temp1,p->GetData(),temp2);}}int BinaryTreeAndExpr::Evaluation(int a,char op,int b) {switch(op){case '+':return a+b;break;case '-':return a-b;break;case '*':return a*b;break;case '/':return a/b;break;case '^':return pow(a,b);break;}return 0;}3、ExpressionMain.cpp文件的实现#include<iostream>#include"Expression.h"using namespace std;int main(){BinaryTreeAndExpr btae,*btae1;char E1[100],E2[100],P,V;int switchs,c,switchs2;bool run=true,run2=true;while(run){cout<<"请选择功能,功能如下:"<<endl;cout<<"1.构造复合表达试并输出相应结果."<<endl;cout<<"2.输入前缀表达试并构造中缀表达试."<<endl;cout<<"3.对前缀表达试求值."<<endl;cout<<"4.退出."<<endl;cin>>switchs;switch(switchs){case 4:run=false;break;case 1:cout<<"请输入相关数据.前缀表达试"<<endl;getchar();scanf("%s %c %s",E1,&P,E2);btae1=BinaryTreeAndExpr::CompoundExpr(P,E1,E2);while(run2){cout<<"如有变量要赋值请输入1,否则输入2"<<endl;cin>>switchs2;if(switchs2==1){cout<<"请输入相关数据."<<endl;getchar();scanf("%c %d",&V,&c);btae1->Assign(V,c);}else run2=false;}btae1->WriteExpr(E1);cout<<"中缀表达试:"<<E1<<endl;btae1->Release();delete(btae1);run2=true;break;case 2:cout<<"请输入相关数据.前缀表达试"<<endl;cin>>E1;btae.ReadExpr(E1);while(run2){cout<<"如有变量要赋值请输入1,否则输入2"<<endl;cin>>switchs2;if(switchs2==1){cout<<"请输入相关数据."<<endl;getchar();scanf("%c %d",&V,&c);btae.Assign(V,c);}else run2=false;}cout<<"中缀表达试:";btae.WriteExpr(E2);cout<<E2<<endl;run2=true;break;case 3:cout<<"请输入相关数据.前缀表达试"<<endl;cin>>E1;btae.ReadExpr(E1);btae.WriteExpr(E2);cout<<"中缀表达试为:";cout<<E2<<endl;cout<<"计算结果为:";cout<<BinaryTreeAndExpr::Value(E1)<<endl;break;default:cout<<"你的输入无效!请重新输入."<<endl;break;}btae.Release();if(run) cout<<endl;}return 0;}四、调式分析:1、调式时递归函数不正确,出现一些逻辑错误,经改正后最终得到了正确的结果。
数据结构二叉树知识点总结
数据结构二叉树知识点总结二叉树是指每个节点最多有两个子节点的树结构。
它是一种重要的数据结构,在算法和程序设计中被广泛应用。
下面是对二叉树的主要知识点进行详细总结。
1.二叉树的基本概念:-树节点:树的基本单元,包含数据项(节点值)和指向其他节点的指针。
-根节点:树的第一个节点。
-叶节点(又称为终端节点):没有子节点的节点。
-子节点:一些节点的下一级节点。
-父节点:一些节点的上一级节点。
-兄弟节点:拥有同一父节点的节点。
-深度:从根节点到当前节点的路径长度。
-高度:从当前节点到最远叶节点的路径长度。
2.二叉树的分类:-严格二叉树:每个节点要么没有子节点,要么有两个子节点。
-完全二叉树:除了最后一层外,其他层的节点数都达到最大,并且最后一层的节点依次从左到右排列。
-满二叉树:每个节点要么没有子节点,要么有两个子节点,并且所有叶节点都在同一层上。
-平衡二叉树:任意节点的两棵子树的高度差不超过13.二叉树的遍历:-前序遍历:根节点->左子树->右子树。
递归实现时,先访问当前节点,然后递归遍历左子树和右子树。
-中序遍历:左子树->根节点->右子树。
递归实现时,先递归遍历左子树,然后访问当前节点,最后递归遍历右子树。
-后序遍历:左子树->右子树->根节点。
递归实现时,先递归遍历左子树,然后递归遍历右子树,最后访问当前节点。
-层序遍历:从上到下,从左到右依次访问每个节点。
使用队列实现。
4.二叉查找树(BST):-二叉查找树是一种有序的二叉树,对于树中的每个节点,其左子树的节点的值都小于当前节点的值,右子树的节点的值都大于当前节点的值。
-插入操作:从根节点开始,递归地比较要插入的值和当前节点的值,根据比较结果向左或向右移动,直到找到插入位置为止。
-查找操作:从根节点开始,递归地比较要查找的值和当前节点的值,根据比较结果向左或向右移动,直到找到目标节点或到叶节点。
-删除操作:有三种情况:-被删除节点是叶节点:直接将其删除。
数据结构期中考试答案解析
数据结构期中试卷及答案解析考试说明考试说明:考察前五章小题,难度接近真题。
满分100分,共20道选择题,每题5分。
请在60分钟内完成。
C T(n)=n3+5000nD T(n)=2nlogn-1000n参考答案:C本题考察时间复杂度,多个项相加时,只保留最高阶项由于巴啦啦能量——“常<对<幂<指<阶”,因此T(n)=logn+5000n=O(n)T(n)=n2-8000n=O(n2)T(n)=n3+5000n=O(n3)T(n)=2nlogn-1000n=O(nlogn)所以O(n3)复杂度最大,选C。
3.下列叙述中正确的是()①线性表在链式存储时,查找第 i 个元素的时间同 i 的值成正比②线性表在链式存储时,查找第 i 个元素的时间同 i 的值无关③线性表在顺序存储时,查找第 i 个元素的时间同 i 的值成正比A. 仅①B. 仅②C. 仅③D. ①②③参考答案:A线性表在链式存储时,查找第 i 个元素的时间同 i 的值成正比。
线性表在顺序存储时,查找第 i 个元素的时间同 i 的值无关4.若线性表最常用的操作是存取第i个元素及其前驱和后继元素的值,为节省时间应采用的存储方式()。
A. 单链表B. 双向链表C. 单循环链表D. 顺序表参考答案:D注意到,题目要求存取第i个元素及其前驱和后继,ABC三个选项找到第i个元素的时间复杂度均为O(n),而D选项对于这3个位置的存取的时间复杂度均为O(1),故选D。
5.静态链表中next域表示的是()A 下一个元素的地址B 下一个元素的值C 当前元素的值D 下一个元素在数组中的位置参考答案:D静态链表一般保存在数组中,它和链表最大的区别是静态链表占用一段固定的区间,所以next域只需要表示下一个元素在数组中的下标即可而不是表示下一个元素的地址,选D。
6.对于不带头结点的链栈L(next域表示该结点下一个元素),top指针指向栈顶元素(栈顶在链头方向),则x结点进栈操作为A top->next=x;top=x;B top=x;top-next=x;C top=x;x->next=top;D x->next=top;top=x;参考答案:D本题考察链栈的操作x入栈之后x下一个元素为原来的top,所以先把x->next=top,然后更新top,栈顶元素指向x。
习题课-二叉树
数据结构与算法二叉树部分习题讲解齐荣嵘qrr0831@edx二叉树(上)一棵有510个结点的完全二叉树的高度为多少?(独根树高度为1)答案:根据公式log2510+1可以计算出高度为9在一棵非空二叉树中,若度为0的结点的个数n,度为2的结点个数为m,则有n=________答案: m+1Problem3-1•下列关于二叉树性质的说法正确的有:1.非空满二叉树的结点个数一定为奇数个。
√•结点度为0或2的数目相差12.当一棵完全二叉树是满二叉树时,叶子结点不一定集中在最下面一层。
√•倒数第二层的度都为0或者23.一棵非空二叉树的为空的外部结点数目等于其结点数加1。
√•2*n0+n1=n0+n1+n2+14.非完全二叉树也可以用像完全二叉树那样使用顺序存储结构进行存储。
×5.完全二叉树最多只有最下面的一层结点度数可以小于2。
×倒数第二层6.满二叉树的所有结点的度均为2。
×可能为0Problem3-2下列关于二叉树遍历的说法正确的有:1.只有空二叉树和一个根结点的二叉树这两种二叉树的前序和中序遍历的顺序恰好一样。
ו所有结点左子树为空的二叉树也满足要求2.所有结点左子树为空的二叉树的前序和中序遍历顺序恰好一样。
√3.所有结点右子树为空的二叉树的前序和中序遍历顺序恰好一样。
×4.只有空二叉树和一个根结点的二叉树这两种二叉树的前序和后序遍历的顺序恰好一样。
√•前序为中左右,而后序为左右中,所以缺失左子树或者右子树都不能让两者一样。
5.所有结点左子树为空的二叉树的前序和后序遍历顺序恰好一样。
×6.存在一棵非空二叉树,它的前序、中序和后序遍历都是一样的。
√•只有一个根结点的二叉树满足要求。
•已知一棵树的前序遍历为ABDEGCF,中序遍历为DBGEACF,求这棵树的后序遍历。
•答案:DGEBFCA•已知一棵树的中序遍历为DBGEACF,后序遍历为DGEBFCA,求这棵树的前序遍历。
树的类型定义.
对比树型结构和线性结构 的结构特点
线性结构 第一个数据元素 (无前驱) 最后一个数据元素 (无后继) 其它数据元素 (一个前驱、 一个后继)
树型结构 根结点 (无前驱) 多个叶子结点 (无后继) 其它数据元素 (一个前驱、 多个后继)
树的抽象数 据类型定义
数据对象 D
D是具有相同特性的数据 元素的集合
1.若D为空集,则称为空树
数据关系 R
2.在D中存在唯一的称为根的数据元素
root
3.当n>1时,其余结点可分为m (m>0)个
互不相交的有限集T1, T2, …, Tm,其中
每一棵子集本身又是一棵符合本定义
的树,称为根root的子树
基本操作
查 找 类 插 入 类 删 除 类
查找类
Root(T) // 求树的根结点 Value(T, cur_e) // 求当前结点的元素值
data firstchild 1 A -1 4 6
2 5
3
孩子兄弟表示法 root
A B C E F D
B C E F D
A
B
A
C
E D
F
G
G
G
孩子兄弟表示法
data firstChild nextSibling
二叉树的存储结构
一、二叉树的顺 序存储表示 二、二叉树的链 式存储表示
顺序存储表示
有向树
(1) 有确定的根 (2) 树根和子树根之间为有向关系
有序树
子树之间存在确定的次序关系
无序树
子树之间不存在确定的次序关系
结点(node) 结点的度(degree) 分支(branch)结点 叶(leaf)结点 子女(child)结点 双亲(parent)结点
常见基本数据结构——树,二叉树,二叉查找树,AVL树
常见基本数据结构——树,⼆叉树,⼆叉查找树,AVL树常见数据结构——树处理⼤量的数据时,链表的线性时间太慢了,不宜使⽤。
在树的数据结构中,其⼤部分的运⾏时间平均为O(logN)。
并且通过对树结构的修改,我们能够保证它的最坏情形下上述的时间界。
树的定义有很多种⽅式。
定义树的⾃然的⽅式是递归的⽅式。
⼀棵树是⼀些节点的集合,这个集合可以是空集,若⾮空集,则⼀棵树是由根节点r以及0个或多个⾮空⼦树T1,T2,T3,......,Tk组成,这些⼦树中每⼀棵的根都有来⾃根r的⼀条有向的边所连接。
从递归的定义中,我们发现⼀棵树是N个节点和N-1条边组成的,每⼀个节点都有⼀条边连接⽗节点,但是根节点除外。
具有相同⽗亲的节点为兄弟,类似的⽅法可以定义祖⽗和孙⼦的关系。
从节点n1到nk的路径定义为节点n1,n2,...,nk的⼀个序列,并且ni是ni+1的⽗亲。
这个路径的长是路径上的边数,即k-1。
每个节点到⾃⼰有⼀条长为0的路径。
⼀棵树从根到叶⼦节点恰好存在⼀条路径。
对于任意的节点ni,ni的深度为从根到ni的唯⼀路径长。
ni的⾼是从ni到⼀⽚叶⼦的最长路径的长。
因此,所有的树叶的⾼度都是0,⼀棵树的⾼等于它的根节点的⾼。
⼀棵树的深度总是等于它最深叶⼦的深度;该深度等于这棵树的⾼度。
树的实现实现树的⼀种⽅法可以是在每⼀个节点除数据外还要有⼀些指针,使得该节点的每⼀个⼉⼦都有⼀个指针指向它。
但是由于每个节点的⼉⼦树可以变化很⼤⽽且事先不知道,故在各个节点建⽴⼦节点的链接是不可⾏的,这样将会浪费⼤量的空间。
实际的做法很简单:将每个节点的所有⼉⼦都放在树节点的链表中。
下⾯是典型的声明:typedef struct TreeNode *PtrToNodestruct TreeNode{ ElementType Element; PtrToNode FirstChild; PtrToNode NextSibling}下⾯是⼉⼦兄弟表⽰法的图⽰:树的遍历及应⽤⼀个常见的使⽤是操作系统中的⽬录结构。
北京理工大学数据结构实验报告 简易计算器(二叉树)
数据结构实验报告三——简易计算器(二叉树)姓名:任子龙学号:1120140167 班级:05111451一、需求分析(1)问题描述由键盘输入一算术表达式,以中缀形式输入,试编写程序将中缀表达式转换成一棵二叉表达式树,通过对该二叉树的后序遍历求出计算表达式的值。
(2)基本要求a.要求对输入的表达式能判断出是否合法,不合法要有错误提示信息。
b.将中缀表达式转换成二叉表达式树。
c.后序遍历求出表达式的值。
(3)数据结构与算法分析一棵表达式树,它的树叶是操作数,如常量或变量名字,而其他的结点为操作符。
a.建立表达式树。
二叉树的存储可以用顺序存储也可用链式存储。
当要创建二叉树时,先从表达式尾部向前搜索,找到第一个优先级最低的运算符,建立以这个运算符为数据元素的根结点。
注意到表达式中此运算符的左边部分对应的二叉绔为根结点的左子树,右边部分对应的是二叉绔为根结点的右子树,根据地这一点,可用递归调用自己来完成对左右子树的构造。
b.求表达式的值。
求值时同样可以采用递归的思想,对表达式进行后序遍历。
先递归调用自己计算左子树所代表的表达式的值,再递归调用自己计算右子树代表的表达式的值,最后读取根结点中的运算符,以刚才得到的左右子树的结果作为操作数加以计算,得到最终结果。
(4)测试a.加减运算输入:6+9-5 输出:10b.乘除运算输入:5.6*2.7/2 输出:7.56c.四则混合运算输入:(2+3)*8-3/2 输出:23.5d.非法输入输入:(5+6(*5 输出:括号不匹配!1.2问题分析与之前利用栈实现计算器功能不同,本实验采取的方法是:将中缀表达式转换成一棵二叉表达式树,通过对该树的后序遍历求出计算表达式的值。
所以,实验的重点是如何“将中缀表达式转换成一棵二叉表达式树”;如上图所示,该二叉表达式树表示的是计算式(5+2)*3。
可以看出,操作数均为叶子结点,其它结点为操作符;构建二叉树的整体思路是:(1)将中缀表达式转化为后缀表达式;(2)利用(1)中的后缀表达式,在此基础上构建二叉表达式树。
表达式转表达式二叉树
表达式转表达式⼆叉树表达式树⼆叉树是表达式处理的常⽤⼯具,例如,a+b*(c-d)-e/f可以表⽰成如下所⽰的⼆叉树其中,每个⾮叶⼦节点表⽰⼀个运算符,左⼦树是第⼀个运算数对应的表达式,右⼦树是第⼆个表达式对应的表达式。
每个叶⼦节点都是数。
其在空间利⽤上也⾮常⾼效,节点数等于表达式的长度。
表达式转⼆叉树lrj说⽅法有很多种,下⾯介绍他讲的⼀种:找到“最后计算”的运算符(它是整个表达式树的根),然后递归处理左右两边。
1const int maxn = 1000 + 10;2char str[maxn];3int lch[maxn + 1], rch[maxn + 1]; char op[maxn + 1]; //每个结点的左右⼦结点编号和字符4int nc = 0; //结点数5int build_tree(char* s, int x, int y)6{7int i, c1=-1, c2=-1, p=0;8int u;9if(y-x == 1) //仅⼀个字符,建⽴单独结点10 {11 u = ++nc;12 lch[u] = rch[u] = 0;13 op[u] = s[x];14return u;15 }1617for (i = x; i < y; i++) //寻找根节点的位置18 {19switch (s[i])20 {21case'(': p++; break;22case')': p--; break;23case'+':24case'-': if (!p) c1 = i; break;25case'*':26case'/': if (!p) c2 = i; break;27 }28 }29if (c1 < 0) c1 = c2; //找不到括号外的加减号,就⽤乘除号30if(c1 < 0) return build_tree(s, x+1, y-1); //整个表达式被⼀对括号括起来31 u = ++nc;32 lch[u] = build_tree(s, x, c1);33 rch[u] = build_tree(s, c1+1, y);34 op[u] = s[c1];35return u;36 }前缀式、中缀式、后缀式前缀表达式和后缀表达式分别对应表达式树前序和后序遍历的结果,如果不考虑括号,中缀表达式对应表达式树中序遍历的结果。
前中后缀表达式的转化例题
前中后缀表达式的转化例题摘要:1.前中后缀表达式的概念和作用2.前中后缀表达式的转化方法3.例题解析正文:前中后缀表达式是在计算机科学中经常使用的一种表达式形式,它主要用来描述算法的运算过程。
前缀表达式指的是在给定的字符串中,任意一个前缀字符串与后缀字符串的逻辑与结果为真。
中缀表达式指的是在给定的二叉树中,任意一个结点的左子树与右子树的逻辑与结果为真。
后缀表达式指的是在给定的字符串中,任意一个后缀字符串与前缀字符串的逻辑与结果为真。
前中后缀表达式的转化是计算机科学中的一个重要问题。
它可以将一个前缀表达式转换为一个等价的中缀表达式,也可以将一个中缀表达式转换为一个等价的后缀表达式。
具体的转化方法如下:对于前缀表达式到中缀表达式的转化,可以采用栈的方法。
首先,初始化一个空栈,然后遍历前缀表达式中的每一个字符。
如果当前字符为"0",则将其入栈;如果当前字符为"1",则判断栈顶元素是否为"0",如果是,则将栈顶元素弹出并入栈,否则直接弹出栈顶元素。
这样,在遍历完前缀表达式后,栈中存储的就是中缀表达式的二进制表示。
对于中缀表达式到后缀表达式的转化,可以采用递归的方法。
首先,定义一个递归函数,接收两个参数,一个是中缀表达式的二进制表示,另一个是当前正在处理的结点的左子树或右子树。
然后,根据中缀表达式的二进制表示,判断当前结点是左子树还是右子树。
如果是左子树,则递归处理左子树;如果是右子树,则递归处理右子树。
在递归处理结束后,将左子树和右子树的后缀表达式拼接起来,就得到了中缀表达式的后缀表达式。
下面是一个例题的解析:例题:给定前缀表达式"00110011",求其对应的中缀表达式和后缀表达式。
解析:首先,对于前缀表达式到中缀表达式的转化,我们可以按照上述方法进行操作。
初始化一个空栈,然后遍历前缀表达式中的每一个字符。
这样,我们可以得到中缀表达式"00101"。
中缀表达式生成二叉树
中缀表达式⽣成⼆叉树中缀表达式⽣成⼆叉树,⼤概应该有递规,迭代,和编译原理中的⾃顶向下的预测分析法等。
递规,迭代的思路每次读出⼀个数字,⼀个运算符,⽐较当前运算符和之前符号的优先级,进⾏相关的操作。
⾃顶向下的预测分析法,做了下,实在忘记的差不多了,先占个位。
以后完成。
tree.c#include "head.h"struct Node * CreateNodesetV(int number,char opr,int type){struct nodeData db;db.numberValue=number;db.operatorValue=opr;db.symbolType=type;struct Node * myNode=malloc(sizeof(struct Node));CreateNode(db,myNode);return myNode;};void CreateNode(struct nodeData nd,struct Node * myN){myN->NData.numberValue=nd.numberValue;myN->NData.operatorValue=nd.operatorValue;myN->NData.symbolType=nd.symbolType;myN->lchilden='\0';myN->rchilden='\0';};char insertNode(struct Node * myNode,struct Node * father,char lr){char result='Y';if(lr=='L'){if(father->lchilden=='\0'){father->lchilden=myNode;}else{result='N';}}else{if(father->rchilden=='\0'){father->rchilden=myNode;}else{result='N';}}return result;}//原来树的遍历也就是递归.我去,我说⾃⼰怎么⽼是不得要领.根源在于没想明⽩递归函数.void visitTree(struct Node * Root){if(Root->lchilden!='\0'){visitTree(Root->lchilden);}else{//终⽌递归的确定事件,是⽆事件.}if(Root->NData.symbolType==1){printf("%d",Root->NData.numberValue);}else{printf("%c",Root->NData.operatorValue);}if(Root->rchilden!='\0'){visitTree(Root->rchilden);}else{//终⽌递归的确定事件,是⽆事件.}}//所以如果⽤递归来做运算必须是后序遍历,要等左右树都有结果了,才⽤符号。
二叉树求解表达式代码编写 -回复
二叉树求解表达式代码编写-回复如何使用二叉树求解表达式。
引言:在计算机科学中,表达式求解是一项非常基本且重要的任务。
通过将表达式转换为计算机能够理解和处理的形式,我们可以利用计算机来自动求解各种表达式。
在本文中,我们将介绍如何使用二叉树来求解表达式,详细解释每个步骤,并提供相关的代码示例。
一、表达式的构成和表示方法在开始之前,让我们先了解一下表达式的构成和常见的表示方法。
表达式由运算符和操作数组成,运算符用于指定操作数之间的运算关系。
常见的运算符包括加法、减法、乘法、除法等。
表达式通常以中缀表示法展示,即运算符出现在操作数之间。
例如,表达式"3 + 4" 中的运算符是"+",操作数是3 和4。
二、二叉树表示方法为了方便表达式的求解,我们可以将表达式转化为二叉树的形式,其中每个节点都是一个运算符,叶子节点是操作数。
通过遍历二叉树,我们可以按照一定的顺序计算出表达式的值。
具体而言,我们可以使用二叉树的后序遍历(即左子树-右子树-根节点的遍历方式),来求解表达式。
在遍历过程中,如果节点为运算符,则计算其左右子树的值,并根据运算符进行相应的运算。
三、建立二叉树的过程接下来,我们将介绍如何根据表达式构建二叉树。
首先,我们需要定义二叉树的节点结构。
在本例中,节点包含一个运算符和两个指向左右子树的指针。
以下是一个示例的节点结构定义:struct Node {char operator;Node* left;Node* right;};接下来,我们可以使用递归的方式构建二叉树。
具体而言,我们可以从表达式的末尾开始查找运算符,这样我们可以将运算符作为根节点,并将其前面的表达式分割为左右两个子表达式。
例如,对于表达式"3 + 4 * 5",我们可以选择"*" 作为根节点,并将"4" 和"5" 作为其左右子节点。
中序遍历 中缀表达式
中序遍历中缀表达式中序遍历是一种常用的二叉树遍历方法,它按照从左子树、根节点、右子树的顺序进行遍历。
而中缀表达式是表达式中最常见的一种表示方式。
在中缀表达式中,运算符位于操作数的中间。
让我们来思考一下这样一个问:为什么在人们进行运算时,习惯使用中缀表达式呢?我们可以通过分析中序遍历中缀表达式的特点来解答这个问。
在中序遍历中缀表达式中,操作符位于操作数的中间,这种方式使得人们在阅和理解表达式时更加自然和直观。
举个例子,当我们看到"3 + 5" 这样的表达式时,我们很容易就能够理解其中的运算意义。
另一个原因是中缀表达式可以方便地表示复杂的运算优先级。
在中,不同的运算符有不同的优先级,比如乘除法通常比加减法优先计算。
中缀表达式使得这种优先级关系能够清晰地体现出来。
例如,我们可以通过中缀表达式 "3 + 4 * 5" 直观地理解乘法比加法优先计算。
中缀表达式还可以使用括来改变运算的顺序,增加了表达式的灵活性。
括可以用来明确指定哪些运算应该先进行,使得表达式的含义更加明确。
比如,中缀表达式 "3 + 4) * 5" 可以确保加法先于乘法计算。
尽管中缀表达式在人类的中具有优势,但在计算机的计算中却不是最常用的表达式表示方式。
这是因为计算机在执行运算时,更适合使用其他表达式表示方式,比如后缀表达式(也称为逆波兰表达式)或前缀表达式。
这是因为后缀和前缀表达式可以更方便地进行计算机的运算操作。
在这些表达式中,运算符位于操作数的后面或前面,不需要括来换优先级,减少了计算的复杂性。
中序遍历中缀表达式在人们的中具有明显的优势,它使得我们能够直观地理解运算的含义,并能够灵活地表示运算的优先级。
在计算机的计算中,中缀表达式并不是最常用的表示方式,而是使用后缀或前缀表达式。
通过了解不同的表达式表示方式,我们可以更好地理解计算和计算机的运算原理。
中缀表达式转二叉树
中缀表达式转二叉树
从最后被计算的运算符开始,分成三部分
运算符为树根,运算符左边为左子树,右边为右子树
a +
b ∗(
c −
d ) −
e / f
1、从左到右遍历表达式,找到最后计算的字符-
2、分成3部分a+b*(c-d),-,e/f,分别为左子树,根,右子树
3、再继续把每个拆分成三部分,左侧a ,+,b*(c-d);右侧e,/,f
4、继续就这样拆分成三部分,最终得到一棵完整的二叉树
中缀表达式转二叉树就完成了
建完这棵树之后求前缀和后缀表达式就很简单了,分别求它前序遍历和后序遍历
这棵树转中缀表达式只要求中序遍历(注意求的时候如果当前子树优先级比它的父亲低,则在子树外面套一个括号,具体操作自己根据上面那棵树自己模拟)
当用前缀或后缀表达式转二叉树时则更简单,因为根是运算符,接着用普通的前缀后缀表达式转二叉树的方法就可以了。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
将一个中缀表达式表示成二叉树的形式,相关提示如下:(1)基本思路:中缀先转换成后缀,然后再表示成二叉树。
这样做起来要方便的多;(2)打印二叉树时,可以用课件上的逆时针旋转90度打印方式。
#include<iostream>#include<string>#include"d_except.h"using namespace std;#ifndef STACK#define STACKconst MAXSTACKSIZE=50;template<typename T>class stack //有限栈{public:stack();void push(const T& item);void pop();T& top();const T& top() const;bool empty() const;bool full() const;int size() const;private:T stackList[MAXSTACKSIZE];int topIndex;};template <typename T>stack<T>::stack(){topIndex=-1;}template <typename T>void stack<T>::push(const T& item){if(full())throw underflowError("miniStack top():stack empty");//exit(1);topIndex++;stackList[topIndex]=item;}template <typename T>void stack<T>::pop(){if (empty())throw underflowError("miniStack top(): stack empty");topIndex--;}template <typename T>T& stack<T>::top(){if (empty()) throw underflowError("miniStack top(): stack empty");return stackList[topIndex];}template <typename T>const T& stack<T>::top() const{if (empty()) throw underflowError("miniStack top(): stack empty");return stackList[topIndex];}template <typename T>bool stack<T>::empty() const{return topIndex == -1;}template <typename T>bool stack<T>::full() const{return topIndex==MAXSTACKSIZE-1;}template <typename T>int stack<T>::size() const{return topIndex+1;}#endif#include<string>#include"stack.h"using namespace std;class expressionSymbol{public:expressionSymbol();expressionSymbol(char ch);friend bool operator>= (const expressionSymbol& left, const expressionSymbol& right ) {return left.stackPrecedence >= right.inputPrecedence;}char getOp() const;private:char op;int inputPrecedence;int stackPrecedence;};expressionSymbol::expressionSymbol(){}expressionSymbol::expressionSymbol(char ch) { op = ch;switch(op){ case '+':case '-': inputPrecedence = 1;stackPrecedence = 1; break;case '*':case '%':case '/': inputPrecedence = 2;stackPrecedence = 2; break;case '^': inputPrecedence = 4;stackPrecedence = 3; break;case '(': inputPrecedence = 5;stackPrecedence = -1; break;case ')': inputPrecedence = 0;stackPrecedence = 0; break;}}char expressionSymbol::getOp() const{return op;}class infix2Postfix{public:infix2Postfix();infix2Postfix(const string& infixExp);void setInfixExp(const string& infixExp);string postfix();private:string infixExpression;string postfixExpression;stack<expressionSymbol> operatorStack;void outputHigherOrEqual(const expressionSymbol& op);bool isOperator(char ch) const;// ch is one of '+','-','*','/','%','^'};void infix2Postfix::outputHigherOrEqual(const expressionSymbol& op) {expressionSymbol op2;while(!operatorStack.empty() &&(op2 = operatorStack.top()) >= op){operatorStack.pop();postfixExpression += op2.getOp();postfixExpression += ' ';}}bool infix2Postfix::isOperator(char ch) const{return ch == '+' || ch == '-' || ch == '*' ||ch == '%' || ch == '/' || ch == '^';}infix2Postfix::infix2Postfix(){}infix2Postfix::infix2Postfix(const string& infixExp):infixExpression(infixExp){}void infix2Postfix::setInfixExp(const string& infixExp){infixExpression = infixExp;postfixExpression = "";}string infix2Postfix::postfix(){expressionSymbol op;int rank = 0, i;char ch;for (i=0; i < infixExpression.length(); i++){ch = infixExpression[i];if (isdigit(ch)){postfixExpression += ch;// postfixExpression += ' ';rank++;if (rank > 1)throw expressionError("infix2Postfix:Operator expected");}else if (isOperator(ch) || ch == '('){if (ch != '(') rank--;if (rank < 0)throw expressionError("infix2Postfix:Operand expected");else{op = expressionSymbol(ch);outputHigherOrEqual(op);operatorStack.push(op);}}else if (ch == ')'){op = expressionSymbol(ch);outputHigherOrEqual(op);if(operatorStack.empty())throw expressionError("infix2Postfix: Missing '('");elseoperatorStack.pop();}else if (!isspace(ch))throw expressionError("infix2Postfix: Invalid input");}if (rank != 1)throw expressionError("infix2Postfix: Operand expected");else{while (!operatorStack.empty()){op = operatorStack.top();operatorStack.pop();if (op.getOp() == '(')throw expressionError("infix2Postfix: Missing ')'");else{postfixExpression += op.getOp();//postfixExpression += ' ';}}}return postfixExpression;}#include<iostream>#include<iomanip>#include<string>#include"stack.h"using namespace std;class tnode{public:char nodeValue;tnode *left, *right;tnode(){}tnode (const char& item, tnode *lptr = NULL,tnode *rptr = NULL):nodeV alue(item), left(lptr), right(rptr){}tnode* buildtree(string str);int depth(tnode *root);void print(tnode *node_ptr, int depth);};//根据后缀表达式生成二叉树tnode* tnode::buildtree(string n){tnode *ptr;stack<tnode*> nodeStack;char c;int i=0;c=n[i++];while(c!='\0'){//如果不是运算符,则进栈if(c!='+' && c!='-' && c!='*' && c!='/'){ptr=new tnode(c);nodeStack.push(ptr);c=n[i++];}else{ptr=new tnode(c);if(!nodeStack.empty()){ptr->right=nodeStack.top();nodeStack.pop();}if(!nodeStack.empty()){ptr->left=nodeStack.top();nodeStack.pop();}nodeStack.push(ptr);c=n[i++];}}return ptr;}int tnode::depth(tnode *root){int depthval,depthleft,depthright;if(root==NULL)depthval=-1;else{depthleft=depth(root->left);depthright=depth(root->right);depthval=1+(depthleft>depthright?depthleft:depthright);}return depthval;}void tnode::print(tnode *node_ptr, int depth){if (node_ptr != NULL){print(node_ptr->right, depth+1);cout << setw(4*depth) << " ";cout << node_ptr->nodeValue << endl;print(node_ptr->left, depth+1);}}#include<iostream>#include<string>#include"stack.h"#include"expression.h"#include"tree.h"using namespace std;void main(){string p;cout<<"请输入表达式:"<<endl;cin>>p;infix2Postfix A(p);string q=A.postfix();cout<<"后缀表达式为:"<<endl;cout<<q<<endl;cout<< "二叉树为:"<<endl;tnode tree(' ');tnode *root;int depth;root=tree.buildtree(q);depth=tree.depth(root);tree.print(root,depth);}。