第十章 二叉树
学习目的
学习广义树的定义,熟悉树的有关术语
理解树是一种非线性的数据结构
理解很多有关树的操作都涉及到二叉树,所谓二叉树是指每个父结点最多包含两个子结点
掌握一棵n个结点的完全二叉树的高度是 int(log2n),这样的对是沿着从根开始的路径来寻找数据的
理解树的退化,面成为像链表一样的高效的存储结构
学习二叉树的实现,使用tnode对象来保存数据以及指向左、右子树的指针
理解6种树扫描的递归算法,最常用的3种算法是:中序,后序和前序遍历
学习使用队列逐层扫描树的算法
通过学习一系列实际应用,熟悉二叉树的相关算法
理解二叉搜索树的结构。理解二叉树按照结点的值,而不是结点的位置来保存数据。熟悉它的ADT
注意二叉搜索树是关联容器的特例
学习树的iterator类的实现
10.1树结构
根结构:在一棵树中,有一个唯一的起始点,称为根结点。每一个结点包含一个值和零个或多个指向
后继的结点的指针。
边:从父结点指向子结点的连接称为边。
叶子结点:没有子结点的称为叶子结点。
层次:任何结点到它或其子结点只有唯一的一条路径。从根结点到任何结点的路径长度为每一个结点
定义了一种度量,称为层次。根结点的层次是0
树的高度:定义为树中所有结点层次的最大值.高度的概念也可以用路径来解释.树的高度是所有从根
结点到其他结点的路径中长度的最大值.
建立二叉树
二叉树由动态分配的结点对象构成,这些结点对象的指针指向自己的子结点。
见代码chapter10.1
代码chapter10.2的树图
功能:建立如下二叉树,前序遍历,按层次遍历二叉树,拷贝二叉树,删除树
10.5 二叉搜索树
将二叉树设计成在能够存储大量数据的同时,又能为程序员提供方便高效的访问和更新元素的操作.最终得到的容器结构为二叉搜索树,......是所有关联容器的原型.
按元素值来存储的关联容器.
二叉树是由各个结点组成的数据结构,从根结点到其他结点之间只有唯一的路径.为了将二叉树设计成有效的存储容器,我们必须实现一种次序,把结点的值与它所处的路径联系起来.这种次序使得我们可以根据值来找到对应元素的位置.由于这个原因,这种存储容器称为二叉搜索树.
排序:对于每个结点,其左子树的所有结点的值都比它小,而其右子树中所有结点的值都比它大.
10.5.3二叉搜索树中的数据查找
每个结点都有一个唯一的路径.这个路径既可以用来插入,也可以用来查找元素.比较当前结点与待查找的元素,如果相等,则找到元素;否则,如果待查找元素小于当前结点,则查找左子树;如果大于当前结点,则查找右子树.如果最后达到空树,则称没有找到该值.
见代码chapter10.5
chapter10.1
// Tnode.h
// 表示ercas二叉树的一个结点
template<class T> class Tnode
{
public:
T nodeValue;
Tnode * left, *right; // 左右子结点指针
// 默认的构造函数,数据初始化
Tnode(){}
// 初始化数据成员
Tnode(const T & item, Tnode<T> * lptr = NULL, Tnode<T> * rptr = NULL)
: nodeValue(item), left(lptr),right(rptr)
{}
};
// main.cpp
#include <iostream>
#include "Tnode.h"
#include <string>
using namespace std;
template<class T> void pre_order(Tnode<T> * node);
int main()
{
Tnode<int> * root, * p, * q, * r;
p = new Tnode<int>(20);
q = new Tnode<int>(40);
r = new Tnode<int>(30,q );
root = new Tnode<int>(10,p,r);
pre_order( root );
return 0;
}
template<class T> void pre_order(Tnode<T> * node)
{
if( node != NULL )
{
cout << node->nodeValue << endl;
pre_order(node->left);
pre_order(node->right);
}
}
/chapter10.2
// Tnode.h
#ifndef BINTREE_H
#define BINTREE_H
// 表示ercas二叉树的一个结点
#include <iostream>
using std::cout;
using std::endl;
template<class T> class Tnode
{
public:
T nodeValue;
Tnode * left, *right; // 左右子结点指针
// 默认的构造函数,数据不有初始化
Tnode(){}
// 初始化数据成员
Tnode(const T & item, Tnode<T> * lptr = NULL, Tnode<T> * rptr = NULL)
: nodeValue(item), left(lptr),right(rptr)
{}
void setLeftNode(Tnode<T> * child_left)
{ left = child_left; }
void setRightNode( Tnode<T> * child_right )
{ right = child_right; }
~Tnode()
{ cout << "delete node that's value is " << nodeValue << endl; }
};
template<class T> class BinaryTree
{
public:
BinaryTree() : root(NULL)
{ count_leaf = 0;idepth=0;}
void build_tree();
//前序遍历二叉树
void pre_order();
// 按层次遍历二叉树
void level_order()
{ level_order(root); }
// 叶子结点计数
int getCountLeaf();
// 计算树的深度
int depth();
// 得到根结点
const Tnode<T> * getRoot()
{ return root; }
// 设置根结点
void setRoot( Tnode<T> * root_pa )
{ root = root_pa; }
Tnode<T> * copy_tree(const Tnode<T> * source);
void delete_tree()
{ delete_tree(root); }
protected:
Tnode<T> * root;
int count_leaf;
int idepth;
void pre_order(Tnode<T> * node);
void level_order(Tnode<T> * node);
void getCountLeaf(Tnode<T> * node);
int depth(Tnode<T> * node);
void delete_tree(Tnode<T> * node);
};
#endif
// BinaryTree.cpp
#include "Tnode.h"
#include <deque>
using std::max;
template<class T> void BinaryTree<T>::build_tree()
{
Tnode<char> * p,*pr,* lt, * rt, * oldp;
lt = new Tnode<char>('G');
p = new Tnode<char>('E',lt); // E子树
lt = new Tnode<char>('D'); // E的兄弟结点
p = new Tnode<char>('B',lt,p); // B 子树
lt = new Tnode<char>('H');
rt = new Tnode<char>('J');
pr = new Tnode<char>('F',lt,rt); // F子树
pr = new Tnode<char>('C',NULL,pr);// C子树
p = new Tnode<char>('A',p, pr);
root = p;
}
template<class T> void BinaryTree<T>::pre_order()
{
pre_order( root );
}
template<class T> void BinaryTree<T>::pre_order(Tnode<T> * node)
{
if( node != NULL )
{
cout << node->nodeValue << endl;
pre_order(node->left);
pre_order(node->right);
}
}
template<class T> void BinaryTree<T>::level_order(Tnode<T> * node)
{
using std::deque;
deque<Tnode<T> * > dq;
Tnode<T> * temp;
dq.push_back( node );
while ( !dq.empty() )
{
temp = dq.front();
dq.pop_front();
cout << temp->nodeValue;
if (NULL != temp->left )
dq.push_back(temp->left);
if (NULL != temp->right )
dq.push_back(temp->right);
}
}
template<class T> int BinaryTree<T>::getCountLeaf()
{
getCountLeaf( root );
return count_leaf;
}
template<class T> void BinaryTree<T>::getCountLeaf(Tnode<T> * node)
{
if( node != NULL )
{
if ( NULL == node->left && NULL == node->right )
count_leaf++;
getCountLeaf(node->left);
getCountLeaf(node->right);
}
}
template<class T> int BinaryTree<T>::depth()
{
int d = depth(root);
return d;
}
template<class T> int BinaryTree<T>::depth(Tnode<T> * node)
{
if ( NULL == node )
return -1;
return 1 + max(depth(node->left),depth(node->right));
}
template<class T> Tnode<T> * BinaryTree<T>::copy_tree(const Tnode<T> * source)
{
if ( NULL == source )
return NULL;
Tnode<T> * p = new Tnode<T>( source->nodeValue );
Tnode<T> * pl, * pr;
pl = copy_tree(source->left );
p->setLeftNode( pl );
pr = copy_tree(source->right);
p->setRightNode( pr );
return p;
}
template<class T> void BinaryTree<T>::delete_tree(Tnode<T> * node)
{
// 采用后序遍历,保证先删除子结点,再删除父结点
if ( NULL != node )
{
delete_tree(node->left);
delete_tree(node->right);
delete node;
}
}
// main.cpp
#include <iostream>
#include "Tnode.h"
#include "BinaryTree.cpp"
#include <string>
using namespace std;
int main()
{
BinaryTree<char> bintree;
bintree.build_tree();
int count = bintree.getCountLeaf();
cout << "leaf count = " << count << endl;
int d = bintree.depth();
cout << "depth of tree = " << d << endl;
BinaryTree<char> tree_backup;
Tnode<char> * p = tree_backup.copy_tree( bintree.getRoot() );
tree_backup.setRoot( p );
tree_backup.level_order();
tree_backup.pre_order();
cout << "the address of bintree root = " << bintree.getRoot() << endl;
cout << " the address of tree_backup = " << tree_backup.getRoot() << endl;
bintree.delete_tree();
return 0;
}
/
chapter10.5二叉搜索树 插入加查找
#ifndef BINTREE_H
#define BINTREE_H
// 表示ercas二叉树的一个结点
#include <iostream>
using std::cout;
using std::endl;
template<class T> class Tnode
{
public:
T nodeValue;
Tnode * left, *right; // 左右子结点指针
// 默认的构造函数,数据不有初始化
Tnode(){}
// 初始化数据成员
Tnode(const T & item, Tnode<T> * lptr = NULL, Tnode<T> * rptr = NULL)
: nodeValue(item), left(lptr),right(rptr)
{}
void setLeftNode(Tnode<T> * child_left)
{ left = child_left; }
void setRightNode( Tnode<T> * child_right )
{ right = child_right; }
~Tnode()
{ cout << "delete node that's value is " << nodeValue << endl; }
};
template<class T> class BinaryTree
{
public:
BinaryTree() : root(NULL)
{ count_leaf = 0;idepth=0;}
void build_tree();
//前序遍历二叉树
void pre_order();
// 按层次遍历二叉树
void level_order()
{ level_order(root); }
// 叶子结点计数
int getCountLeaf();
// 计算树的深度
int depth();
// 得到根结点
const Tnode<T> * getRoot()
{ return root; }
// 设置根结点
void setRoot( Tnode<T> * root_pa )
{ root = root_pa; }
Tnode<T> * copy_tree(const Tnode<T> * source);
void delete_tree()
{ delete_tree(root); }
void insert(const T & t)
{ insert( t, root, NULL, 1);
}
bool find(const T & t)
{ return find(t,root); }
protected:
Tnode<T> * root;
int count_leaf;
int idepth;
void pre_order(Tnode<T> * node);
void level_order(Tnode<T> * node);
void getCountLeaf(Tnode<T> * node);
int depth(Tnode<T> * node);
void delete_tree(Tnode<T> * node);
void insert(const T & t, Tnode<T> * current, Tnode<T> * parent, int flag);
bool find(const T & t, Tnode<T> * current);
};
#endif
// BinaryTree.cpp
#include "Tnode.h"
#include <deque>
using std::max;
template<class T> void BinaryTree<T>::build_tree()
{
Tnode<char> * p,*pr,* lt, * rt, * oldp;
lt = new Tnode<char>('G');
p = new Tnode<char>('E',lt); // E子树
lt = new Tnode<char>('D'); // E的兄弟结点
p = new Tnode<char>('B',lt,p); // B 子树
lt = new Tnode<char>('H');
rt = new Tnode<char>('J');
pr = new Tnode<char>('F',lt,rt); // F子树
pr = new Tnode<char>('C',NULL,pr);// C子树
p = new Tnode<char>('A',p, pr);
root = p;
}
template<class T> void BinaryTree<T>::pre_order()
{
pre_order( root );
}
template<class T> void BinaryTree<T>::pre_order(Tnode<T> * node)
{
if( node != NULL )
{
cout << node->nodeValue << endl;
pre_order(node->left);
pre_order(node->right);
}
}
template<class T> void BinaryTree<T>::level_order(Tnode<T> * node)
{
using std::deque;
deque<Tnode<T> * > dq;
Tnode<T> * temp;
dq.push_back( node );
while ( !dq.empty() )
{
temp = dq.front();
dq.pop_front();
cout << temp->nodeValue;
if (NULL != temp->left )
dq.push_back(temp->left);
if (NULL != temp->right )
dq.push_back(temp->right);
}
}
template<class T> int BinaryTree<T>::getCountLeaf()
{
getCountLeaf( root );
return count_leaf;
}
template<class T> void BinaryTree<T>::getCountLeaf(Tnode<T> * node)
{
if( node != NULL )
{
if ( NULL == node->left && NULL == node->right )
count_leaf++;
getCountLeaf(node->left);
getCountLeaf(node->right);
}
}
template<class T> int BinaryTree<T>::depth()
{
int d = depth(root);
return d;
}
template<class T> int BinaryTree<T>::depth(Tnode<T> * node)
{
if ( NULL == node )
return -1;
return 1 + max(depth(node->left),depth(node->right));
}
template<class T> Tnode<T> * BinaryTree<T>::copy_tree(const Tnode<T> * source)
{
if ( NULL == source )
return NULL;
Tnode<T> * p = new Tnode<T>( source->nodeValue );
Tnode<T> * pl, * pr;
pl = copy_tree(source->left );
p->setLeftNode( pl );
pr = copy_tree(source->right);
p->setRightNode( pr );
return p;
}
template<class T> void BinaryTree<T>::delete_tree(Tnode<T> * node)
{
// 采用后序遍历,保证先删除子结点,再删除父结点
if ( NULL != node )
{
delete_tree(node->left);
delete_tree(node->right);
delete node;
}
}
template<class T>
void BinaryTree<T>::insert(const T & t, Tnode<T> * current, Tnode<T> * parent, int flag)
{
if ( NULL == t )
return ;
if ( NULL == root )
{
root = new Tnode<T>(t);
return ;
}
if ( NULL == current )
{
Tnode<T> * p = new Tnode<T>(t);
flag?( parent->left = p):(parent->right = p);
return;
}
if( t<current->nodeValue)
insert(t, current->left,current,1);
else if (t>current->nodeValue)
insert(t, current->right,current,0);
}
template<class T> bool BinaryTree<T>::find(const T & t, Tnode<T> * current)
{
if (NULL == current)
return false;
if (t == current->nodeValue)
return true;
else if (t < current->nodeValue)
return find(t,current->left);
else
return find(t,current->right);
}
//main.cpp
#include <iostream>
#include "Tnode.h"
#include "BinaryTree.cpp"
#include <string>
using namespace std;
int main()
{
BinaryTree<int> binSearchTree;
binSearchTree.insert(30);
binSearchTree.insert(25);
binSearchTree.insert(35);
binSearchTree.insert(10);
binSearchTree.insert(32);
binSearchTree.insert(37);
binSearchTree.insert(15);
binSearchTree.level_order();
bool b = binSearchTree.find( 10 );
b?( cout << "exist/n" ):(cout << "does't exist/n");
b = binSearchTree.find( 8 );
b?( cout << "exist/n" ):(cout << "does't exist/n");
return 0;
}