c语言实现一.二叉树操作 二.用栈实现算术表达式求值 课设报告
利用二叉树以及栈对算术表达式实现四则运算等计算功能代码

#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;}。
实验:二叉树基本操作的编程实现实验报告

HUBEI UNIVERSITY OF AUTOMOTIVE TECHNOLOGY Array
数据结构
实验五二叉树基本操作的编程实现
【实验目的】
内容:二叉树基本操作的编程实现
要求:
二叉树基本操作的编程实现(2学时,验证型),掌握二叉树的建立、遍历、插入、删除等基本操作的编程实现,也可以进一步编程实现查找等操作,存储结构主要采用顺序或链接结构。
也鼓励学生利用基本操作进行一些应用的程序设计。
【实验性质】
验证性实验(学时数:2H)
【实验内容】
以下的选题都可以作为本次实验的推荐题目
1.建立二叉树,并以前序遍历的方式将结点内容输出。
2.将一个表示二叉树的数组结构转换成链表结构。
3.将表达式二叉树方式存入数组,以递归方式建立表达式之二叉树状结构,再分别输出前序、中序
及后序遍历结果,并计算出表达式之结果。
【注意事项】
1.开发语言:使用C。
2.可以自己增加其他功能。
【实验分析、说明过程】
【思考问题】
【实验小结】 (总结本次实验的重难点及心得、体会、收获)
【附录-实验代码】。
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、依据后缀表达式计算表达式的值
沈阳理工大学
沈阳理工大学课程设计专用纸
c++课程设计报告(二叉树运算)

课程设计报告设计题目:二叉树解决四则运算问题院系:自动化院班级:XXX学号:XXX姓名:XX指导老师:XX时间:XX一.程序功能简介利用二叉树的结构解决带括号的四则运算的问题。
程序利用二叉树的堆栈将二叉树的结点变成结点中的数据时运算符,左右子树是标准结点形式,或是另外的标准二叉树形式,通过后序遍历,经标准结点中的表达式求出。
二.课程设计要求(1)读懂程序,将程序的运算步骤完整的描述出来。
(2)四则运算的表达式可以接受空格输入(3)依照运算顺序依次输出四则运算每一步的算式及及结果,最后输出最终计算结果三.课程设计思想这个课题设计要求最关键的就是读懂程序,用类实现四则运算其实不是很难,只是利用二叉树实现带括号的四则运算有些难度。
初读源程序觉得摸不到头脑,几遍下来还是能够理解的。
在程序中先计算的式子放在栈顶,首先赋值右子树,再赋值左子树,保证优先级。
如图:二叉树类栈运算符栈)—* (+输入“+”,“(”,“*”三个运算符没有优先级冲突,按顺序压栈,然后输入“—”,优先级低于“*”,binary_tree temp_tree; //生成二叉树string thisstring="";thisstring = thisstring + OpStack.top();OpStack.pop() //将栈顶优先级高的运算符移除(即这边的乘号)etree.root = build_node(thisstring);//将优先级高的运算符作为二叉树的根结点copy(temp_tree.root,NodeStack.top().root);//将二叉树堆栈栈顶的二叉树复制到新生成的二叉树中(即把1复制到新的二叉树中)NodeStack.pop();//移除二叉树栈栈顶etree.root->right_child = temp_tree.root;//将二叉树作为新二叉树的右分支temp_tree.root = NULL;copy(temp_tree.root,NodeStack.top().root); //继续将下一个栈顶二叉树复制(即把5复制)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);//优先级低的运算符压栈过程如图:栈顶二叉树temp_tree二叉树Etree二叉树将temp_tree作为etree的右结点新的二叉树类栈最后进行一个遍历,判断运算符栈是否处理完,算出最后结果。
(完整版)C++二叉树基本操作实验报告

一、实验目的选择二叉链式存储结构作为二叉树的存储结构,设计一个程序实现二叉树的基本操作(包括建立、输出、前序遍历、中序遍历、后序遍历、求树高、统计叶子总数等)二、实验开发环境Windows 8.1 中文版Microsoft Visual Studio 6.0三、实验内容程序的菜单功能项如下:1------建立一棵二叉树2------前序遍历递归算法3------前序遍历非递归算法4------中序遍历递归算法5------中序遍历非递归算法6------后序遍历递归算法7------后序遍历非递归算法8------求树高9------求叶子总数10-----输出二叉树11-----退出四、实验分析1、建立一棵二叉树2、输入二叉树各节点数据cout<<"请按正确顺序输入二叉树的数据:";cin.getline(t,1000); //先把输入的数据输入到一个t数组3、递归前序遍历void BL1(ECS_data *t){if(NULL!=t){cout<<t->data<<",";BL1(t->l);BL1(t->r);}}4、非递归前序遍历void preOrder2(ECS_data *t){stack<ECS_data*> s;ECS_data *p=t;while(p!=NULL||!s.empty()){while(p!=NULL){cout<<p->data<<" ";s.push(p);p=p->l;}if(!s.empty()){p=s.top();s.pop();p=p->r;}}}5、递归中序遍历void BL2(ECS_data *t){if(NULL!=t){BL2(t->l);cout<<t->data<<",";BL2(t->r);}}6、非递归中序遍历void inOrder2(ECS_data *t) //非递归中序遍历{stack<ECS_data*> s;ECS_data *p=t;while(p!=NULL||!s.empty()){while(p!=NULL){s.push(p);p=p->l;}if(!s.empty()){p=s.top();cout<<p->data<<" ";s.pop();p=p->r;}}}7、递归后序遍历void BL3(ECS_data *t){if(NULL!=t){BL3(t->l);BL3(t->r);cout<<t->data<<",";}}8、非递归后序遍历void postOrder3(ECS_data *t){stack<ECS_data*> s;ECS_data *cur; //当前结点ECS_data *pre=NULL; //前一次访问的结点s.push(t);while(!s.empty()){cur=s.top();if((cur->l==NULL&&cur->r==NULL)||(pre!=NULL&&(pre==cur->l||pre==cur->r))){cout<<cur->data<<" "; //如果当前结点没有孩子结点或者孩子节点都已被访问过s.pop();pre=cur;}else{if(cur->r!=NULL)s.push(cur->r);if(cur->l!=NULL)s.push(cur->l);}}}9、求树高int Height (ECS_data *t){if(t==NULL) return 0;else{int m = Height ( t->l );int n = Height(t->r);return (m > n) ? (m+1) : (n+1);}}10、求叶子总数int CountLeaf(ECS_data *t){static int LeafNum=0;//叶子初始数目为0,使用静态变量if(t)//树非空{if(t->l==NULL&&t->r==NULL)//为叶子结点LeafNum++;//叶子数目加1else//不为叶子结点{CountLeaf(t->l);//递归统计左子树叶子数目CountLeaf(t->r);//递归统计右子树叶子数目}}return LeafNum;}五、运行结果附:完整程序源代码://二叉树链式存储的实现#include<iostream>#include<cstring>#include <stack>using namespace std;struct ECS_data //先定义好一个数据的结构{char data;ECS_data *l;ECS_data *r;};class ECS{private://int level; //树高int n; //表示有多少个节点数int n1; //表示的是数组的总长度值,(包括#),因为后面要进行删除判断ECS_data *temp[1000];public:ECS_data *root;ECS() //初始化{ECS_data *p;char t[1000];int i;int front=0,rear=1; //front表示有多少个节点,rear表示当前插入的点的父母cout<<"请按正确顺序输入二叉树的数据:";cin.getline(t,1000); //先把输入的数据输入到一个t数组//cout<<t<<" "<<endl;int n1=strlen(t); //测量数据的长度n=0;for(i=0;i<n1;i++){if(t[i]!='#'){p=NULL;if(t[i]!=',') //满足条件并开辟内存{n++;p=new ECS_data;p->data=t[i];p->l=NULL;p->r=NULL;}front++;temp[front]=p;if(1 == front){root=p;}else{if((p!=NULL)&&(0==front%2)){temp[rear]->l=p;//刚开始把这里写成了==}if((p!=NULL)&&(1==front%2)){temp[rear]->r=p;}if(1==front%2)rear++; //就当前的数据找这个数据的父母}}}}~ECS() //释放内存{int i;for(i=1;i<=n;i++)if(temp[i]!=NULL)delete temp[i];}void JS() //记录节点的个数{int s;s=n;cout<<"该二叉树的节点数为:"<<s<<endl;}void BL1(ECS_data *t)//递归前序遍历{if(NULL!=t){cout<<t->data<<",";BL1(t->l);BL1(t->r);}}void preOrder2(ECS_data *t) //非递归前序遍历{stack<ECS_data*> s;ECS_data *p=t;while(p!=NULL||!s.empty()){while(p!=NULL){cout<<p->data<<" ";s.push(p);p=p->l;}if(!s.empty()){p=s.top();s.pop();p=p->r;}}}void BL2(ECS_data *t)//递归中序遍历{if(NULL!=t){BL2(t->l);cout<<t->data<<",";BL2(t->r);}}void inOrder2(ECS_data *t) //非递归中序遍历{stack<ECS_data*> s;ECS_data *p=t;while(p!=NULL||!s.empty()){while(p!=NULL){s.push(p);p=p->l;}if(!s.empty()){p=s.top();cout<<p->data<<" ";s.pop();p=p->r;}}}void BL3(ECS_data *t)//递归后序遍历{if(NULL!=t){BL3(t->l);BL3(t->r);cout<<t->data<<",";}}void postOrder3(ECS_data *t) //非递归后序遍历{stack<ECS_data*> s;ECS_data *cur; //当前结点ECS_data *pre=NULL; //前一次访问的结点s.push(t);while(!s.empty()){cur=s.top();if((cur->l==NULL&&cur->r==NULL)||(pre!=NULL&&(pre==cur->l||pre==cur->r))){cout<<cur->data<<" "; //如果当前结点没有孩子结点或者孩子节点都已被访问过s.pop();pre=cur;}else{if(cur->r!=NULL)s.push(cur->r);if(cur->l!=NULL)s.push(cur->l);}}}int Height (ECS_data *t) //求树高{if(t==NULL) return 0;else{int m = Height ( t->l );int n = Height(t->r);return (m > n) ? (m+1) : (n+1);}}int CountLeaf(ECS_data *t) //求叶子总数{static int LeafNum=0;//叶子初始数目为0,使用静态变量if(t)//树非空{if(t->l==NULL&&t->r==NULL)//为叶子结点LeafNum++;//叶子数目加1else//不为叶子结点{CountLeaf(t->l);//递归统计左子树叶子数目CountLeaf(t->r);//递归统计右子树叶子数目}}return LeafNum;}};int main(){ECS a;a.JS();cout<<"递归前序遍历:";a.BL1(a.root);cout<<endl;cout<<"非递归前序遍历:";a.preOrder2(a.root);cout<<endl;cout<<"递归中序遍历:";a.BL2(a.root);cout<<endl;cout<<"非递归中序遍历:";a.inOrder2(a.root);cout<<endl;cout<<"递归后序遍历:";a.BL3(a.root);cout<<endl;cout<<"非递归后序遍历:";a.postOrder3(a.root);cout<<endl;cout<<"树高为:"<<a.Height(a.root)<<endl;cout<<"叶子总数为:"<<a.CountLeaf(a.root)<<endl;return 0;}。
算术表达式与二叉树课程设计

山西大学课程设计任务书设计题目算术表达式与二叉树所属课程:数据结构系别软件学院专业软件工程班级软工1408班姓名霍志斌指导教师李雪梅设计任务下达日期 2015年 12 月15 日设计时间2016年1月4日至 2016年1月8日目录:一、需求分析二、概要设计1、数据类型的声明:2、表达式的抽象数据类型定义3、整体设计三、详细设计1、二叉树的存储类型2、顺序栈的存储类型3、表达式的基本操作4、主程序和其他伪码算法5、函数的调用关系四、设计和调试分析五、测试六、课程设计的心得和心得以及问题一、需求分析【课程设计要求】【问题的描述】一个表达式和一棵二叉树之间,存在着自然的对应关系。
写一个程序,实现基于二叉树表示的算术表达式Expression的操作。
【基本要求】假设算术表达式Expression内可以含有变量(a-z),常量(0-9)和二元运算符(+,-,*,/,^(乘幂))。
实现以下操作:(1)ReadExpr(E)――以字符序列的形式输入语法正确的前缀表达式并构造表达式E。
(2)WriteExpr(E)――用带括号的中缀表达式输出表达式E。
(3)Assign(V,c)――实现对变量V的赋值(V=c),变量的初值为0。
(4)Value(E)――对算术表达式E求值。
(5)CompoundExpr(p,E1,E2)――构造一个新的复合表达式(E1)p(E2)。
【测试数据】1)分别输入0;a;-91;+a*bc;+*5x2*8x;+++*3^*2^x2x6并输出。
2)每当输入一个表达式后,对其中的变量赋值,然后对表达式求值。
二、概要设计1、数据类型的声明:在这个课程设计中,采用了链表二叉树的存储结构,以及两个顺序栈的辅助存储结构/*头文件以及存储结构*/#include<stdio.h>#include<conio.h>#include<stdlib.h>#include<string.h>#define TRUE 1#define FALSE 0#define OK 1#define ERROR 0#define OVERFLOW 0typedef int Status;2、表达式的抽象数据类型定义ADT Expression{数据对象D:D是具有数值的常量C和没有数值的变量V;数据关系:R={<(V或者C)P(V或者C)>|V,C∈D, <(V或者C)P(V或者C)>表示由运算符P结合起来的表达式E}基本操作:Status Input_Expr(&string,flag)操作结果:以字符序列的形式输入语法正确的前缀表达式,保存到字符串string;参数flag表示输出的提示信息是什么,输入成功返回OK,否则,返回ERROR。
基于二叉树的表达式求值算法实验报告

基于二叉树的表达式求值算法实验报告一、实验目的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.掌握栈在算术表达式的计算方面的应用。
二. 实验内容1. 编写程序利用栈将中缀表达式转换成后缀表达式,即从键盘输入任一个中缀表达式(字符串形式),转换成后缀表达式后,将后缀表达式输出。
假设:中缀表达式包含圆括号( ) 及双目运算符+、-、*、/、^(乘方)。
要求:把栈的基本操作的实现函数存放在头文件stack1.h中(栈元素的类型为char),在主文件test6_2.cpp中包含将中缀表达式S1转换成后缀表达式S2的转换函数void Change( char *S1, char *S2 )及主函数,在主函数中进行输入输出及转换函数的调用。
2. 选做:编写利用栈对后缀表达式进行求值的函数double Compute(char *str),以计算从前述程序得到的后缀表达式的值。
要求:把栈的基本操作的实现函数存放在头文件stack2.h中(栈元素的类型为double),在主文件test6_2.cpp中添加后缀表达式求值函数,并在主函数中增加调用求值函数及输出结果值的语句。
3. 填写实验报告,实验报告文件取名为report2.doc。
4. 上传实验报告文件report2.doc与源程序文件stack1.h、stack2.h(若有)及test6_2.cpp到Ftp服务器上你自己的文件夹下。
二.函数的功能说明及算法思路(算法思路见源程序的注释部分)//栈的顺序存储结构定义struct Stack{ElemType *stack;int top;int MaxSize;};//初始化栈S为空void InitStack(Stack &S)//元素item进栈,即插入到栈顶void Push(Stack &S,ElemType item)//删除栈顶元素并返回ElemType Pop(Stack &S)//读取栈顶元素的值ElemType Peek(Stack &S)//判断S是否为空,若是则返回true,否则返回false bool EmptyStack(Stack &S)//清除栈S中的所有元素,释放动态存储空间void ClearStack(Stack &S)//将中缀算术表达式转换为后缀算术表达式void Change(char *S1,char *&S2)//返回运算符op所对应的优先级数值int Precedence(char op)//计算由str所指字符串的后缀表达式的值double Compute(char *str)四. 实验结果与分析五. 心得体会【附录----源程序】test6_2.cpp#include<iostream.h>#include<stdlib.h>#include<math.h>#include"stack1.h"#include"stack2.h"void main(){char x[30],y[30];double r;while(1){cout<<"请输入一个中缀算术表达式:";cin.getline(x,sizeof(x));Change(x,y);cout<<"对应的后缀算术表达式为:";cout<<y<<endl;r=Compute(y);cout<<"后缀算术表达式值为:"<<r<<endl<<endl;}}stack1.htypedef char ElemType1;struct Stack1{ElemType1 *stack;int top;int MaxSize;};void InitStack(Stack1 &S){S.MaxSize=10;S.stack=new ElemType1[S.MaxSize];if(!S.stack){cerr<<"动态储存分配失败"<<endl;exit(1);}S.top=-1;}void Push(Stack1 &S,ElemType1 item)if(S.top==S.MaxSize-1){int k=sizeof(ElemType1);S.stack=(ElemType1*)realloc(S.stack,2*S.MaxSize*k);S.MaxSize=2*S.MaxSize;}S.top++;S.stack[S.top]=item;}ElemType1 Pop(Stack1 &S){if(S.top==-1){cerr<<"Stack is empty! "<<endl;exit(1);}S.top--;return S.stack[S.top+1];}ElemType1 Peek(Stack1 &S){if(S.top==-1){cerr<<"Stack is empty! "<<endl;exit(1);}return S.stack[S.top];}bool EmptyStack(Stack1 &S){return S.top==-1;}void ClearStack(Stack1 &S){if(S.stack){delete []S.stack;S.stack=0;}S.top=-1;S.MaxSize=0;}//返回运算符op所对应的优先级数值int Precedence(char op){switch(op){case'+':case'-':return 1;case'*':case'/':return 2;case'^':return 3;case'(':case'@':default:return 0;}}//将中缀算术表达式转换为后缀算术表达式void Change(char *S1,char *S2){Stack1 R;InitStack(R);Push(R,'@');int i=0,j=0;char ch=S1[i];while(ch!='\0'){//对于空格字符不做任何处理,顺序读取下一个字符if(ch==' ')ch=S1[++i];//对于左括号,直接进栈else if(ch=='('){Push(R,ch);ch=S1[++i];}//对于右括号,使括号内的仍停留在栈中的运算符依次出栈并写入S2else if(ch==')'){while(Peek(R)!='(')S2[j++]=Pop(R);Pop(R);//删除栈顶的左括号ch=S1[++i];}//对于运算符,使暂存于栈顶且不低于ch优先级的运算符依次出栈并写入S2else if(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='^'){char w=Peek(R);while(Precedence(w)>=Precedence(ch)){S2[j++]=w;Pop(R);w=Peek(R);}Push(R,ch);//把ch运算符写入栈中ch=S1[++i];}else{if((ch<'0'||ch>'9')&&ch!='.'){cout<<"中缀表达式表示错误!"<<endl;exit(1);}while((ch>='0'&&ch<='9')||ch=='.'){S2[j++]=ch;ch=S1[++i];}S2[j++]=' ';}}//把暂存在栈中的运算符依次退栈并写入到S2中ch=Pop(R);while(ch!='@'){if(ch=='('){cerr<<"expression error!"<<endl;exit(1);}else{S2[j++]=ch;ch=Pop(R);}}S2[j++]='\0';}stack2.htypedef double ElemType2;struct Stack2{ElemType2 *stack;int top;int MaxSize;};void InitStack(Stack2 &S){S.MaxSize=10;S.stack=new ElemType2[S.MaxSize];if(!S.stack){cerr<<"动态储存分配失败"<<endl;exit(1);}S.top=-1;}void Push(Stack2 &S,ElemType2 item){if(S.top==S.MaxSize-1){int k=sizeof(ElemType2);S.stack=(ElemType2*)realloc(S.stack,2*S.MaxSize*k);S.MaxSize=2*S.MaxSize;}S.top++;S.stack[S.top]=item;}ElemType2 Pop(Stack2 &S){if(S.top==-1){cerr<<"Stack is empty! "<<endl;exit(1);}S.top--;return S.stack[S.top+1];}ElemType2 Peek(Stack2 &S){if(S.top==-1){cerr<<"Stack is empty! "<<endl;exit(1);}return S.stack[S.top];}bool EmptyStack(Stack2 &S){return S.top==-1;}void ClearStack(Stack2 &S){if(S.stack){delete []S.stack;S.stack=0;}S.top=-1;S.MaxSize=0;}//计算由str所指字符串的后缀表达式的值double Compute(char *str){Stack2 S;InitStack(S);double x,y;int i=0;while(str[i]){if(str[i]==' '){i++;continue;}switch(str[i]){case '+':x=Pop(S)+Pop(S);i++;break;case'-':x=Pop(S);x=Pop(S)-x;i++;break;case'*':x=Pop(S)*Pop(S);i++;break;case'/':x=Pop(S);if(x!=0)x=Pop(S)/x;else{cerr<<"Divide by 0!"<<endl;exit(1);}i++;break;case'^':x=Pop(S);x=pow(Pop(S),x);i++;break;default:x=0;while(str[i]>=48&&str[i]<=57){x=x*10+str[i]-48;i++;}if(str[i]=='.'){i++;y=0;double j=10.0;while(str[i]>=48&&str[i]<=57){y=y+(str[i]-48)/j;i++;j*=10;}x+=y;}}Push(S,x);}if(EmptyStack(S)){cerr<<"expression error!"<<endl;exit(1);}x=Pop(S);if(EmptyStack(S))return x;else{cerr<<"expression error!"<<endl;exit(1);}ClearStack(S);}(注:可编辑下载,若有不当之处,请指正,谢谢!)。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
目录题目一.二叉树操作(1)二.算术表达式求 (1)一、课程设计的目的 (1)二、课程设计的内容和要求 (1)三、题目一设计过程 (2)四、题目二设计过程 (6)五、设计总结 (17)六、参考文献 (18)题目一.二叉树操作(1)二.算术表达式求一、课程设计的目的本学期我们对《数据结构》这门课程进行了学习。
这门课程是一门实践性非常强的课程,为了让大家更好地理解与运用所学知识,提高动手能力,我们进行了此次课程设计实习。
这次课程设计不但要求学生掌握《数据结构》中的各方面知识,还要求学生具备一定的C语言基础和编程能力。
(1)题目一的目的:1、掌握二叉树的概念和性质2、掌握二叉树的存储结构3、掌握二叉树的基本操作(2)题目二的目的:1、掌握栈的顺序存储结构和链式存储结构2、掌握栈的先进后出的特点3、掌握栈的基本运算二、课程设计的内容和要求(1)题目一的内容和要求:1、编写已知二叉树的先序、中序序列,恢复此二叉树的程序2、编写求二叉树深度的程序(2)题目二的内容和要求:1、算术表达式由操作数、运算符和界限符组成。
操作数是正整数,运算符为加减乘除,界限符有左右括号和表达式起始2、将一个表达式的中缀形式转化为相应的后缀形式3、依据后缀表达式计算表达式的值三、题目一设计过程1、题目分析现已知一棵二叉树的先序遍历序列和中序遍历序列,依次从先序遍历序列中取结点,由先序序列确定根结点(就是第一个字母),每次取出一个结点就与中序遍历的序列进行比较,当相等的时候,中序遍历序列就被分成以该结点为根的二叉树子树,该结点左部分为左子树,右部分为右子树,直到取完先序列里的所有结点,则二叉树构造完毕(树用链式存储结构存储),用递归实现!由建好的二叉树,先判断这棵树是否为空,若不为空则找数的左子树,统计它的高度,然后找树的右子树,统计它的高度,比较左子树和右子树的高度,然后返回其中大的那个值加一,则求出数的高度。
这里用递归实现!2、算法描述main ( )(主函数)先构造一颗二叉树,初始化为空,用来存储所构造的二叉树,并输入一棵树的先序序列和中序序列,并统计这个序列的长度。
然后调用实现功能的函数。
void CreateBiTree(BiTree *T,char *pre,char *in,int len)(由先序序列和中序序列构造二叉树)根据前序遍历的特点, 知前序序列(pre)的首个元素(pre[0])为根(root), 然后在中序序列(in)中查找此根(pre[0]), 根据中序遍历特点, 知在查找到的根(root) 前边的序列为左子树, 后边的序列为右子树。
设根前边有n个元素,则又有, 在前序序列中,紧跟着根(root)的n个元素序列(即pre[1...n]) 为左子树, 在后边的为右子树,而构造左子树问题其实跟构造整个二叉树问题一样,只是此时前序序列为pre[1...n]), 中序序列为in[0...n-1], 分别为原序列的子串, 构造右子树同样。
这里用递归实现!int Depth(BiTree T)(求树的深度)当所给的参数T是NULL时,返回0。
说明这个树只有一个叶子节点深度为0,当所给的参数不是NULL时,函数调用自己看看这个参数的左分支是不是NULL,如果不是继续调用自己看看左分支的左分支是不是NULL,直到最后一个的左分支是NULL。
然后看与最后一个左分支并列的右分支是不是NULL,不是的话自动调用自己,直到是NULL。
同理求出右分支,然后左分支深度和右分支深度比较,返回值大的作为深度。
3、源代码#include<stdio.h>#include<malloc.h>typedef struct Node{char data;struct Node *lchild;struct Node *rchild;}*BiTree,BitNode;void InitBitTree(BiTree *T);//初始化一棵树void CreateBiTree(BiTree *T,char *pre,char *in,int len);//由先序序列和中序序列构造二叉树int Depth(BiTree T);//求树的深度void main(){BiTree T;InitBitTree(&T);char a[50],b[50];int i,len=0,j;printf("请输入一棵二叉树的先序序列:");gets(a);printf("请输入一棵二叉树的中序序列:");gets(b);for(i=0;i<50;i++){if(a[i]!='\0')len++;elsebreak;}CreateBiTree(&T,a,b,len);j=Depth(T);printf("这棵树的深度是:%d\n",j);}void InitBitTree(BiTree *T)//初始化一棵树{*T=NULL;}void CreateBiTree(BiTree *T,char *pre,char *in,int len)//由先序序列和中序序列构造二叉树{int k;char *temp;if(len<=0){*T=NULL;return;}*T=(BitNode*)malloc(sizeof(BitNode));(*T)->data=*pre;for(temp=in;temp<in+len;temp++)if(*pre==*temp)break;k=temp-in;CreateBiTree(&((*T)->lchild),pre+1,in,k); //构建左子树CreateBiTree(&((*T)->rchild),pre+1+k,temp+1,len-1-k);//构建右子树}int Depth(BiTree T)//求树的深度{int h,lh,rh;if(T==NULL)h=0;else{lh=Depth(T->lchild);rh=Depth(T->rchild);if(lh>=rh)h=lh+1;elseh=rh+1;}return h;}4、运行结果先输入一棵树的先序遍历序列和中序遍历序列,然后构造出这颗二叉树,并输出这棵树的深度,结果如图:四、题目二设计过程1、题目分析已知输入一个中缀表达式,利用栈(这里用栈的顺序存储结构)的后进先出性,将一个中缀表达式转换成一个后缀表达式,然后同样利用栈的后进先出性,由后缀表达式求出这个表达式的值,并输出。
2、算法描述main ( ) (主函数)在主函数中建立两个数组,一个用来存放中缀表达式,另一个用来存放转换后的后缀表达式,然后调用子函数(其中包括一些栈的基本操作函数),实现函数功能。
void TranslateExpress(char s1[],char s2[])(将中缀表达式转化为后缀表达式)将中缀表达式转换为等价的后缀表达式的过程要使用一个栈放“(”,具体方式如下:(1)从左到右一次扫描中缀表达式的每一个字符,如果是数字字符和圆点“.”则直接将它们写入后缀表达式中。
(2)如果遇到的是开括号“(”,则将它们压入一个操作符栈(不需要与栈顶操作符相比较),它表明一个新的计算层次的开始,在遇到和它匹配的闭括号“)”时,将栈中的元素弹出来并放入后缀表达式中,直到栈顶元素为“(”时,将栈顶元素“(”弹出(不需要加入后缀表达式),表明这一层括号内的操作处理完毕。
(3)如果遇到的是操作符,则将该操作符和操作符栈顶元素比较:1、当所遇到的操作符的优先级小于或等于栈顶元素的优先级时,则取出栈顶元素放入后缀表式,并弹出该栈顶元素,反复执行直到栈顶元素的优先级小于当前操作符的优先级;2、当所遇到的操作符的优先级大于栈顶元素的优先级的时则将它压入栈中。
(4)重复上述步骤直到遇到中缀表达式的结束符标记“#”,弹出栈中的所有元素并放入后缀表达式中,转换结束。
float ComputeExpress(char s[])(计算后缀表达式的值)计算后缀表达式的值,将遇到的操作数暂存于一个操作数栈中,凡是遇到操作数,便从栈中pop(弹出)出两个操作数,并将计算结果存于操作数栈中,直到对后缀表达式中最后一个操作数处理完,最后存入栈中的数就是最后后缀表达式的计算结果。
3、源代码#include<stdio.h>#include<string.h>#include<malloc.h>#include<stdlib.h>#define MaxSize 50typedef struct{float data[MaxSize];int top;}OpStack;typedef struct{char data[MaxSize];int top;}SeqStack;void InitStack(SeqStack *S);//初始化栈int StackEmpty(SeqStack S);//判断栈是否为空int PushStack(SeqStack *S,char e);//进栈int PopStack(SeqStack *S,char *e);//删除栈顶元素int GetTop(SeqStack S,char *e);//取栈顶元素void TranslateExpress(char s1[],char s2[]);//将中缀表达式转化为后缀表达式float ComputeExpress(char s[]);//计算后缀表达式的值void main(){char a[MaxSize],b[MaxSize];float f;printf("请输入一个算术表达式:");gets(a);printf("中缀表达式为:%s\n",a);TranslateExpress(a,b);printf("后缀表达式为:%s\n",b);f=ComputeExpress(b);printf("计算结果:%f\n",f);}void InitStack(SeqStack *S)//初始化栈{S->top=0;}int StackEmpty(SeqStack S)//判断栈是否为空{if(S.top ==0)return 1;elsereturn 0;}int PushStack(SeqStack *S,char e)//进栈{if(S->top>=MaxSize){printf("栈已满,不能进栈!");return 0;}else{S->data[S->top]=e;S->top++;return 1;}}int PopStack(SeqStack *S,char *e)//删除栈顶元素{if(S->top==0){printf("栈已空\n");return 0;}else{S->top--;*e=S->data[S->top];return 1;}}int GetTop(SeqStack S,char *e)//取栈顶元素{if(S.top<=0){printf("栈已空");return 0;}else{*e=S.data[S.top-1];return 1;}}void TranslateExpress(char str[],char exp[])//把中缀表达式转换为后缀表达式{SeqStack S;char ch;char e;int i=0,j=0;InitStack(&S);ch=str[i];i++;while(ch!='\0') //依次扫描中缀表达式{switch(ch){case'(':PushStack(&S,ch);break;case')':while(GetTop(S,&e)&&e!='('){PopStack(&S,&e);exp[j]=e;j++;}PopStack(&S,&e);break;case'+':case'-':while(!StackEmpty(S)&&GetTop(S,&e)&&e!='('){PopStack(&S,&e);exp[j]=e;j++;}PushStack(&S,ch);break;case'*':case'/':while(!StackEmpty(S)&&GetTop(S,&e)&&e=='/'||e=='*') {PopStack(&S,&e);exp[j]=e;j++;}PushStack(&S,ch);break; //是空格就忽略case' ':break;default:while(ch>='0'&&ch<='9'){exp[j]=ch;j++;ch=str[i];i++;}i--;exp[j]=' ';j++;}ch=str[i];i++;}while(!StackEmpty(S)) //将栈中剩余运算符出栈{PopStack(&S,&e);exp[j]=e;j++;}exp[j]='\0';}float ComputeExpress(char a[])//计算后缀表达式的值{OpStack S;int i=0;float x1,x2,value;float result;S.top=-1;while(a[i]!='\0') //依次扫描后缀表达式{if(a[i]!=' '&&a[i]>='0'&&a[i]<='9')//如果是数字{value=0;while(a[i]!=' ') //如果不是空格{value=10*value+a[i]-'0';i++;}S.top++;S.data[S.top]=value; //处理后进栈}else //如果是运算符{switch(a[i]){case'+':x1=S.data[S.top];S.top--;x2=S.data[S.top];S.top--;result=x1+x2;S.top++;S.data[S.top]=result;break;case'-':x1=S.data[S.top];S.top--;x2=S.data[S.top];S.top--;result=x2-x1;S.top++;S.data[S.top]=result;break;case'*':x1=S.data[S.top];S.top--;x2=S.data[S.top];S.top--;result=x1*x2;S.top++;S.data[S.top]=result;break;case'/':x1=S.data[S.top];S.top--;x2=S.data[S.top];S.top--;result=x2/x1;S.top++;S.data[S.top]=result;break;}i++;}}if(!S.top!=-1) //如果栈不空,将结果出栈并返回{result=S.data[S.top];S.top--;if(S.top==-1)return result;else{printf("表达式错误");exit(-1);}}return 0;}4、运行结果输入一个算术表达式,然后输出这个表达式(中缀),转换为后缀表达式,输出转换后的后缀表达式,根据后缀表达式计算出表达式的值,并输出,结果如图:五、设计总结通过这次课设我学会了许多东西,同时也遇到了许多问题。