《数据结构》实验二报告
一、目的和要求(需求分析):
1、掌握二叉树的存储结构以及二叉树的建立和操作。
2、输入一串表达式后,建立二叉树,并对其进行先序、中序和后序的遍历。
(输入表达式如此形式:a+b*c-d-e/f….;)
3、递归实现表达式运算。
二、程序设计的基本思想,原理和算法描述:
1.程序的结构:使用二叉树存储输入的表达式,其中叶子节点存储操作数,而其余节点存储运算符,不同层级的运算符则代表运算的先后顺序。
2.输入/输出设计:直接从键盘读入若干字符串形式的表达式,以string类型存入,而后利用tofloat()函数将数字部分转化成float类型。
3.计算的基本原理:利用二叉树存储的特性,利用乘除运算优先加减方式,先构建加减节点,然后构建乘除,最后将所有数字填入叶子节点。而计算时候直接从叶子节点读出两个数字根据双亲节点进行运算即可。
4.遍历的基本原理:通过调整对自身节点的和对左右子节点访问的顺序和递归调用就可以很容易实现二叉树的前中后序遍历。
三、调试和运行程序过程中产生的问题及采取的措施:
1.一开始对于string转化数字使用的是int类型,但是明显对于/运算会损失精度,所以后来装换成float,而改代码中由于忘记修改函数的返回值为float,所以浪费了很多时间debug。
2.一开始对于多位数字没有一个很好的办法处理,后来查到可以利用字符减去’0’后再强转成float形式最后乘以位数相应的10次方形式进行。
四、代码演示
#include<bits/stdc++.h>
using namespace std;
using EleType=string;
struct Tree{
EleType data;
Tree* left=NULL;
Tree* right=NULL;
};
Tree* root=NULL;
float tofloat(string s){//string to float
float sum=0.0;
int t=1;
for(int i=s.length()-1;i>=0;i--){
sum+=(s[i]-'0')*t*1.0;
t*=10;
}
return sum;
}
float calculate(Tree* p){//计算
if(p->data!="+"&&p->data!="-"&&p->data!="*"&&p->data!="/"){
return tofloat(p->data);
}
if(p->data=="+"){
return calculate(p->left)+calculate(p->right);
}
if(p->data=="-"){
return calculate(p->left)-calculate(p->right);
}
if(p->data=="*"){
return calculate(p->left)*calculate(p->right);
}
if(p->data=="/"){
return calculate(p->left)/calculate(p->right);
}
}
Tree* Build(string s,int l,int r){ //建树
int rt=-1;
if(l>r){
return NULL;
}
//寻找根节点
for(int i=r;i>=l;i--){
if(s[i]=='+'||s[i]=='-'){
rt=i;
break;
}
}
if(rt==-1){
for(int i=r;i>=l;i--){
if(s[i]=='*'||s[i]=='/'){
rt=i;
break;
}
}
}
//无根节点,建立叶子节点
if(rt==-1){
Tree* p=new Tree;
p->data=string(s,l,r-l+1);
return p;
}
//递归建树
Tree* p=new Tree;
p->data=string(s,rt,1);
p->left=Build(s,l,rt-1);
p->right=Build(s,rt+1,r);
return p;
}
void PreTra(Tree* p){//先序遍历
if(p==NULL) return;
cout<<p->data<<" ";
PreTra(p->left);
PreTra(p->right);
return;
}
void MidTra(Tree* p){//中序遍历
if(p==NULL) return;
MidTra(p->left);
cout<<p->data<<" ";
MidTra(p->right);
return;
}
void PosTra(Tree* p){//后序遍历
if(p==NULL) return;
PosTra(p->left);
PosTra(p->right);
cout<<p->data<<" ";
return;
}
void tra(Tree *root){
cout<<"前序遍历:";
PreTra(root);
cout<<endl;
cout<<"中序遍历:";
MidTra(root);
cout<<endl;
cout<<"后序遍历:";
PosTra(root);
cout<<endl;
}
void Test(){
//输入只含数字以及+-*/的字符串
string s;
cin>>s;
root=Build(s,0,s.length()-1);
cout<<calculate(root)<<endl;
tra(root);
}
int main(){
Test();
return 0;
}
五、心得与体会:
1、掌握二叉树的存储结构以及二叉树的建立和操作。
2、输入一串表达式后,建立二叉树,并对其进行先序、中序和后序的遍历。
3、递归实现表达式运算。
4、因为在建立二叉树的时候就根据加减乘除的运算先后分出树层级结构,所以后期计算的时候可以不用考虑运算的优先级问题,直接将叶子节点的数字节后双亲节点的运算符进行运算即可。
5、学到了处理字符串多位数字转化成数字的方法。