实验4 二叉树的应用
分别提交两个附件:
1:设计文档(提交PDF格式的文件,文件名要规范,参看规范)。
2:实验源码包。(文件名也要规范,可以参考报告文件的格式)
一、问题分析
要处理的对象:N个不同的非负键值整数数列
要实现的功能:利用这个非负键值整数数列,构造一颗既是CBT也是BST的树,并将这个数以层次遍历的形式在一行中输出。
结果显示:以层次遍历的形式输出这棵树,输出要求每个数字必须由一个空格隔开,且行首和行尾没有多余的空格。
二、算法思想设计
① 这个实验的首要任务是建立这样一棵既是二叉搜索树,又是完全二叉树的树,所以这棵树要尽可能的矮,且第k层的所有节点都连续集中在最左边。
② 构造这棵树的初步思想是使用递归,主要分三步:
a.先找到根节点的值;
b.再确定这个根节点的左子树和右子树;
c.接着分别以左子树和右子树作为新的根节点,分别找寻他们的左子树和右子树;
d.循环递归,直到找完所有的数值,完成建立树。
③ 从上述建树的过程可以看出,建树的关键是找到数组中各个根节点。下面的步骤将围绕根节点的寻找展开。
④ 寻找根节点的方法:将数组进行从小到大的顺序排序,只需要确定了左子节点的个数,就能确定根节点的位置。
⑤ 确定左子节点个数的方法:因为该树为CBT,故从1-(k-1)层一定是一个满二叉树(也是完全二叉树),所有节点个数加起来为(-1)个,
a.先确定树的层数。因为该树为CBT,故层数k满足-1≧N,解得最小k即为层数。
b.因为该树是CBT,故从1到(k-1)层一定是一个满二叉树(也是完全二叉树),从1到(k-1)层,节点个数加起来为(-1)个,则最后一层的叶子结点数为N-(-1)个。
c.最后一层的满值个数是,若b中算出来最后一层的叶子结点个数>/2,则左子节点数最后一层为/2个,否则则为N-(-1)个。
⑥ 数组个数出去最小的几个左子节点数外,其余的数对半分,中间的值即为根节点。
⑦ 根节点找到后数组分为左右两个子段数组,利用递归循环,重复上述寻找根节点的步骤,完成树的建立。
三、样例分析
【样例】10
1 2 3 4 5 6 7 8 9 0
【分析】
① 数组先进行从小到大的排序,为0 1 2 3 4 5 6 7 8 9;
② 数组长度N=10,由-1=15≧N,算得k=4,一共4层。由N-(-1)得最后一层的叶子结点数为3,3</2=8,故最后一层左子节点数为3;
③ 数组忽略前三个最小的数,后续7个数取中间的数6作为第一层的根节点,并将6的左段作为【数组1】(0 1 2 3 4 5),右端为【数组2】(7 8 9);
④ 在左端对【数组1】进行递归,此时N=6,由-1=7≧N,算得k=3,一共3层。由N-(-1)得最后一层的叶子结点数为3,3</2=2,故最后一层左子节点数为2。忽略【数组1】中前两个数和后一个数,2 3 4三个数取中间值为3作为左子节点。
⑤ 以3为新的根节点,将【数组1】分为【数组11】(0 1 2)和数组【数组12】(4 5);
⑥ 对【数组11】进行递归,此时N=3,由-1≧N,算得k=2,一共2层。由N-(-1)得最后一层的叶子结点数为2,2>/2=1,故最后一层左子节点数为1。忽略【数组11】中前1个数和后1个数,根节点为1;
⑦ 以根节点1为分界点,左端0右端2,再根据递归作为1的左子节点和右子结点。
⑧ 返回结点3,结点3的右端【数组12】(4 5),根据递归可得3的右子节点为5,5的左子节点为4
⑨ 返回结点6,处理6的右端【数组2】(7 8 9),根据递归,一共2层,最底层的左子节点数为1,根节点为8;
⑩ 根据根节点8将【数组2】分为7和9两个数组,根据递归得8的左子节点为7,右子结点为9.
⑪ 递归到这里,用完了所有数字,完成建树。树的形状如下图:
【样例输出】
6 3 8 1 5 7 9 0 2 4
四、关键功能的算法步骤
① 对输入的数组进行排序sort(number,number+n);
② 计算树的层数
③ 最底下一层的左子节点个数为left_number = n-(key/2)+1;left_number=(left_number>key/4)?key/4:left_number;
④ 确定树的高度key += pow(2,i);
⑤ 分别对左右部分进行递归root->setLeft(built_CBT_BST(leftinorder,rt_pos,k - 1));;root->setRight(built_CBT_BST(rightinorder,n - rt_pos - 1,k - 1));
⑥ 层次输出树myTree.levelOrder(root);
五、分析
1)Cin>>n;时间复杂度为1;
2)for(int i = 0 ; i < n ; i++) {cin >> number[i];},在数组中依次存储数据,时间复杂度为n;
3)数组排序sort(number,number+n);时间复杂度为log n;
4)创建树build_BST_CBT(number[],n,k);时间复杂度为n;
5)输出树,时间复杂度为n;
6)总的时间复杂度为O(n);
7)计算过程中给每个节点开辟了空间,故空间复杂度为O(n)
六、二叉树ADT的实现
① void clear()=0;//清空二叉树
② void preOrder(void(*visit)(BinNode*node))=0;//前序遍历
③ void inOrder(void(*visit)(BinNode*node))=0;//中序遍历
④ void postOrder(void(*visit)(BinNode*node))=0;//后序遍历
⑤ void LevelOrderTranverse(void(*visit)(BinNode*node))=0;//层次遍历
⑥ bool create_by_post_and_in_order(E post[],E in[],int n)=0;//按照中序遍历和后序遍历的结果还原树
⑦ int BinTreeDepth(BinNode*tmp)=0;//计算树的深度
⑧ int BinTreeNodes(BinNode*tmp)=0;//计算树的结点数
⑨ int BinTreeHeight(BinNode*tmp)=0;//计算树的高度
⑩ int BinTreeLeafs(BinNodetmp)=0;//计算树的叶子结点数
⑪ bool find(BinNodetmp,E e)=0;//在树中寻找值e
⑫ int countNode(BinNode rt)
⑬ BinNode built_CBT_BST(int number[],int n,int k)//按照一组数建立一个即是BST又是CBT的树
代码实现部分:
BinNode.h
#ifndef BINNODE_H_INCLUDED
#define BINNODE_H_INCLUDED
#include <iostream>
#include <math.h>
using namespace std;
template<typename E>
class BinNode//结点类
{
private:
BinNode*lc;//左孩子
BinNode*rc;//右孩子
E elem;
public:
BinNode()//默认构造函数
{
lc = NULL;
rc = NULL;
}
BinNode(E tmp,BinNode*l=NULL,BinNode*r=NULL)//带参构造函数
{
elem = tmp;
lc = l;
rc = r;
}
BinNode*left()//返回左孩子
{
return lc;
}
BinNode*right()//返回右孩子
{
return rc;
}
void setLeft(BinNode*l)//设置左孩子
{
lc = l;
}
void setRight(BinNode*r)//设置右孩子
{
rc = r;
}
void setValue(E tmp)//设置当前结点的值
{
elem = tmp;
}
E getValue()//获得当前结点的值
{
return elem;
}
bool isLeaf()//判断当前结点是否为叶子结点
{
if(lc == NULL&&rc == NULL)
return true;
else
return false;
}
};
#endif // BINNODE_H_INCLUDED
BinTree.h
#ifndef BINTREE_H_INCLUDED
#define BINTREE_H_INCLUDED
#include "BinNode.h"
#include "string"
#include <queue>
template<typename E>
class BinTree //二叉树类
{
private:
BinNode<E>*root;//根节点
bool build_BST_CBT_help(BinNode<E>* now,E number[],int start,int endd)
{
int n = endd - start + 1;
int k=1;int key =2;
while(n+1>key)
{
k++;
key *= 2;
}
int left_number = n-(key/2)+1;
left_number=(left_number>key/4)?key/4:left_number;
int address = start+left_number+(n-left_number-1)/2;
E temp=number[address];
root->setValue(temp);
if(address>0)//有左子树
{
root->setLeft(new BinNode<E>);
if(!build_BST_CBT_help(root->left(),number,address-(n-left_number-1)/2-left_number,address-1)) return 0;
}
if(address<n-1)//有右子树
{
root->setRight(new BinNode<E>);
if(!build_BST_CBT_help(root->right(),number,address+1,address+(n-left_number-1)/2)) return 0;
}
return 1;
}
bool create_by_post_and_in_order_help(BinNode<E>* now,E post[],E in[],int pi,int pj,int ini,int inj)
{
E temp=post[pj];
int pos=ini;
for(pos=ini;pos<inj;pos++)
{
if(in[pos]==temp)
{
break;
}
}
if(pos>inj)
{
return 0;
}
now->setValue(temp);
if(pos>ini)//有左子树
{
int num_of_left=pos-ini;
now->setLeft(new BinNode<E>);
if(!create_by_post_and_in_order_help(now->left(),post,in,pi,pi+num_of_left-1,ini,pos-1)) return 0;
}
if(pos<inj)//有右子树
{
int num_of_right=inj-pos;
now->setRight(new BinNode<E>);
if(!create_by_post_and_in_order_help(now->right(),post,in,pj-num_of_right,pj-1,pos+1,inj)) return 0;
}
return 1;
}
void clear(BinNode<E>*r)//清空二叉树
{
if(r==NULL)
return ;
if(r->left()!=NULL)
{
clear(r->left());
}
if(r->right()!=NULL)
{
clear(r->right());
}
delete r;
r = NULL;
}
void preOrder(BinNode<E>*tmp,void(*visit)(BinNode<E>*node))
//先序遍历,void(*visit)(BinNode<E>*node)为一个函数指针参数
{
if(tmp== NULL)
return;
visit(tmp);
preOrder(tmp->left(),visit);
preOrder(tmp->right(),visit);
}
void inOrder(BinNode<E>*tmp,void(*visit)(BinNode<E>*node))
//中序遍历,void(*visit)(BinNode<E>*node)为一个函数指针参数
{
if(tmp == NULL)
return;
inOrder(tmp->left(),visit);
visit(tmp);
inOrder(tmp->right(),visit);
}
void postOrder(BinNode<E>*tmp,void(*visit)(BinNode<E>*node))
//后续遍历,void(*visit)(BinNode<E>*node)为一个函数指针参数
{
if(tmp == NULL)
return;
postOrder(tmp->left(),visit);
postOrder(tmp->right(),visit);
visit(tmp);
}
void LevelOrderTranverse(BinNode<E>*tmp,void(*visit)(BinNode<E>*node))
//层次遍历
{
if(tmp ==NULL)
return;
queue<BinNode<E>*>que;
que.push(tmp);
BinNode<E>*curr;
//int sum=0;
while(que.empty()!=true)
{
curr = que.front();
if(curr->left()!=NULL)
{
que.push(curr->left());
}
if(curr->right()!=NULL)
{
que.push(curr->right());
}
que.pop();
visit(curr);
}
}
int BinTreeDepth(BinNode<E>*tmp)
//获得二叉树的深度
{
if(tmp==NULL)
return 0;
int ld=0;
int rd=0;
if(tmp->left!=NULL)
ld=BinTreeDepth(tmp->left());
if(tmp->right!=NULL)
rd=BinTreeDepth(tmp->right());
if(ld>=rd)
return ld+1;
else
return rd+1;
}
int BinTreeNodes(BinNode<E>*tmp)
//获得二叉树的结点数
{
if(tmp==NULL)
return 0;
queue<BinNode<E>*>que;
que.push(tmp);
BinNode<E>*curr;
int sum = 0;
while(que.empty!=true)
{
curr = que.front();
if(curr->left()!=NULL)
que.push(curr->left());
if(curr->right()!=NULL)
que.push(curr->righ());
que.pop();
sum++;
}
return sum;
}
int BinTreeHeight(BinNode<E>*tmp)
//获得二叉树的高度
{
if(tmp==NULL)
return 0;
return BinTreeDepth(tmp)-1;
}
int BinTreeLeafs(BinNode<E>*tmp)
//获得二叉树的叶子结点数
{
if(tmp==NULL)
return 0;
queue<BinNode<E>*>que;
que.push(tmp);
BinNode<E>*curr;
int sum=0;
while(que.empty()!=true)
{
curr=que.front();
if(curr->left()!=NULL)
que.push(curr->left);
if(curr->right()!=NULL)
que.push(curr->right);
if(curr->right()==NULL&&curr->left()==NULL)
sum++;
que.pop();
}
return sum;
}
bool find(BinNode<E>*tmp,E e)
//查找二叉树中是否含有某个名为e的结点
{
if(tmp==NULL)
return 0;
queue<BinNode<E>*>que;
que.push(tmp);
BinNode<E>*curr;
int sum=0;
while(que.empty()!=true)
{
curr=que.front();
if(curr->left()!=NULL)
que.push(curr->left);
if(curr->right()!=NULL)
que.push(curr->right);
if(curr->getValue()==e)
return true;
que.pop();
}
return false;
}
public:
BinTree()//默认构造函数
{
root=new BinNode<E>;
}
~BinTree()//析构函数
{
clear(root);
}
bool BinTreeEmpty()//判断二叉树是否为空
{
if(root == NULL)
return true;
else
return false;
}
BinNode<E>*getRoot()//获得根节点
{
return root;
}
void setRoot(BinNode<E>*r)//设置根节点
{
root = r;
}
//下面的函数是对外的函数,所以内部还会有一些同名的函数,但是参数列表不一样,
//实现数据的封装,外部的调用不会涉及到内部的数据对象
void clear()//清空二叉树
{
clear(root);
root = NULL;
}
void preOrder(void(*visit)(BinNode<E>*node))
//先序遍历,传入相对应的访问函数即可对该当前结点实现不同功能的访问(输出)
{
inOrder(root,visit);
}
void inOrder(void(*visit)(BinNode<E>*node))
//中序遍历,传入相对应的访问函数即可对该当前结点实现不同功能的访问(输出)
{
inOrder(root,visit);
}
void postOrder(void(*visit)(BinNode<E>*node))
//后序遍历,传入相对应的访问函数即可对该当前结点实现不同功能的访问(输出)
{
inOrder(root,visit);
}
void LevelOrderTranverse(void(*visit)(BinNode<E>*node))
//层次遍历,传入相对应的访问函数即可对该当前结点实现不同功能的访问(输出)
{
LevelOrderTranverse(root,visit);
}
int BinTreeDepth()//获得二叉树的深度
{
return BinTreeDepth(root);
}
int BinTreeNodes()//获得二叉树结点数
{
return BinTreeNodes(root);
}
int BinTreeHeight()//获得二叉树高度
{
return BinTreeHeigh(root);
}
int BinTreeLeafs()//获得二叉树叶子结点数
{
return BinTreeLeafs(root);
}
bool find(E e)//查找二叉树中是否存在名为e的结点
{
return find(root,e);
}
bool create_by_post_and_in_order(E post[],E in[],int n)
{
clear();
root=new BinNode<E>;
E temp=post[n-1];
root->setValue(temp);
int pos=0;
for(pos=0;pos<n;pos++)
{
if(in[pos]==temp)
{
break;
}
}
if(pos>0)//有左子树
{
int num_of_left=pos;
root->setLeft(new BinNode<E>);
if(!create_by_post_and_in_order_help(root->left(),post,in,0,0+num_of_left-1,0,pos-1)) return 0;
}
if(pos<n-1)//有右子树
{
int num_of_right=n-pos-1;
root->setRight(new BinNode<E>);
if(!create_by_post_and_in_order_help(root->right(),post,in,pos,pos+num_of_right-1,pos+1,pos+num_of_right)) return 0;
}
return 1;
}
bool build_BST_CBT(E number[],int n)
{
int k=1;int key =2;
while(n+1>key)
{
k++;
key *= 2;
}
int left_number = n-(key/2)+1;
left_number=(left_number>key/4)?key/4:left_number;
int address = left_number+(n-left_number-1)/2;
E temp=number[address];
root->setValue(temp);
if(address>0)//有左子树
{
//int num_of_left=key;
root->setLeft(new BinNode<E>);
if(!build_BST_CBT_help(root->left(),number,0,address-1)) return 0;
}
if(address<n-1)//有右子树
{
//int num_of_right=n-key-1;
root->setRight(new BinNode<E>);
if(!build_BST_CBT_help(root->right(),number,address+1,n-1)) return 0;
}
return 1;
}
};
#endif // BINTREE_H_INCLUDED
BinTree_ADT.h
#ifndef BINTREE_H
#define BINTREE_H
#include"BinNode.h"
#include<vector>
template <class E> class BinTree_ADT
{
public:
virtual void clear()=0;
virtual void preOrder(void(*visit)(BinNode<E>*node))=0;
virtual void inOrder(void(*visit)(BinNode<E>*node))=0;
virtual void postOrder(void(*visit)(BinNode<E>*node))=0;
virtual void LevelOrderTranverse(void(*visit)(BinNode<E>*node))=0;
virtual bool create_by_post_and_in_order(E post[],E in[],int n)=0;
virtual int BinTreeDepth(BinNode<E>*tmp)=0;
virtual int BinTreeNodes(BinNode<E>*tmp)=0;
virtual int BinTreeHeight(BinNode<E>*tmp)=0;
virtual int BinTreeLeafs(BinNode<E>*tmp)=0;
virtual bool find(BinNode<E>*tmp,E e)=0;
//virtual void LevelOrderTraverse(BinNode* rt)=0;
virtual bool build_BST_CBT(E number[],int n)=0;
};
#endif // BINTREE_H
main.c
#include <iostream>
#include <string>
#include <algorithm>
#include "BinTree.h"
#include "BinNode.h"
using namespace std;
template<typename E>
void printNode(BinNode<E>*tmp)//打印结点的值的函数
{
cout << tmp->getValue() << " ";
}
int main()
{
int n;
cin >> n;
BinTree<int> tree;
int number[n];
for(int i = 0 ; i < n ; i++)
cin >> number[i];
sort(number,number+n);
bool b ;
b = tree.build_BST_CBT(number,n);
if(b)
{
tree.LevelOrderTranverse(printNode);
}
return 0;
}