"《算法导论》之‘树’":二叉查找树

时间:2021-11-22 16:25:41

  树的介绍部分摘取自博文二叉查找树(一)二叉查找树(二)二叉查找树

1. 树的介绍

1.1 树的定义

  树是一种数据结构,它是由n(n>=1)个有限节点组成一个具有层次关系的集合。

  "《算法导论》之‘树’":二叉查找树

  把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:
  (1) 每个节点有零个或多个子节点;
  (2) 没有父节点的节点称为根节点;
  (3) 每一个非根节点有且只有一个父节点;
  (4) 除了根节点外,每个子节点可以分为多个不相交的子树。

1.2 树的基本术语

  若一个结点有子树,那么该结点称为子树根的"双亲",子树的根是该结点的"孩子"。有相同双亲的结点互为"兄弟"。一个结点的所有子树上的任何结点都是该结点的后裔。从根结点到某个结点的路径上的所有结点都是该结点的祖先。

  结点的度:结点拥有的子树的数目。
  叶子:度为零的结点。
  分支结点:度不为零的结点。
  树的度:树中结点的最大的度。

  层次:根结点的层次为1,其余结点的层次等于该结点的双亲结点的层次加1。
  树的高度:树中结点的最大层次。
  无序树:如果树中结点的各子树之间的次序是不重要的,可以交换位置。
  有序树:如果树中结点的各子树之间的次序是重要的, 不可以交换位置。
  森林:0个或多个不相交的树组成。对森林加上一个根,森林即成为树;删去根,树即成为森林。

2. 二叉树介绍

2.1 二叉树的定义

  二叉树是每个节点最多有两个子树的树结构。它有五种基本形态:二叉树可以是空集;根可以有空的左子树或右子树;或者左、右子树皆为空。

  "《算法导论》之‘树’":二叉查找树

2.2 二叉树的性质

  二叉树有以下几个性质:TODO(上标和下标)
  性质1:二叉树第i层上的结点数目最多为 2{i-1} (i≥1)。
  性质2:深度为k的二叉树至多有2{k}-1个结点(k≥1)。
  性质3:包含n个结点的二叉树的高度至少为log2 (n+1)
  性质4:在任意一棵二叉树中,若终端结点的个数为n0,度为2的结点数为n2,则n0=n2+1

  性质1:二叉树第i层上的结点数目最多为 2{i-1} (i≥1)

  证明:下面用"数学归纳法"进行证明。
        (01) 当i=1时,第i层的节点数目为2{i-1}=2{0}=1。因为第1层上只有一个根结点,所以命题成立。
        (02) 假设当i>1,第i层的节点数目为2{i-1}。这个是根据(01)推断出来的!
               下面根据这个假设,推断出"第(i+1)层的节点数目为2{i}"即可。
               由于二叉树的每个结点至多有两个孩子,故"第(i+1)层上的结点数目" 最多是 "第i层的结点数目的2倍"。即,第(i+1)层上的结点数目最大值=2×2{i-1}=2{i}
                故假设成立,原命题得证!

  性质2:深度为k的二叉树至多有2{k}-1个结点(k≥1)

  证明:在具有相同深度的二叉树中,当每一层都含有最大结点数时,其树中结点数最多。利用"性质1"可知,深度为k的二叉树的结点数至多为:
           20+21+…+2k-1=2k-1
           故原命题得证!

  性质3:包含n个结点的二叉树的高度至少为log2 (n+1)

  证明:根据"性质2"可知,高度为h的二叉树最多有2{h}–1个结点。反之,对于包含n个节点的二叉树的高度至少为log2(n+1)。

  性质4:在任意一棵二叉树中,若终端结点的个数为n0,度为2的结点数为n2,则n0=n2+1

  证明:因为二叉树中所有结点的度数均不大于2,所以结点总数(记为n)="0度结点数(n0)" + "1度结点数(n1)" + "2度结点数(n2)"。由此,得到等式一。
         (等式一) n=n0+n1+n2
      另一方面,0度结点没有孩子,1度结点有一个孩子,2度结点有两个孩子,故二叉树中孩子结点总数是:n1+2n2。此外,只有根不是任何结点的孩子。故二叉树中的结点总数又可表示为等式二。
         (等式二) n=n1+2n2+1
        由(等式一)和(等式二)计算得到:n0=n2+1。原命题得证!

2.3 满二叉树,完全二叉树和二叉查找树

    (1)满二叉树

  定义:高度为h,并且由2{h} –1个结点的二叉树,被称为满二叉树。

  "《算法导论》之‘树’":二叉查找树

    (2)完全二叉树

  定义:一棵二叉树中,只有最下面两层结点的度可以小于2,并且最下一层的叶结点集中在靠左的若干位置上。这样的二叉树称为完全二叉树。
  特点:叶子结点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部。显然,一棵满二叉树必定是一棵完全二叉树,而完全二叉树未必是满二叉树。

  "《算法导论》之‘树’":二叉查找树

   (3)二叉查找树

  定义:二叉查找树(Binary Search Tree),又被称为二叉搜索树。设x为二叉查找树中的一个结点,x节点包含关键字key,节点x的key值记为key[x]。如果y是x的左子树中的一个结点,则key[y] < key[x];如果y是x的右子树的一个结点,则key[y] > key[x]。

  "《算法导论》之‘树’":二叉查找树

    

  在二叉查找树中:

  1)若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;

  2)任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;

  3)任意节点的左、右子树也分别为二叉查找树。

  4)没有键值相等的节点(no duplicate nodes)。

3. 二叉查找树操作

3.1 查找

  在二叉查找树中查找一个给定的关键字k的过程与二分查找很类似,根据二叉查找树在的关键字存放的特征,很容易得出查找过程:首先是关键字k与树根的关键字进行比较,如果k大比根的关键字大,则在根的右子树中查找,否则在根的左子树中查找,重复此过程,直到找到与遇到空结点为止。例如下图所示的查找关键字13的过程:(查找过程每次在左右子树中做出选择,减少一半的工作量)

  "《算法导论》之‘树’":二叉查找树

  《算法导论》中给出的递归和非递归的伪代码如下:

 TREE_SEARCH(x,k)
if x=NULL or k=key[x]
then return x
if(k<key[x])
then return TREE_SEARCH(left[x],k)
else
then return TREE_SEARCH(right[x],k)
 ITERATIVE_TREE_SEARCH(x,k)
while x!=NULL and k!=key[x]
do if k<key[x]
then x=left[x]
else
then x=right[x]
return x

3.2 查找最大关键字和最小关键字

  根据二叉查找树的特征,很容易查找出最大和最小关键字。查找二叉树中的最小关键字:从根结点开始,沿着各个节点的left指针查找下去,直到遇到NULL时结束。如果一个结点x无左子树,则以x为根的子树中,最小关键字就是key[x]。查找二叉树中的最大关键字:从根结点开始,沿着各个结点的right指针查找下去,直到遇到NULL时结束。书中给出了查找最大最小关键字的伪代码:

  《算法导论》中给出的伪代码如下:

 TREE_MINMUM(x)
while left[x] != NULL
do x=left[x]
return x
 TREE_MAXMUM(x)
while right[x] != NULL
do x= right[x]
return x

3.3 前驱和后继

  给定一个二叉查找树中的结点,找出在中序遍历顺序下某个节点的前驱和后继。如果树中所有关键字都不相同,则某一结点x的前驱就是小于key[x]的所有关键字中最大的那个结点,后继即是大于key[x]中的所有关键字中最小的那个结点。根据二叉查找树的结构和性质,不用对关键字做任何比较,就可以找到某个结点的前驱和后继。

  查找前驱步骤:先判断x是否有左子树,如果有则在left[x]中查找关键字最大的结点,即是x的前驱。如果没有左子树,则从x继续向上执行此操作,直到遇到某个结点是其父节点的右孩子结点。例如下图查找结点7的前驱结点6过程:

  "《算法导论》之‘树’":二叉查找树

  查找后继步骤:先判断x是否有右子树,如果有则在right[x]中查找关键字最小的结点,即使x的后继。如果没有右子树,则从x的父节点开始向上查找,直到遇到某个结点是其父结点的左儿子的结点时为止。例如下图查找结点13的后继结点15的过程:

  "《算法导论》之‘树’":二叉查找树

  《算法导论》中中给出了求x结点后继结点的伪代码:

 TREE_PROCESSOR(x)
if right[x] != NULL
then return TREE_MINMUM(right(x))
y=parent[x]
while y!= NULL and x ==right[y]
do x = y
y=parent[y]
return y

    定理:对一棵高度为h的二叉查找,动态集合操作SEARCH、MINMUM、MAXMUM、SUCCESSOR、PROCESSOR等的运行时间均为O(h)。

3.4 插入和删除

  插入和删除会引起二叉查找表示的动态集合的变化,难点在在插入和删除的过程中要保持二叉查找树的性质。插入过程相当来说要简单一些,删除结点比较复杂。

  (1)插入

  插入结点的位置对应着查找过程中查找不成功时候的结点位置,因此需要从根结点开始查找带插入结点位置,找到位置后插入即可。下图所示插入结点过程:

  "《算法导论》之‘树’":二叉查找树

  《算法导论》中给出了插入过程的伪代码:

 TREE_INSERT(T, z)
y = NULL;
x = root[T]
while x != NULL
do y = x
if key[z] < key[x]
then x = left[x]
else
x = right[x]
parent[z] = y
if y = NULL
then root[T] = z
else if key[z]>key[y]
then keft[y] = z
else right[y] = z

  插入过程运行时间为O(h),h为树的高度。

  (2)删除

  从二叉查找树中删除给定的结点z,分三种情况讨论:

  <1>结点z没有左右子树,则修改其父节点p[z],使其为NULL。删除过程如下图所示:

  "《算法导论》之‘树’":二叉查找树

  <2>如果结点z只有一个子树(左子树或者右子树),通过在其子结点与父节点建立一条链来删除z。删除过程如下图所示:

  "《算法导论》之‘树’":二叉查找树

  <3>如果z有两个子女,那么找z的后继y(一定在z的右子树中),并让y占据树中z的位置。z的原来右子树部分成为y的新的右子树,并且z的左子树成为y的新的左子树。

  "《算法导论》之‘树’":二叉查找树

  《算法导论》中给出了删除过程的伪代码:

 TREE_DELETE(T, z)
if left[z] == NULL or right[z] == NULL
then y = z
else y = TREE_SUCCESSOR(z) if left[y] != NULL
then x = left[y]
else x = right[y] if x != NULL
then parent[x] = parent[y]
if p[y] == NULL
then root[T] = x
else if y = left[[prarnt[y]]
then left[parent[y]] = x
else right[parent[y]] = x if y != z
then key[z] = key[y]
copy y's data into z
return y

  定理:对高度为h的二叉查找树,动态集合操作INSERT和DELETE的运行时间为O(h)。

3.5 遍历

  前序遍历

  若二叉树非空,则执行以下操作:
  (1) 访问根结点;
  (2) 先序遍历左子树;
  (3) 先序遍历右子树

  中序遍历

  若二叉树非空,则执行以下操作:
  (1) 中序遍历左子树;
  (2) 访问根结点;
  (3) 中序遍历右子树。

  后序遍历

  若二叉树非空,则执行以下操作:
  (1) 后序遍历左子树;
  (2) 后序遍历右子树;
  (3) 访问根结点。

  看看下面这颗树的各种遍历方式:

  "《算法导论》之‘树’":二叉查找树

  对于上面的二叉树而言,
  (1) 前序遍历结果: 3 1 2 5 4 6
  (2) 中序遍历结果: 1 2 3 4 5 6 
  (3) 后序遍历结果: 2 1 4 6 5 3

4. 二叉查找树实现

  我先定义了一个最基本的类“Tree”如下:

 #ifndef TREE_H
#define TREE_H #include <iostream>
#include <cassert>
using namespace std; template<class T>
class Node
{
public:
Node() : height(), parent(NULL), left(NULL), right(NULL){};
~Node(){}; public:
T key;
T data;
unsigned int height;
Node * parent;
Node * left;
Node * right; }; template<class T>
class Tree
{
public:
typedef Node<T> * NodePointer; public:
Tree(){};
virtual ~Tree(){};
//Tree(const Tree& orig){};
//Tree& operator=(const Tree& orig){};
virtual bool isEmpty() = ; // 判断树是否为空
virtual void creatTree(T * k, T * arr, unsigned len) = ; // 初始化树
virtual bool addNode(T k, T val) = ; // 添加节点
virtual bool delNode(T k) = ; // 删除节点 virtual unsigned int getHeight() = ; // 获得树的高度
//virtual unsigned int getHeight(NodePointer tree) = 0; virtual T getMinimum() = ; // 获取树中的最小值
virtual T getMaxmum() = ; // 获取树中的最大值 virtual Node<T> * searchNode(T k) = ; // 搜索key为k的节点
virtual Node<T> * getPredecessor(T k) = ; // 获取某节点(key为k)的前驱节点
virtual Node<T> * getSuccessor(T k) = ; // 获取某节点(key为k)的后继节点 virtual void preOrder() = ; //先序遍历
//virtual void preOrder(NodePointer tree) = 0;
virtual void inOrder() = ; //中序遍历
//virtual void inOrder(NodePointer tree) = 0;
virtual void postOrder() = ; //后序遍历
//virtual void postOrder(NodePointer tree) = 0; virtual void destroy() = ; //释放整棵树
//virtual void destroy(NodePointer tree) = 0; protected:
NodePointer root; }; #endif

  二叉搜索树的类定义为:

 #include "tree.h"

 template<class T>
class BSTree : public Tree<T>
{
public:
BSTree();
virtual ~BSTree();
BSTree(const BSTree& orig);
BSTree& operator=(const BSTree& orig);
virtual bool isEmpty(); // 判断树是否为空
virtual void creatTree(T * k, T * arr, unsigned len); // 初始化树
virtual bool addNode(T k, T val); // 添加节点
virtual bool delNode(T k); // 删除节点 virtual unsigned int getHeight(); // 获得树的高度 virtual T getMinimum(); // 获取树中的最小值
virtual T getMaxmum(); // 获取树中的最大值 virtual Node<T> * searchNode(T k); // 搜索key为k的节点
virtual Node<T> * getPredecessor(T k); // 获取某节点(key为k)的前驱节点
virtual Node<T> * getSuccessor(T k); // 获取某节点(key为k)的后继节点 virtual void preOrder(); // 先序遍历
virtual void inOrder(); // 中序遍历
virtual void postOrder(); // 后序遍历 virtual void destroy(); // 释放整棵树 protected:
void preOrder(NodePointer tree); // 先序遍历
void inOrder(NodePointer tree); // 中序遍历
void postOrder(NodePointer tree); // 后序遍历
unsigned int getHeight(NodePointer tree); // 获得树的高度
void destroy(NodePointer tree); // 释放整棵树 // 辅助单元测试
public:
// 单元测试用,模板友元函数
template<class T>
friend T getTestData(const BSTree<T>& tree, int pos); private:
int count;
T testData[]; };

  完整实现程序:

 // Blog: http://www.cnblogs.com/xiehongfeng100/p/4093815.html 

 #ifndef BSTREE_H
#define BSTREE_H #include "tree.h" template<class T>
class BSTree : public Tree<T>
{
public:
BSTree();
virtual ~BSTree();
BSTree(const BSTree& orig);
BSTree& operator=(const BSTree& orig);
virtual bool isEmpty(); // 判断树是否为空
virtual void creatTree(T * k, T * arr, unsigned len); // 初始化树
virtual bool addNode(T k, T val); // 添加节点
virtual bool delNode(T k); // 删除节点 virtual unsigned int getHeight(); // 获得树的高度 virtual T getMinimum(); // 获取树中的最小值
virtual T getMaxmum(); // 获取树中的最大值 virtual Node<T> * searchNode(T k); // 搜索key为k的节点
virtual Node<T> * getPredecessor(T k); // 获取某节点(key为k)的前驱节点
virtual Node<T> * getSuccessor(T k); // 获取某节点(key为k)的后继节点 virtual void preOrder(); // 先序遍历
virtual void inOrder(); // 中序遍历
virtual void postOrder(); // 后序遍历 virtual void destroy(); // 释放整棵树 protected:
void preOrder(NodePointer tree); // 先序遍历
void inOrder(NodePointer tree); // 中序遍历
void postOrder(NodePointer tree); // 后序遍历
unsigned int getHeight(NodePointer tree); // 获得树的高度
void destroy(NodePointer tree); // 释放整棵树 // 辅助单元测试
public:
// 单元测试用,模板友元函数. 需要注意的是友元函数并没有this指针
template<class T>
friend T getTestData(const BSTree<T>& tree, int pos); private:
int count;
T testData[]; }; template<class T>
BSTree<T>::BSTree()
{
root = NULL;
} template<class T>
BSTree<T>::~BSTree()
{
destroy(root);
root = NULL; // 以防root成为“野指针”
} template<class T>
BSTree<T>::BSTree(const BSTree& orig)
{
// leave blank
} template<class T>
BSTree<T>& BSTree<T>::operator=(const BSTree& orig)
{
// leave blank
return *this;
} template<class T>
bool BSTree<T>::isEmpty()
{
return root == NULL;
} template<class T>
void BSTree<T>::creatTree(T * k, T * arr, unsigned len)
{
for (int i = ; i < len; i++)
{
addNode(k[i], arr[i]);
}
} template<class T>
unsigned BSTree<T>::getHeight()
{
return getHeight(root);
} template<class T>
unsigned BSTree<T>::getHeight(NodePointer tree)
{
if (tree == NULL)
{
return ;
}
else
{
int m = getHeight(tree->left);
int n = getHeight(tree->right);
return (m > n) ? (m + ) : (n + );
} } template<class T>
bool BSTree<T>::addNode(T k, T val)
{
bool isSuccess = true;
// to allocate memory
// method 1
NodePointer ptr = new(nothrow) Node<T>();
if (ptr == NULL)
{
return false;
}
// method 2
//NodePointer ptr;
//try
//{
// ptr = new Node<T>();
//}
//catch (bad_alloc* e)
//{
// return false;
//}
//catch (exception* e)
//{
// return false;
//}
ptr->key = k;
ptr->data = val;
if (root == NULL)
{
root = ptr;
root->parent = NULL;
}
else
{
NodePointer tmpPtr = root;
while (tmpPtr != NULL)
{
if (k == tmpPtr->key)
{
// 如果关键字重复,则添加失败,且释放已经申请到的内存
isSuccess = false;
delete ptr;
break;
}
else if (k < tmpPtr->key)
{
if (tmpPtr->left == NULL)
{
tmpPtr->left = ptr;
ptr->parent = tmpPtr;
break;
}
else
{
tmpPtr = tmpPtr->left;
}
}
else
{
if (tmpPtr->right == NULL)
{
tmpPtr->right = ptr;
ptr->parent = tmpPtr;
break;
}
else
{
tmpPtr = tmpPtr->right;
}
}
}
} return isSuccess;
} template<class T>
bool BSTree<T>::delNode(T k)
{
bool isSuccess = true;
NodePointer delNodePtr = searchNode(k);
if (delNodePtr == NULL)
{
isSuccess = false;
}
else
{
// 删除的节点没有子树
if (delNodePtr->left == NULL && delNodePtr->right == NULL)
{
// 如果是根节点
if (delNodePtr == root)
{
root = NULL;
}
// 如果不是根节点
else
{
NodePointer parentPtr = delNodePtr->parent;
if (parentPtr->left == delNodePtr)
{
parentPtr->left = NULL;
}
else
{
parentPtr->right = NULL;
}
} delete delNodePtr;
delNodePtr = NULL;
} // 删除的节点只有一个子树
else if (delNodePtr->left == NULL || delNodePtr->right == NULL)
{
NodePointer tmp = NULL;
// 如果是根节点
if (delNodePtr == root)
{
if (delNodePtr->left == NULL)
{
tmp = delNodePtr->right;
}
else
{
tmp = delNodePtr->left;
}
tmp->parent = NULL;
root = tmp;
}
// 如果不是根节点
else
{
NodePointer parentPtr = delNodePtr->parent;
if (parentPtr->left == delNodePtr)
{
parentPtr->left = (delNodePtr->left == NULL) ? delNodePtr->right : delNodePtr->left;
tmp = parentPtr->left;
}
else
{
parentPtr->right = (delNodePtr->left == NULL) ? delNodePtr->right : delNodePtr->left;
tmp = parentPtr->right;
}
tmp->parent = parentPtr;
} delete delNodePtr;
delNodePtr = NULL;
} // 删除的节点有两个子树
else
{
NodePointer successor = getSuccessor(delNodePtr->data);
if (successor == delNodePtr->right)
delNodePtr->right = nullptr;
else
(successor->parent)->left = nullptr; successor->right = delNodePtr->right;
successor->left = delNodePtr->left;
(delNodePtr->left)->parent = successor;
if (delNodePtr->right != nullptr)
(delNodePtr->right)->parent = successor; // 如果待删节点是根节点
if (delNodePtr == root)
{
successor->parent = nullptr;
root = successor;
}
else
{
NodePointer parentPtr = delNodePtr->parent;
// 判断待删节点是其父节点的左节点还是右节点
if (delNodePtr == parentPtr->left)
parentPtr->left = successor; else
parentPtr->right = successor;
successor->parent = parentPtr;
}
// 释放待删节点内存
delete delNodePtr;
delNodePtr = NULL;
}
} return isSuccess;
} template<class T>
T BSTree<T>::getMinimum()
{
NodePointer tmpPtr = root, ptr = NULL;
while (tmpPtr != NULL)
{
ptr = tmpPtr;
tmpPtr = tmpPtr->left;
}
return ptr->data;
} template<class T>
T BSTree<T>::getMaxmum()
{
NodePointer tmpPtr = root, ptr = NULL;
while (tmpPtr != NULL)
{
ptr = tmpPtr;
tmpPtr = tmpPtr->right;
}
return ptr->data;
} template<class T>
Node<T> * BSTree<T>::searchNode(T k)
{
// 优先判断树是否为空
if (root == NULL)
{
return NULL;
} NodePointer ptr = NULL, tmpPtr = root;
while (tmpPtr != NULL)
{
if (k == tmpPtr->key)
{
ptr = tmpPtr;
break;
}
else if (k < tmpPtr->key)
{
if (tmpPtr->left == NULL)
{
break;
}
else
{
tmpPtr = tmpPtr->left;
}
}
else
{
if (tmpPtr->right == NULL)
{
break;
}
else
{
tmpPtr = tmpPtr->right;
}
}
} return ptr;
} template<class T>
Node<T> * BSTree<T>::getPredecessor(T k)
{
NodePointer tmpPtr = searchNode(k), ptr = NULL;
if (tmpPtr != NULL)
{
if (tmpPtr == root)
{
ptr = NULL;
}
else if (tmpPtr->left != NULL)
{
NodePointer bakPtr = NULL;
ptr = tmpPtr->left;
while (ptr != NULL)
{
bakPtr = ptr;
ptr = ptr->right;
}
ptr = bakPtr;
}
else
{
ptr = tmpPtr->parent;
}
} return ptr;
} template<class T>
Node<T> * BSTree<T>::getSuccessor(T k)
{
NodePointer tmpPtr = searchNode(k), ptr = NULL;
if (tmpPtr != NULL)
{
if (tmpPtr == root && tmpPtr->right == NULL)
{
ptr = NULL;
}
else if (tmpPtr->right != NULL)
{
NodePointer bakPtr = NULL;
ptr = tmpPtr->right;
while (ptr != NULL)
{
bakPtr = ptr;
ptr = ptr->left;
}
ptr = bakPtr;
}
else
{
ptr = tmpPtr->parent;
while (ptr->key < tmpPtr->key)
{
ptr = ptr->parent;
// 如果找到根节点仍找不到
if (ptr == root && ptr->key < tmpPtr->key)
{
ptr = NULL;
break;
}
}
}
} return ptr;
} template<class T>
void BSTree<T>::preOrder()
{
count = ;
preOrder(root);
} template<class T>
void BSTree<T>::preOrder(NodePointer tree)
{
if (tree != NULL) // 注意这里不是用while循环
{
// cout << tmpPtr->data << end;
testData[count] = tree->data;
count++;
preOrder(tree->left);
preOrder(tree->right);
}
} // 中序遍历的输出是按从小到大的排序的
template<class T>
void BSTree<T>::inOrder()
{
count = ;
inOrder(root);
} template<class T>
void BSTree<T>::inOrder(NodePointer tree)
{
if (tree != NULL)
{
inOrder(tree->left);
// cout << tmpPtr->data << end;
testData[count] = tree->data;
count++;
inOrder(tree->right);
}
} template<class T>
void BSTree<T>::postOrder()
{
count = ;
postOrder(root);
} template<class T>
void BSTree<T>::postOrder(NodePointer tree)
{
if (tree != NULL)
{
postOrder(tree->left);
postOrder(tree->right);
// cout << tmpPtr->data << end;
testData[count] = tree->data;
count++;
}
} template<class T>
void BSTree<T>::destroy()
{
destroy(root);
root = NULL;
} template<class T>
void BSTree<T>::destroy(NodePointer tree)
{
NodePointer leftPtr = NULL, rightPtr = NULL;
if (tree != NULL)
{
leftPtr = tree->left;
rightPtr = tree->right;
delete tree;
tree = NULL; // 这一句十分重要。因为tree被释放后成为一个
// “野指针”,即不是NULL指针,因此会让while循环
// 在释放完所有的内存后再循环一次,而此时tree
// 已经是一个“野指针”,对它再进行内存释放必然出错
destroy(leftPtr);
destroy(rightPtr);
}
} // 模板友元函数
template<class T>
T getTestData(const BSTree<T>& tree, int pos)
{
return tree.testData[pos];
} #endif

BSTree.hpp

  Boost单元测试程序:

 #define BOOST_TEST_MODULE Tree_Test_Module

 #include "stdafx.h"
#include "../AVLTree/BSTree.hpp" struct BSTree_Fixture
{
public:
BSTree_Fixture()
{
testBSTree = new BSTree<int>();
}
~BSTree_Fixture()
{
delete testBSTree;
} BSTree<int> * testBSTree;
}; BOOST_FIXTURE_TEST_SUITE(BSTree_Test_Suite, BSTree_Fixture) BOOST_AUTO_TEST_CASE(BSTree_Normal_Test)
{
// isEmpty & getHight-----------------------------
BOOST_REQUIRE(testBSTree->isEmpty() == true);
BOOST_REQUIRE(testBSTree->getHeight() == ); // addNode & searchNode ---------------------------
BOOST_REQUIRE(testBSTree->addNode(, ) == true);
BOOST_REQUIRE(testBSTree->searchNode() != NULL);
BOOST_REQUIRE((testBSTree->searchNode())->data == );
BOOST_REQUIRE(testBSTree->isEmpty() == false);
BOOST_REQUIRE(testBSTree->getHeight() == ); BOOST_REQUIRE(testBSTree->addNode(, ) == true);
BOOST_REQUIRE(testBSTree->searchNode() != NULL);
BOOST_REQUIRE((testBSTree->searchNode())->data == );
BOOST_REQUIRE(testBSTree->getHeight() == ); BOOST_REQUIRE(testBSTree->addNode(, ) == true);
BOOST_REQUIRE(testBSTree->searchNode() != NULL);
BOOST_REQUIRE((testBSTree->searchNode())->data == );
BOOST_REQUIRE(testBSTree->getHeight() == ); BOOST_REQUIRE(testBSTree->addNode(, ) == true);
BOOST_REQUIRE(testBSTree->searchNode() != NULL);
BOOST_REQUIRE((testBSTree->searchNode())->data == );
BOOST_REQUIRE(testBSTree->getHeight() == ); // getMinimum & getMaxmum ----------------------
BOOST_REQUIRE(testBSTree->getMinimum() == );
BOOST_REQUIRE(testBSTree->getMaxmum() == ); // preOrder ------------------------------------
testBSTree->preOrder();
BOOST_REQUIRE(getTestData(*testBSTree, ) == );
BOOST_REQUIRE(getTestData(*testBSTree, ) == );
BOOST_REQUIRE(getTestData(*testBSTree, ) == );
BOOST_REQUIRE(getTestData(*testBSTree, ) == ); // inOrder -------------------------------------
testBSTree->inOrder();
BOOST_REQUIRE(getTestData(*testBSTree, ) == );
BOOST_REQUIRE(getTestData(*testBSTree, ) == );
BOOST_REQUIRE(getTestData(*testBSTree, ) == );
BOOST_REQUIRE(getTestData(*testBSTree, ) == ); // postOrder -----------------------------------
testBSTree->postOrder();
BOOST_REQUIRE(getTestData(*testBSTree, ) == );
BOOST_REQUIRE(getTestData(*testBSTree, ) == );
BOOST_REQUIRE(getTestData(*testBSTree, ) == );
BOOST_REQUIRE(getTestData(*testBSTree, ) == ); // destroy -------------------------------------
testBSTree->destroy(); // creatBSTree --------------------------------
int key[] = { , , , , , , , , , , };
int value[] = { , , , , , , , , , , };
unsigned len = sizeof(key) / sizeof(int);
testBSTree->creatTree(key, value, len); // getPredecessor ------------------------------
BOOST_REQUIRE(testBSTree->getPredecessor() == NULL);
BOOST_REQUIRE((testBSTree->getPredecessor())->data == );
BOOST_REQUIRE((testBSTree->getPredecessor())->data == ); // getSuccessor --------------------------------
BOOST_REQUIRE(testBSTree->getSuccessor()->data == );
BOOST_REQUIRE(testBSTree->getSuccessor()->data == );
BOOST_REQUIRE(testBSTree->getSuccessor()->data == );
BOOST_REQUIRE(testBSTree->getSuccessor() == NULL); } BOOST_AUTO_TEST_CASE(BSTree_delNode_Test)
{
// creatBSTree --------------------------------
int key[] = { , , , , , , , , , , };
int value[] = { , , , , , , , , , , };
unsigned len = sizeof(key) / sizeof(int);
testBSTree->creatTree(key, value, len); // delNode ----------------------------------
// delete root with two children
Node<int> * treeRoot = testBSTree->searchNode();
BOOST_REQUIRE((treeRoot->left)->data == );
BOOST_REQUIRE((treeRoot->right)->data == );
BOOST_REQUIRE(testBSTree->delNode() == true); BOOST_REQUIRE(testBSTree->searchNode() == NULL);
treeRoot = testBSTree->searchNode();
BOOST_REQUIRE((treeRoot->left)->data == );
BOOST_REQUIRE((treeRoot->right)->data == ); // delete node (not root) with two children
Node<int> * treeNode = testBSTree->searchNode();
BOOST_REQUIRE((treeNode->left)->data == );
BOOST_REQUIRE((treeNode->right)->data == );
BOOST_REQUIRE(testBSTree->delNode() == true); treeNode = testBSTree->searchNode();
BOOST_REQUIRE((treeNode->left)->data == );
BOOST_REQUIRE((treeNode->right)->data == ); // delete node with only one left child
treeNode = testBSTree->searchNode();
BOOST_REQUIRE((treeNode->left)->data == );
BOOST_REQUIRE(treeNode->right == NULL);
BOOST_REQUIRE(testBSTree->delNode() == true); BOOST_REQUIRE(testBSTree->searchNode() == NULL);
treeNode = testBSTree->searchNode();
BOOST_REQUIRE((treeNode->left)->data == );
BOOST_REQUIRE((treeNode->right)->data == ); // delete node with two children (right->right, without any left child)
treeNode = testBSTree->searchNode();
BOOST_REQUIRE((treeNode->parent)->data == );
BOOST_REQUIRE(treeNode->left == NULL);
BOOST_REQUIRE((treeNode->right)->data == );
BOOST_REQUIRE(testBSTree->delNode() == true); treeNode = testBSTree->searchNode();
BOOST_REQUIRE((treeNode->parent)->data == );
BOOST_REQUIRE(treeNode->left == NULL);
BOOST_REQUIRE((treeNode->right)->data == ); // delete node with only one right child
BOOST_REQUIRE(testBSTree->delNode() == true); treeNode = testBSTree->searchNode();
BOOST_REQUIRE((treeNode->parent)->data == );
BOOST_REQUIRE(treeNode->left == NULL);
BOOST_REQUIRE(treeNode->right == NULL); BOOST_REQUIRE(testBSTree->delNode() == true); // delete root with only left tree
treeNode = testBSTree->searchNode();
BOOST_REQUIRE((treeNode->parent)->data == );
BOOST_REQUIRE(testBSTree->delNode() == true); treeNode = testBSTree->searchNode();
BOOST_REQUIRE(treeNode->parent == NULL); // delete other noods
BOOST_REQUIRE(testBSTree->delNode() == true);
BOOST_REQUIRE(testBSTree->delNode() == true);
BOOST_REQUIRE(testBSTree->delNode() == true); // delete root with left or right child
treeNode = testBSTree->searchNode();
BOOST_REQUIRE(treeNode->left == NULL);
BOOST_REQUIRE(treeNode->right == NULL);
BOOST_REQUIRE(testBSTree->delNode() == true); BOOST_REQUIRE(testBSTree->searchNode() == NULL); } //BOOST_AUTO_TEST_CASE(BSTree_CopyConstructor_Test)
//{
// // leave blank
//}
//
//BOOST_AUTO_TEST_CASE(BSTree_EqualOperator_Test)
//{
// // leave blank
//} BOOST_AUTO_TEST_SUITE_END()

BSTreeUnitTest

  本篇博文的代码均托管到Github.