c语言实现一.二叉树操作 二.用栈实现算术表达式求值 课设报告
- 格式:doc
- 大小:114.50 KB
- 文档页数:19
#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.可以自己增加其他功能。
【实验分析、说明过程】
【思考问题】
【实验小结】 (总结本次实验的重难点及心得、体会、收获)
【附录-实验代码】。
课程设计报告设计题目:二叉树解决四则运算问题院系:自动化院班级: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的右结点新的二叉树类栈最后进行一个遍历,判断运算符栈是否处理完,算出最后结果。
一、实验目的选择二叉链式存储结构作为二叉树的存储结构,设计一个程序实现二叉树的基本操作(包括建立、输出、前序遍历、中序遍历、后序遍历、求树高、统计叶子总数等)二、实验开发环境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、分析、理解程序程序的功能是采用二叉树链表存储结构,完成二叉树的建立,先序、中序和后序以及按层次遍历的操作。
如输入二叉树ABD###CE##F##,链表示意图如下:2、添加中序和后序遍历算法//========LNR 中序遍历===============void Inorder(BinTree T){if(T){Inorder(T->lchild);printf("%c",T->data);Inorder(T->rchild);}}//==========LRN 后序遍历============void Postorder(BinTree T){if(T){Postorder(T->lchild);Postorder(T->rchild);printf("%c",T->data);}}3、调试程序,设计一棵二叉树,输入完全二叉树的先序序列,用#代表虚结点(空指针),如ABD###CE##F##,建立二叉树,求出先序、中序和后序以及按层次遍历序列,求所有叶子及结点总数。
(1)输入完全二叉树的先序序列ABD###CE##F##,程序运行结果如下:(2)先序序列:(3)中序序列:(4)后序序列:(5)所有叶子及结点总数:(6)按层次遍历序列:四、源程序代码#include"stdio.h"#include"string.h"#include"stdlib.h"#define Max 20 //结点的最大个数typedef struct node{char data;struct node *lchild,*rchild;}BinTNode; //自定义二叉树的结点类型typedef BinTNode *BinTree; //定义二叉树的指针int NodeNum,leaf; //NodeNum为结点数,leaf为叶子数//==========基于先序遍历算法创建二叉树==============//=====要求输入先序序列,其中加入虚结点"#"以示空指针的位置========== BinTree CreatBinTree(void){BinTree T;char ch;if((ch=getchar())=='#')return(NULL); //读入#,返回空指针else{T=(BinTNode *)malloc(sizeof(BinTNode)); //生成结点T->data=ch;T->lchild=CreatBinTree(); //构造左子树T->rchild=CreatBinTree(); //构造右子树return(T);}}//========NLR 先序遍历=============void Preorder(BinTree T){if(T) {printf("%c",T->data); //访问结点Preorder(T->lchild); //先序遍历左子树Preorder(T->rchild); //先序遍历右子树}}//========LNR 中序遍历===============void Inorder(BinTree T){if(T){Inorder(T->lchild);printf("%c",T->data);Inorder(T->rchild);}}//==========LRN 后序遍历============void Postorder(BinTree T){if(T){Postorder(T->lchild);Postorder(T->rchild);printf("%c",T->data);}}//=====采用后序遍历求二叉树的深度、结点数及叶子数的递归算法======== int TreeDepth(BinTree T){int hl,hr,max;if(T){hl=TreeDepth(T->lchild); //求左深度hr=TreeDepth(T->rchild); //求右深度max=hl>hr? hl:hr; //取左右深度的最大值NodeNum=NodeNum+1; //求结点数if(hl==0&&hr==0) leaf=leaf+1; //若左右深度为0,即为叶子。
一、实验目的选择二叉链式存储结构作为二叉树的存储结构,设计一个程序实现二叉树的基本操作(包括建立、输出、前序遍历、中序遍历、后序遍历、求树高、统计叶子总数等)二、实验开发环境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;}。
二叉树的基本操作与实现实验报告二叉树是一种重要的数据结构,在计算机科学领域中被广泛应用。
本实验将介绍二叉树的基本操作与实现,并给出相应的实验报告。
一、引言二叉树是一种特殊的树状结构,每个节点至多有两个子节点。
二叉树有许多重要的特性,如平衡二叉树、二叉树等,应用广泛。
在本实验中,我们将介绍二叉树的基本操作和实现。
二、实验目的1.掌握二叉树的基本概念和特性;2.熟悉二叉树的基本操作,包括创建、插入、删除、遍历等;3.学会使用编程语言实现二叉树的基本操作。
三、实验内容本实验主要包括以下内容:1.二叉树的定义和基本概念;2.二叉树的基本操作,包括创建、插入、删除、遍历等;3.使用编程语言实现二叉树的基本操作;4.测试和验证二叉树的基本操作的正确性。
四、实验步骤1.二叉树的定义和基本概念二叉树是一种树状结构,每个节点至多有两个子节点。
二叉树的每个节点包含一个数据项和指向左子树和右子树的指针。
二叉树的特性有很多,如完全二叉树、平衡二叉树、二叉树等。
2.二叉树的基本操作(1)创建二叉树:可以通过手动输入节点数据来创建二叉树,也可以通过读取文件中的数据来创建二叉树。
(2)插入节点:在指定位置插入一个新节点。
(3)删除节点:删除指定位置的节点。
(4)遍历二叉树:有前序遍历、中序遍历和后序遍历三种遍历方式。
3.使用编程语言实现二叉树的基本操作实现二叉树的基本操作可以使用编程语言来完成。
我们可以定义一个二叉树的结构体,包含节点数据和指向左右子树的指针。
然后根据具体的需求,实现相应的操作函数。
4.测试和验证二叉树的基本操作的正确性在完成二叉树的基本操作后,我们可以编写测试代码来验证操作的正确性。
通过创建二叉树,并进行插入、删除和遍历操作,观察输出结果是否符合预期。
五、实验结果与分析在完成二叉树的基本操作后,我们可以进行测试和验证。
通过输出二叉树的遍历结果,比对预期结果来判断操作是否正确。
同时,我们还可以观察二叉树的结构和特性,如是否满足平衡二叉树或二叉树的条件。
栈是一种常见的数据结构,用于解决许多算法和数据处理问题。
在编程中,栈通常用于处理表达式求值问题。
本篇文章将介绍如何使用栈解决表达式求值问题,并给出对应的C语言代码。
1. 表达式求值问题介绍表达式求值是指计算一个数学表达式的值,通常涉及到四则运算、括号和优先级等概念。
给定一个表达式“3 + 4 * 2”,我们需要得到其计算结果为11。
在编程中,需要将该表达式转换为计算机可识别的形式,并使用算法进行求值。
2. 中缀表达式、前缀表达式和后缀表达式在计算机中常见的表达式有三种形式:中缀表达式、前缀表达式和后缀表达式。
其中,中缀表达式是通常人们在日常生活中使用的表达式形式,如“3 + 4 * 2”。
前缀表达式是运算符位于操作数之前的形式,例如“+ 3 * 4 2”。
后缀表达式则是运算符位于操作数之后的形式,例如“3 4 2 * +”。
3. 使用栈解决表达式求值问题在解决表达式求值问题时,我们可以利用栈的特性来简化计算过程。
具体步骤如下:3.1 将中缀表达式转换为后缀表达式我们需要将中缀表达式转换为后缀表达式,这样可以简化表达式的计算顺序。
具体转换规则如下:- 从左至右扫描中缀表达式的每个数字或符号。
- 如果是操作数,则直接输出。
- 如果是运算符,则弹出栈中所有优先级大于或等于该运算符的运算符,并将其压入栈中,然后压入该运算符。
- 如果是括号,则根据括号的不同情况进行处理。
通过以上规则,我们可以将中缀表达式转换为后缀表达式。
3.2 计算后缀表达式的值得到后缀表达式后,我们可以利用栈来计算其值。
具体步骤如下:- 从左至右扫描后缀表达式的每个数字或符号。
- 如果是操作数,则压入栈中。
- 如果是运算符,则弹出栈中的两个操作数进行相应的运算,并将结果压入栈中。
- 继续扫描直到表达式结束,栈中的值即为所求结果。
通过以上步骤,我们可以使用栈来解决表达式求值问题。
4. C语言代码实现以下是使用C语言实现栈来解决表达式求值问题的代码示例:```c#include <stdio.h>#include <stdlib.h>#include <string.h>typedef struct {int top;int capacity;int* array;} Stack;Stack* createStack(int capacity) {Stack* stack = (Stack*)malloc(sizeof(Stack));stack->capacity = capacity;stack->top = -1;stack->array = (int*)malloc(stack->capacity * sizeof(int)); return stack;}int isFull(Stack* stack) {return stack->top == stack->capacity - 1; }int isEmpty(Stack* stack) {return stack->top == -1;}void push(Stack* stack, int item) {if (isFull(stack)) return;stack->array[++stack->top] = item;}int pop(Stack* stack) {if (isEmpty(stack)) return -1;return stack->array[stack->top--];}int evaluatePostfix(char* exp) {Stack* stack = createStack(strlen(exp)); for (int i = 0; exp[i]; i++) {if (isdigit(exp[i])) {push(stack, exp[i] - '0');} else {int val1 = pop(stack);int val2 = pop(stack);switch (exp[i]) {case '+':push(stack, val2 + val1); break;case '-':push(stack, val2 - val1); break;case '*':push(stack, val2 * val1); break;case '/':push(stack, val2 / val1); break;}}}return pop(stack);}int m本人n() {char exp[] = "34*2+";printf("The value of s is d\n", exp, evaluatePostfix(exp));return 0;}```以上代码实现了栈的基本功能,并利用栈来计算后缀表达式的值。
c语言二叉树实验报告一、实验目的本次实验的目的是通过使用C语言编写程序,实现二叉树的基本操作,包括创建二叉树、插入节点、删除节点、遍历等功能。
通过这些操作,加深对数据结构和算法的理解,提高编程能力。
二、实验环境1. 操作系统:Windows 102. 开发工具:Code::Blocks 20.033. 编程语言:C语言三、实验过程及结果1. 创建二叉树在程序中定义了一个结构体来表示二叉树节点:```typedef struct Node {int data; // 节点数据struct Node *left; // 左子节点指针struct Node *right; // 右子节点指针} Node;```创建一个新节点的函数为:```Node *create_node(int data) {Node *node = (Node*)malloc(sizeof(Node)); node->data = data;node->left = NULL;node->right = NULL;return node;}```通过递归方式创建一棵二叉树:```Node *create_tree() {int data;scanf("%d", &data);if (data == -1) {return NULL;}Node *node = create_node(data);node->left = create_tree();node->right = create_tree();return node;}2. 插入节点插入节点需要先找到要插入位置的父节点,然后根据插入位置是左子节点还是右子节点,将新节点插入到相应的位置:```void insert_node(Node *root, int data) {Node *node = create_node(data);Node *parent = NULL;Node *current = root;while (current != NULL) {parent = current;if (data < current->data) {current = current->left;} else {current = current->right;}}if (data < parent->data) {parent->left = node;} else {parent->right = node;}```3. 删除节点删除节点需要先找到要删除的节点,然后根据其子节点的情况进行删除操作:```Node *delete_node(Node *root, int data) {if (root == NULL) {return root;}if (data < root->data) {root->left = delete_node(root->left, data);} else if (data > root->data) {root->right = delete_node(root->right, data);} else { // 找到要删除的节点if (root->left == NULL && root->right == NULL) { // 没有子节点free(root);return NULL;} else if (root->left == NULL || root->right == NULL) { // 只有一个子节点Node *temp;if (root->left != NULL) {temp = root->left;} else {temp = root->right;}free(root);return temp;} else { // 有两个子节点Node *temp = root->right;while (temp->left != NULL) {temp = temp->left;}root->data = temp->data;root->right = delete_node(root->right, temp->data); }}return root;}```4. 遍历二叉树遍历二叉树有三种方式:前序遍历、中序遍历和后序遍历。
二叉树实验报告总结(共10篇)二叉树实验报告实验报告课程名称算法与数据结构专业学号姓名实验日期算法与数据结构实验报告一、实验目的1.了解二叉树的结构特点及有关概念,掌握二叉树建立的基本算法2.了解二叉树遍历的概念,掌握遍历二叉的算法3.进一步掌握树的结构及非线性特点,递归特点和动态性。
二、实验内容二叉树的实现和运算三、实验要求1.用C++/C完成算法设计和程序设计并上机调试通过。
2.撰写实验报告,提供实验结果和数据。
3.分析算法,并简要给出算法设计小结和心得。
四、算法步骤用户以三元组形式输入二叉树的结点元素及其位置关系,建立二叉树,并打印输出该二叉树。
用户输入选择结点,程序调用BiTNode* Find Node(char tag, BiTNode* node)函数,返回子树的根结点,然后调用BiTreeDepth(BiTree T)函数,求出子树的深度,并输出该值。
3.用户可以选择是否继续执行程序,若继续,则输入1,否则输入0,结束程序。
五、主程序代码:int main(void){BiTree T;TElemType e1;char node; // node为用户选择输入的结点//int b,choose; // b为以选定结点为子树的深度,choose为实现多次选择输入的标志//BiTNode* a; // a为选定结点为子树的根结点//choose=1; // 多次选择的标志,当choose为1时运行程序,为0时结束程序// InitBiTree(T);printf(构造空二叉树后,树空否?%d(1:是0:否), 树的深度=%d\n,BiTreeEmpty(T),BiTreeDepth(T));e1 = Root(T);if(e1 != Nil)#ifdef CHARprintf(二叉树的根为: %c\n,e1);#endif#ifdef INTprintf(二叉树的根为: %d\n,e1);#endifelseprintf(树空,无根\n); //三元组构建二叉树striile(x!=end){AddNode(T, x[0], x[1], x[2]);GetUserWord(x);} //输出树PrintTreeLevel( T );//以三元组形式输入任意二叉树(以大写字母表示结点),求以任意一选定结点为子树的深度。
二叉树操作课程设计报告一、总体设计1、程序功能简介带枚举值的二叉树的实现,利用枚举值使二叉树的组成尽量平衡,即左右子树的级数相差不多。
可以完成二叉树结点数据的插入、删除、查找和输出等功能。
2、程序设计要求(1)仔细阅读程序,回答下列问题a.枚举值Red和Black在程序中起什么作用,Red的结点和Black的结点有什么区别?b.一个结点的左右子树最多可以相差几级?为什么?c.程序是通过哪些函数来调整二叉树左右子树的结构,举例说明如何调整。
(2)增加对二叉树上结点中的数据进行由大到小排序的函数。
(3)增加对二叉树上结点中的数据进行由小到大排序的函数。
(4)增加计算二叉树中结点上数据的平均值的函数。
(5)修改main函数,增加菜单选项,使得用户可以通过键盘反复输入命令或数值查看运行结果。
评定难易等级:A级二、详细设计1、对二叉树的初步了解(1)本题中的二叉树是一颗二叉查找树,首先应具有二叉查找树的特征。
它或者是一棵空树;或者是具有下列性质的二叉树:若左子树不空,则左子树上所有结点的值均小于它的根结点的值;若右子树不空,则右子树上所有结点的值均大于它的根结点的值;左、右子树也分别为二叉排序树。
且结点上数据互不相同。
如图所示:(2)本题中的二叉树同时为平衡二叉树中的一类——红黑树,因此它具有红黑树的特征。
红黑树是每个节点都带有颜色属性的二叉查找树,颜色或红色或黑色。
在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:性质1. 节点是红色或黑色。
性质2. 根节点是黑色。
性质3 每个叶节点是黑色的。
性质4 每个红色节点的两个子节点都是黑色。
(从每个叶子到根的所有路径上不能有两个连续的红色节点)性质5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
这些约束强制了红黑树的关键性质: 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。
要知道为什么这些特性确保了这个结果,注意到性质4导致了路径不能有两个毗连的红色节点就足够了。
实验报告姓名:黄雄镖学号:13331093院系专业:软件学院2013级教务4班完成日期:2014 年10 月20 日实验题目:实现一个较为通用的计算器需求分析:实现一个包含加减乘除运算的较为通用的计算器,操作数可能是负数,并且可能是多位数。
运算式中可以有括号和多余空格。
计算器对负号不敏感, 形如1+-1或者1+(-1)都是可以接受的。
概要设计思路: 将表达式的中缀表达式转换成后缀表达式,然后利用一个栈或者建立二叉树对后缀表达式进行求值。
由于多位数在转为后缀表达式时会分不清, 故在每个数和运算符后面加上一个空格作为区别在主程序中调用用栈求值的计算器类和用二叉树计算的计算器类, 输出算式的结果13331093_03.h里存放用栈求值的计算器类13331093_03_tree.h里存放用二叉树计算的计算器类13331093_03.h的类里主要包括:获得算术表达式的函数getexpression(string expression), expression为所要计算的算术表达式计算函数calculate(string num2, string num1, string op), 输入为两个数(字符串形式)和一个操作符, 返回值为计算结果(字符串形式)返回中缀表达式函数ShowMiddleExpression(), 返回的中缀表达式为字符串形式RidSpace(string origin)用于去除输入中多余的空格, 输入为要除去空格的算术表达式, 返回去掉空格的算术表达式MidToLast(string str)中缀表达式转后缀表达式获得后缀表达式函数GetLastExpression(), 返回的后缀表达式为字符串形式用栈执行计算后缀表达式函数exe(), 返回计算结果为字符串形式13331093_03_tree.h类里主要包括:获得算术表达式的函数getexpression(string expression), expression为所要计算的算术表达式计算函数calculate(string num2, string num1, string op), 输入为两个数(字符串形式)和一个操作符, 返回值为计算结果(字符串形式)返回中缀表达式函数ShowMiddleExpression(), 返回的中缀表达式为字符串形式RidSpace(string origin)用于去除输入中多余的空格, 输入为要除去空格的算术表达式, 返回去掉空格的算术表达式MidToLast(string str)中缀表达式转后缀表达式获得后缀表达式函数GetLastExpression(), 返回的后缀表达式为字符串形式生成一颗二叉树的函数makeTree(TNode *&p)后序遍历二叉树并计算的函数PostOrder(TNode *p), 返回计算结果为字符串形式a.调试过程遇到的问题与解决方案:遇到的问题:调试过程中出现程序崩溃的现象, 后来debug发现是没有考虑到执行运算过程中出现的-()的情况原因:没有考虑-()的情况, 导致栈为空的时候还弹出元素解决方案:特殊处理这种情况b.时间和空间复杂度:除去输入中空格的操作的时间复杂度为O(n),中缀表达式转后缀表达式的时间复杂度为O(n), 用栈执行运算的时间复杂度为O(n),后序遍历二叉树的时间复杂度为O(n) 所以用栈计算或者用二叉树计算的操作的时间复杂度为都是O(n)栈属于线性表, 故用栈计算的空间复杂度为O(n)用二叉树计算的空间复杂度也是O(n)主程序:输入一个整数m,代表有m个输入接下来有m行,每一行输入你要计算的式子13331093_03.h:含有用stack计算的计算器类用法:calculator c_stack 声明一个计算器对象c_stack.getexpression(expression) 把算术表达式存入计算器中expression为所要计算的算术表达式c_stack.GetLastExpression() 获取算术表达式的后缀表达式c_stack.exe() 获取计算结果13331093_03_tree.h:含有用二叉树计算的计算器类用法:calculator_tree c_tree 声明一个计算器对象c_tree.getexpression(expression) 把算术表达式存入计算器中expression为所要计算的算术表达式c_tree.GetLastExpression() 获取算术表达式的后缀表达式c_tree.makeTree(tree) 建立一棵二叉树c_tree.PostOrder(tree) 后序遍历二叉树并返回计算结果测试结果在主程序中调用用栈求值的计算器类和用二叉树计算的计算器类, 并对输入表达式进行两种方法所生成的后缀表达式和结果的对比测试代码在test.cpp中测试输入:11-(12.34)-11+-21+(-2)11 + 23 * 32/4-8-1.234/5 *(1 +3)2.333*4-(3+(-5))12345+5432.1/(-12345)-(100 ) * 0.5 -(-22.22)1234/-123+3.333-( 123*50 ) / 2.2测试结果如下:另外我用计算器算过, 结果是正确的实验心得通过这次实验, 我对栈和二叉树的理解加深了很多。
C语言二叉树实验报告摘要本实验报告旨在详细介绍C语言中二叉树的实现方法,并深入探讨二叉树在计算机科学中的应用。
报告内容包括二叉树的定义、创建与遍历方法、二叉树的特性、二叉树的应用领域等方面的内容。
通过对二叉树的学习和实践,我们可以加深对数据结构的理解和应用能力。
1. 引言在计算机科学中,二叉树是一种重要的数据结构,被广泛应用于各种算法和实际问题的解决。
二叉树由节点组成,每个节点最多有两个子节点,分别为左子节点和右子节点。
本实验旨在通过使用C语言来实现二叉树,加深对二叉树的理解和运用能力。
2. 二叉树的定义与创建2.1 二叉树的定义二叉树是一种树形数据结构,在计算机科学中具有广泛的应用。
二叉树由节点组成,每个节点最多有两个子节点,分别为左子节点和右子节点。
根节点是二叉树的起点,也是唯一没有父节点的节点。
2.2 创建二叉树可以通过以下步骤创建一个二叉树:1.定义二叉树的节点结构,包括数据域和左右子节点指针域。
2.使用动态内存分配函数malloc为根节点分配内存空间。
3.输入根节点的值,并将左右子节点指针指向NULL。
4.递归地创建左子树和右子树。
3. 二叉树的遍历方法二叉树的遍历是指以某种顺序访问二叉树中的节点,可以分为前序遍历、中序遍历和后序遍历三种方式。
3.1 前序遍历前序遍历是指先访问根节点,然后递归地遍历左子树和右子树。
在前序遍历中,根节点总是最先被访问。
算法的伪代码如下所示:preorderTraversal(node) {if (node is not NULL) {print node.valuepreorderTraversal(node.left)preorderTraversal(node.right)}}3.2 中序遍历中序遍历是指先递归地遍历左子树,然后访问根节点,最后再递归地遍历右子树。
在中序遍历中,根节点总是被访问在中间位置。
算法的伪代码如下所示:inorderTraversal(node) {if (node is not NULL) {inorderTraversal(node.left)print node.valueinorderTraversal(node.right)}}3.3 后序遍历后序遍历是指先递归地遍历左子树和右子树,最后访问根节点。
一、概述在计算机科学中,栈是一种非常重要的数据结构,它具有“先进后出”的特点,能够很好地辅助实现算法和表达式的求值。
在C语言中,我们可以借助栈这种数据结构来完成对运算表达式的求值,从而实现计算功能。
本文将介绍如何在C语言中利用栈完成运算表达式的求值。
二、栈的基本概念1. 栈的定义栈是一种线性结构,它具有两个基本的操作:入栈(push)和出栈(pop)。
栈的特点是只允许在栈顶进行操作,即每次只能操作最后一个插入到栈中的元素。
这种先进后出的结构使得栈非常适合用来处理递归、表达式求值等问题。
2. 栈的实现在C语言中,我们可以通过数组或链表来实现栈。
数组实现的栈叫做顺序栈,链表实现的栈叫做链式栈。
对于运算表达式的求值来说,我们可以选择数组来实现栈。
栈的结构可以定义如下:```c#define MAX_SIZE 100typedef struct {int data[MAX_SIZE];int top;} Stack;```这样我们就定义了一个包含数组和栈顶指针的栈结构类型。
三、运算表达式的求值1. 中缀表达式在数学中,我们通常使用中缀表达式来表示运算式,例如:1 + 2 * 3。
这种表达式的书写方式是运算符位于操作数之间。
在计算机中,中缀表达式不太方便进行求值,因此我们需要将中缀表达式转换为后缀表达式来进行计算。
2. 后缀表达式后缀表达式又称为逆波兰表达式,它的特点是运算符位于操作数之后,比如:1 2 3 * +。
后缀表达式的求值非常简单,只需要从左到右遍历表达式,遇到操作数就入栈,遇到运算符就弹出栈顶的两个操作数进行运算,然后将结果再入栈,直到表达式结束。
3. 栈完成后缀表达式的求值我们可以利用栈来完成后缀表达式的求值。
具体步骤如下:(1)创建一个空栈(2)从左到右遍历后缀表达式(3)如果遇到操作数,则入栈(4)如果遇到运算符,则弹出栈顶的两个操作数进行运算,然后将结果入栈(5)遍历结束后,栈中剩下的元素就是表达式的值四、示例代码下面是一个简单的示例代码,演示了如何利用栈完成后缀表达式的求值:```c#include <stdio.h>#define MAX_SIZE 100typedef struct {int data[MAX_SIZE];int top;} Stack;void initStack(Stack *s) {s->top = -1;}void push(Stack *s, int value) { if (s->top < MAX_SIZE - 1) { s->data[++s->top] = value; } else {printf("Stack is full\n");}}int pop(Stack *s) {if (s->top >= 0) {return s->data[s->top--]; } else {printf("Stack is empty\n"); return -1;}}int evaluatePostfix(char *exp) { Stack s;initStack(s);int i = 0;while (exp[i] != '\0') {if (isdigit(exp[i])) {push(s, exp[i] - '0');} else {int op2 = pop(s);int op1 = pop(s);switch (exp[i]) {case '+':push(s, op1 + op2);break;case '-':push(s, op1 - op2);break;case '*':push(s, op1 * op2);break;case '/':push(s, op1 / op2);break;default:printf("Invalid operator\n"); return -1;}}i++;}return pop(s);}int m本人n() {char exp[] = "12+3*";int result = evaluatePostfix(exp);printf("Result: d\n", result);return 0;}```五、总结本文介绍了利用栈来完成C语言中运算表达式的求值。
使用栈构造二叉树链式存储的算法c语言如何使用栈构造二叉树链式存储的算法(C语言)第一步:了解二叉树的链式存储结构在讨论如何使用栈来构造二叉树的链式存储之前,首先需要了解二叉树的链式存储结构。
在链式存储结构中,每个节点都包含一个数据域和两个指针,分别指向该节点的左子树和右子树。
通过指针的连接,可以将多个节点组成一棵完整的二叉树。
在C语言中,可以通过定义一个结构体来表示二叉树的节点,结构体中包含数据域和两个指向左右子树的指针。
例如:ctypedef struct Node{int data;struct Node* left;struct Node* right;} Node;第二步:构造二叉树的算法思路在使用栈构造二叉树的算法中,主要需要考虑的是如何按照正确的顺序将节点链接起来,从而构成一棵完整的二叉树。
以下是一种使用栈构造二叉树的算法思路:1. 创建一个栈,并定义一个当前节点的指针current,并初始化为NULL。
2. 读取一个节点的值作为数据域,并创建一个新的节点。
3. 将新创建的节点的左子树指针指向当前节点。
4. 将新创建的节点入栈。
5. 将当前节点指针指向新创建的节点。
6. 重复步骤2-5,直到读取完所有的节点。
7. 当前节点出栈,并将当前节点指针指向出栈的节点的右子树。
8. 重复步骤7,直到栈为空。
9. 返回根节点。
第三步:应用算法构造二叉树的代码实现根据上述算法思路,可以使用以下代码实现使用栈构造二叉树的算法:c#include <stdio.h>#include <stdlib.h>typedef struct Node{int data;struct Node* left;struct Node* right;} Node;Node* createBinaryTree(int arr[], int size){Node* stack[size]; 创建一个大小为size的指针数组作为栈Node* root = NULL; 根节点指针初始化为NULLNode* current = NULL; 当前节点指针初始化为NULLint top = -1; 栈顶指针初始化为-1for(int i = 0; i < size; i++){Node* newNode = (Node*)malloc(sizeof(Node));newNode->data = arr[i];newNode->left = NULL;newNode->right = NULL;while(top > -1 && stack[top]->data < arr[i]){current = stack[top];top;}if(top > -1 && stack[top]->data > arr[i]){stack[top]->left = newNode;}else if(current != NULL){current->right = newNode;}else{root = newNode;}top++;stack[top] = newNode;current = NULL;}return root;}void inorderTraversal(Node* root){if(root != NULL){inorderTraversal(root->left);printf("%d ", root->data);inorderTraversal(root->right);}}int main(){int arr[] = {4, 2, 6, 1, 3, 5, 7};int size = sizeof(arr) / sizeof(arr[0]);Node* root = createBinaryTree(arr, size);printf("中序遍历结果:");inorderTraversal(root);return 0;}在这段代码中,我们首先定义一个指针数组stack作为栈,并将根节点指针root和当前节点指针current初始化为NULL。
目录题目一.二叉树操作(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、运行结果输入一个算术表达式,然后输出这个表达式(中缀),转换为后缀表达式,输出转换后的后缀表达式,根据后缀表达式计算出表达式的值,并输出,结果如图:五、设计总结通过这次课设我学会了许多东西,同时也遇到了许多问题。