"《算法导论》之‘树’":二叉查找树
树的介绍部分摘取自博文二叉查找树(一)、二叉查找树(二)、二叉查找树。
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的过程:(查找过程每次在左右子树中做出选择,减少一半的工作量)
《算法导论》中给出的递归和非递归的伪代码如下:
1 TREE_SEARCH(x,k) 2 if x=NULL or k=key[x] 3 then return x 4 if(k<key[x]) 5 then return TREE_SEARCH(left[x],k) 6 else 7 then return TREE_SEARCH(right[x],k)
1 ITERATIVE_TREE_SEARCH(x,k) 2 while x!=NULL and k!=key[x] 3 do if k<key[x] 4 then x=left[x] 5 else 6 then x=right[x] 7 return x
3.2 查找最大关键字和最小关键字
根据二叉查找树的特征,很容易查找出最大和最小关键字。查找二叉树中的最小关键字:从根结点开始,沿着各个节点的left指针查找下去,直到遇到NULL时结束。如果一个结点x无左子树,则以x为根的子树中,最小关键字就是key[x]。查找二叉树中的最大关键字:从根结点开始,沿着各个结点的right指针查找下去,直到遇到NULL时结束。书中给出了查找最大最小关键字的伪代码:
《算法导论》中给出的伪代码如下:
1 TREE_MINMUM(x) 2 while left[x] != NULL 3 do x=left[x] 4 return x
1 TREE_MAXMUM(x) 2 while right[x] != NULL 3 do x= right[x] 4 return x
3.3 前驱和后继
给定一个二叉查找树中的结点,找出在中序遍历顺序下某个节点的前驱和后继。如果树中所有关键字都不相同,则某一结点x的前驱就是小于key[x]的所有关键字中最大的那个结点,后继即是大于key[x]中的所有关键字中最小的那个结点。根据二叉查找树的结构和性质,不用对关键字做任何比较,就可以找到某个结点的前驱和后继。
查找前驱步骤:先判断x是否有左子树,如果有则在left[x]中查找关键字最大的结点,即是x的前驱。如果没有左子树,则从x继续向上执行此操作,直到遇到某个结点是其父节点的右孩子结点。例如下图查找结点7的前驱结点6过程:
查找后继步骤:先判断x是否有右子树,如果有则在right[x]中查找关键字最小的结点,即使x的后继。如果没有右子树,则从x的父节点开始向上查找,直到遇到某个结点是其父结点的左儿子的结点时为止。例如下图查找结点13的后继结点15的过程:
《算法导论》中中给出了求x结点后继结点的伪代码:
1 TREE_PROCESSOR(x) 2 if right[x] != NULL 3 then return TREE_MINMUM(right(x)) 4 y=parent[x] 5 while y!= NULL and x ==right[y] 6 do x = y 7 y=parent[y] 8 return y
定理:对一棵高度为h的二叉查找,动态集合操作SEARCH、MINMUM、MAXMUM、SUCCESSOR、PROCESSOR等的运行时间均为O(h)。
3.4 插入和删除
插入和删除会引起二叉查找表示的动态集合的变化,难点在在插入和删除的过程中要保持二叉查找树的性质。插入过程相当来说要简单一些,删除结点比较复杂。
(1)插入
插入结点的位置对应着查找过程中查找不成功时候的结点位置,因此需要从根结点开始查找带插入结点位置,找到位置后插入即可。下图所示插入结点过程:
《算法导论》中给出了插入过程的伪代码:
1 TREE_INSERT(T, z) 2 y = NULL; 3 x = root[T] 4 while x != NULL 5 do y = x 6 if key[z] < key[x] 7 then x = left[x] 8 else 9 x = right[x] 10 parent[z] = y 11 if y = NULL 12 then root[T] = z 13 else if key[z]>key[y] 14 then keft[y] = z 15 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的新的左子树。
《算法导论》中给出了删除过程的伪代码:
1 TREE_DELETE(T, z) 2 if left[z] == NULL or right[z] == NULL 3 then y = z 4 else y = TREE_SUCCESSOR(z) 5 6 if left[y] != NULL 7 then x = left[y] 8 else x = right[y] 9 10 if x != NULL 11 then parent[x] = parent[y] 12 if p[y] == NULL 13 then root[T] = x 14 else if y = left[[prarnt[y]] 15 then left[parent[y]] = x 16 else right[parent[y]] = x 17 18 if y != z 19 then key[z] = key[y] 20 copy y's data into z 21 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”如下:
1 #ifndef TREE_H 2 #define TREE_H 3 4 #include <iostream> 5 #include <cassert> 6 using namespace std; 7 8 template<class T> 9 class Node 10 { 11 public: 12 Node() : height(0), parent(NULL), left(NULL), right(NULL){}; 13 ~Node(){}; 14 15 public: 16 T key; 17 T data; 18 unsigned int height; 19 Node * parent; 20 Node * left; 21 Node * right; 22 23 }; 24 25 template<class T> 26 class Tree 27 { 28 public: 29 typedef Node<T> * NodePointer; 30 31 public: 32 Tree(){}; 33 virtual ~Tree(){}; 34 //Tree(const Tree& orig){}; 35 //Tree& operator=(const Tree& orig){}; 36 virtual bool isEmpty() = 0; // 判断树是否为空 37 virtual void creatTree(T * k, T * arr, unsigned len) = 0; // 初始化树 38 virtual bool addNode(T k, T val) = 0; // 添加节点 39 virtual bool delNode(T k) = 0; // 删除节点 40 41 virtual unsigned int getHeight() = 0; // 获得树的高度 42 //virtual unsigned int getHeight(NodePointer tree) = 0; 43 44 virtual T getMinimum() = 0; // 获取树中的最小值 45 virtual T getMaxmum() = 0; // 获取树中的最大值 46 47 virtual Node<T> * searchNode(T k) = 0; // 搜索key为k的节点 48 virtual Node<T> * getPredecessor(T k) = 0; // 获取某节点(key为k)的前驱节点 49 virtual Node<T> * getSuccessor(T k) = 0; // 获取某节点(key为k)的后继节点 50 51 virtual void preOrder() = 0; //先序遍历 52 //virtual void preOrder(NodePointer tree) = 0; 53 virtual void inOrder() = 0; //中序遍历 54 //virtual void inOrder(NodePointer tree) = 0; 55 virtual void postOrder() = 0; //后序遍历 56 //virtual void postOrder(NodePointer tree) = 0; 57 58 virtual void destroy() = 0; //释放整棵树 59 //virtual void destroy(NodePointer tree) = 0; 60 61 protected: 62 NodePointer root; 63 64 }; 65 66 #endif
二叉搜索树的类定义为:
1 #include "tree.h" 2 3 template<class T> 4 class BSTree : public Tree<T> 5 { 6 public: 7 BSTree(); 8 virtual ~BSTree(); 9 BSTree(const BSTree& orig); 10 BSTree& operator=(const BSTree& orig); 11 virtual bool isEmpty(); // 判断树是否为空 12 virtual void creatTree(T * k, T * arr, unsigned len); // 初始化树 13 virtual bool addNode(T k, T val); // 添加节点 14 virtual bool delNode(T k); // 删除节点 15 16 virtual unsigned int getHeight(); // 获得树的高度 17 18 virtual T getMinimum(); // 获取树中的最小值 19 virtual T getMaxmum(); // 获取树中的最大值 20 21 virtual Node<T> * searchNode(T k); // 搜索key为k的节点 22 virtual Node<T> * getPredecessor(T k); // 获取某节点(key为k)的前驱节点 23 virtual Node<T> * getSuccessor(T k); // 获取某节点(key为k)的后继节点 24 25 virtual void preOrder(); // 先序遍历 26 virtual void inOrder(); // 中序遍历 27 virtual void postOrder(); // 后序遍历 28 29 virtual void destroy(); // 释放整棵树 30 31 protected: 32 void preOrder(NodePointer tree); // 先序遍历 33 void inOrder(NodePointer tree); // 中序遍历 34 void postOrder(NodePointer tree); // 后序遍历 35 unsigned int getHeight(NodePointer tree); // 获得树的高度 36 void destroy(NodePointer tree); // 释放整棵树 37 38 39 // 辅助单元测试 40 public: 41 // 单元测试用,模板友元函数 42 template<class T> 43 friend T getTestData(const BSTree<T>& tree, int pos); 44 45 private: 46 int count; 47 T testData[1024]; 48 49 };
完整实现程序:
1 // Blog: http://www.cnblogs.com/xiehongfeng100/p/4093815.html 2 3 4 #ifndef BSTREE_H 5 #define BSTREE_H 6 7 #include "tree.h" 8 9 template<class T> 10 class BSTree : public Tree<T> 11 { 12 public: 13 BSTree(); 14 virtual ~BSTree(); 15 BSTree(const BSTree& orig); 16 BSTree& operator=(const BSTree& orig); 17 virtual bool isEmpty(); // 判断树是否为空 18 virtual void creatTree(T * k, T * arr, unsigned len); // 初始化树 19 virtual bool addNode(T k, T val); // 添加节点 20 virtual bool delNode(T k); // 删除节点 21 22 virtual unsigned int getHeight(); // 获得树的高度 23 24 virtual T getMinimum(); // 获取树中的最小值 25 virtual T getMaxmum(); // 获取树中的最大值 26 27 virtual Node<T> * searchNode(T k); // 搜索key为k的节点 28 virtual Node<T> * getPredecessor(T k); // 获取某节点(key为k)的前驱节点 29 virtual Node<T> * getSuccessor(T k); // 获取某节点(key为k)的后继节点 30 31 virtual void preOrder(); // 先序遍历 32 virtual void inOrder(); // 中序遍历 33 virtual void postOrder(); // 后序遍历 34 35 virtual void destroy(); // 释放整棵树 36 37 protected: 38 void preOrder(NodePointer tree); // 先序遍历 39 void inOrder(NodePointer tree); // 中序遍历 40 void postOrder(NodePointer tree); // 后序遍历 41 unsigned int getHeight(NodePointer tree); // 获得树的高度 42 void destroy(NodePointer tree); // 释放整棵树 43 44 // 辅助单元测试 45 public: 46 // 单元测试用,模板友元函数. 需要注意的是友元函数并没有this指针 47 template<class T> 48 friend T getTestData(const BSTree<T>& tree, int pos); 49 50 private: 51 int count; 52 T testData[1024]; 53 54 }; 55 56 template<class T> 57 BSTree<T>::BSTree() 58 { 59 root = NULL; 60 } 61 62 template<class T> 63 BSTree<T>::~BSTree() 64 { 65 destroy(root); 66 root = NULL; // 以防root成为“野指针” 67 } 68 69 template<class T> 70 BSTree<T>::BSTree(const BSTree& orig) 71 { 72 // leave blank 73 } 74 75 76 template<class T> 77 BSTree<T>& BSTree<T>::operator=(const BSTree& orig) 78 { 79 // leave blank 80 return *this; 81 } 82 83 template<class T> 84 bool BSTree<T>::isEmpty() 85 { 86 return root == NULL; 87 } 88 89 template<class T> 90 void BSTree<T>::creatTree(T * k, T * arr, unsigned len) 91 { 92 for (int i = 0; i < len; i++) 93 { 94 addNode(k[i], arr[i]); 95 } 96 } 97 98 template<class T> 99 unsigned BSTree<T>::getHeight() 100 { 101 return getHeight(root); 102 } 103 104 template<class T> 105 unsigned BSTree<T>::getHeight(NodePointer tree) 106 { 107 if (tree == NULL) 108 { 109 return 0; 110 } 111 else 112 { 113 int m = getHeight(tree->left); 114 int n = getHeight(tree->right); 115 return (m > n) ? (m + 1) : (n + 1); 116 } 117 118 } 119 120 template<class T> 121 bool BSTree<T>::addNode(T k, T val) 122 { 123 bool isSuccess = true; 124 // to allocate memory 125 // method 1 126 NodePointer ptr = new(nothrow) Node<T>(); 127 if (ptr == NULL) 128 { 129 return false; 130 } 131 // method 2 132 //NodePointer ptr; 133 //try 134 //{ 135 // ptr = new Node<T>(); 136 //} 137 //catch (bad_alloc* e) 138 //{ 139 // return false; 140 //} 141 //catch (exception* e) 142 //{ 143 // return false; 144 //} 145 ptr->key = k; 146 ptr->data = val; 147 if (root == NULL) 148 { 149 root = ptr; 150 root->parent = NULL; 151 } 152 else 153 { 154 NodePointer tmpPtr = root; 155 while (tmpPtr != NULL) 156 { 157 if (k == tmpPtr->key) 158 { 159 // 如果关键字重复,则添加失败,且释放已经申请到的内存 160 isSuccess = false; 161 delete ptr; 162 break; 163 } 164 else if (k < tmpPtr->key) 165 { 166 if (tmpPtr->left == NULL) 167 { 168 tmpPtr->left = ptr; 169 ptr->parent = tmpPtr; 170 break; 171 } 172 else 173 { 174 tmpPtr = tmpPtr->left; 175 } 176 } 177 else 178 { 179 if (tmpPtr->right == NULL) 180 { 181 tmpPtr->right = ptr; 182 ptr->parent = tmpPtr; 183 break; 184 } 185 else 186 { 187 tmpPtr = tmpPtr->right; 188 } 189 } 190 } 191 } 192 193 return isSuccess; 194 } 195 196 template<class T> 197 bool BSTree<T>::delNode(T k) 198 { 199 bool isSuccess = true; 200 NodePointer delNodePtr = searchNode(k); 201 if (delNodePtr == NULL) 202 { 203 isSuccess = false; 204 } 205 else 206 { 207 // 删除的节点没有子树 208 if (delNodePtr->left == NULL && delNodePtr->right == NULL) 209 { 210 // 如果是根节点 211 if (delNodePtr == root) 212 { 213 root = NULL; 214 } 215 // 如果不是根节点 216 else 217 { 218 NodePointer parentPtr = delNodePtr->parent; 219 if (parentPtr->left == delNodePtr) 220 { 221 parentPtr->left = NULL; 222 } 223 else 224 { 225 parentPtr->right = NULL; 226 } 227 } 228 229 delete delNodePtr; 230 delNodePtr = NULL; 231 } 232 233 // 删除的节点只有一个子树 234 else if (delNodePtr->left == NULL || delNodePtr->right == NULL) 235 { 236 NodePointer tmp = NULL; 237 // 如果是根节点 238 if (delNodePtr == root) 239 { 240 if (delNodePtr->left == NULL) 241 { 242 tmp = delNodePtr->right; 243 } 244 else 245 { 246 tmp = delNodePtr->left; 247 } 248 tmp->parent = NULL; 249 root = tmp; 250 } 251 // 如果不是根节点 252 else 253 { 254 NodePointer parentPtr = delNodePtr->parent; 255 if (parentPtr->left == delNodePtr) 256 { 257 parentPtr->left = (delNodePtr->left == NULL) ? delNodePtr->right : delNodePtr->left; 258 tmp = parentPtr->left; 259 } 260 else 261 { 262 parentPtr->right = (delNodePtr->left == NULL) ? delNodePtr->right : delNodePtr->left; 263 tmp = parentPtr->right; 264 } 265 tmp->parent = parentPtr; 266 } 267 268 delete delNodePtr; 269 delNodePtr = NULL; 270 } 271 272 // 删除的节点有两个子树 273 else 274 { 275 NodePointer successor = getSuccessor(delNodePtr->data); 276 if (successor == delNodePtr->right) 277 delNodePtr->right = nullptr; 278 else 279 (successor->parent)->left = nullptr; 280 281 successor->right = delNodePtr->right; 282 successor->left = delNodePtr->left; 283 (delNodePtr->left)->parent = successor; 284 if (delNodePtr->right != nullptr) 285 (delNodePtr->right)->parent = successor; 286 287 // 如果待删节点是根节点 288 if (delNodePtr == root) 289 { 290 successor->parent = nullptr; 291 root = successor; 292 } 293 else 294 { 295 NodePointer parentPtr = delNodePtr->parent; 296 // 判断待删节点是其父节点的左节点还是右节点 297 if (delNodePtr == parentPtr->left) 298 parentPtr->left = successor; 299 300 else 301 parentPtr->right = successor; 302 successor->parent = parentPtr; 303 } 304 // 释放待删节点内存 305 delete delNodePtr; 306 delNodePtr = NULL; 307 } 308 } 309 310 return isSuccess; 311 } 312 313 template<class T> 314 T BSTree<T>::getMinimum() 315 { 316 NodePointer tmpPtr = root, ptr = NULL; 317 while (tmpPtr != NULL) 318 { 319 ptr = tmpPtr; 320 tmpPtr = tmpPtr->left; 321 } 322 return ptr->data; 323 } 324 325 template<class T> 326 T BSTree<T>::getMaxmum() 327 { 328 NodePointer tmpPtr = root, ptr = NULL; 329 while (tmpPtr != NULL) 330 { 331 ptr = tmpPtr; 332 tmpPtr = tmpPtr->right; 333 } 334 return ptr->data; 335 } 336 337 template<class T> 338 Node<T> * BSTree<T>::searchNode(T k) 339 { 340 // 优先判断树是否为空 341 if (root == NULL) 342 { 343 return NULL; 344 } 345 346 NodePointer ptr = NULL, tmpPtr = root; 347 while (tmpPtr != NULL) 348 { 349 if (k == tmpPtr->key) 350 { 351 ptr = tmpPtr; 352 break; 353 } 354 else if (k < tmpPtr->key) 355 { 356 if (tmpPtr->left == NULL) 357 { 358 break; 359 } 360 else 361 { 362 tmpPtr = tmpPtr->left; 363 } 364 } 365 else 366 { 367 if (tmpPtr->right == NULL) 368 { 369 break; 370 } 371 else 372 { 373 tmpPtr = tmpPtr->right; 374 } 375 } 376 } 377 378 return ptr; 379 } 380 381 template<class T> 382 Node<T> * BSTree<T>::getPredecessor(T k) 383 { 384 NodePointer tmpPtr = searchNode(k), ptr = NULL; 385 if (tmpPtr != NULL) 386 { 387 if (tmpPtr == root) 388 { 389 ptr = NULL; 390 } 391 else if (tmpPtr->left != NULL) 392 { 393 NodePointer bakPtr = NULL; 394 ptr = tmpPtr->left; 395 while (ptr != NULL) 396 { 397 bakPtr = ptr; 398 ptr = ptr->right; 399 } 400 ptr = bakPtr; 401 } 402 else 403 { 404 ptr = tmpPtr->parent; 405 } 406 } 407 408 return ptr; 409 } 410 411 template<class T> 412 Node<T> * BSTree<T>::getSuccessor(T k) 413 { 414 NodePointer tmpPtr = searchNode(k), ptr = NULL; 415 if (tmpPtr != NULL) 416 { 417 if (tmpPtr == root && tmpPtr->right == NULL) 418 { 419 ptr = NULL; 420 } 421 else if (tmpPtr->right != NULL) 422 { 423 NodePointer bakPtr = NULL; 424 ptr = tmpPtr->right; 425 while (ptr != NULL) 426 { 427 bakPtr = ptr; 428 ptr = ptr->left; 429 } 430 ptr = bakPtr; 431 } 432 else 433 { 434 ptr = tmpPtr->parent; 435 while (ptr->key < tmpPtr->key) 436 { 437 ptr = ptr->parent; 438 // 如果找到根节点仍找不到 439 if (ptr == root && ptr->key < tmpPtr->key) 440 { 441 ptr = NULL; 442 break; 443 } 444 } 445 } 446 } 447 448 return ptr; 449 } 450 451 template<class T> 452 void BSTree<T>::preOrder() 453 { 454 count = 0; 455 preOrder(root); 456 } 457 458 template<class T> 459 void BSTree<T>::preOrder(NodePointer tree) 460 { 461 if (tree != NULL) // 注意这里不是用while循环 462 { 463 // cout << tmpPtr->data << end; 464 testData[count] = tree->data; 465 count++; 466 preOrder(tree->left); 467 preOrder(tree->right); 468 } 469 } 470 471 // 中序遍历的输出是按从小到大的排序的 472 template<class T> 473 void BSTree<T>::inOrder() 474 { 475 count = 0; 476 inOrder(root); 477 } 478 479 template<class T> 480 void BSTree<T>::inOrder(NodePointer tree) 481 { 482 if (tree != NULL) 483 { 484 inOrder(tree->left); 485 // cout << tmpPtr->data << end; 486 testData[count] = tree->data; 487 count++; 488 inOrder(tree->right); 489 } 490 } 491 492 template<class T> 493 void BSTree<T>::postOrder() 494 { 495 count = 0; 496 postOrder(root); 497 } 498 499 template<class T> 500 void BSTree<T>::postOrder(NodePointer tree) 501 { 502 if (tree != NULL) 503 { 504 postOrder(tree->left); 505 postOrder(tree->right); 506 // cout << tmpPtr->data << end; 507 testData[count] = tree->data; 508 count++; 509 } 510 } 511 512 template<class T> 513 void BSTree<T>::destroy() 514 { 515 destroy(root); 516 root = NULL; 517 } 518 519 template<class T> 520 void BSTree<T>::destroy(NodePointer tree) 521 { 522 NodePointer leftPtr = NULL, rightPtr = NULL; 523 if (tree != NULL) 524 { 525 leftPtr = tree->left; 526 rightPtr = tree->right; 527 delete tree; 528 tree = NULL; // 这一句十分重要。因为tree被释放后成为一个 529 // “野指针”,即不是NULL指针,因此会让while循环 530 // 在释放完所有的内存后再循环一次,而此时tree 531 // 已经是一个“野指针”,对它再进行内存释放必然出错 532 destroy(leftPtr); 533 destroy(rightPtr); 534 } 535 } 536 537 // 模板友元函数 538 template<class T> 539 T getTestData(const BSTree<T>& tree, int pos) 540 { 541 return tree.testData[pos]; 542 } 543 544 545 #endif
Boost单元测试程序:
1 #define BOOST_TEST_MODULE Tree_Test_Module 2 3 #include "stdafx.h" 4 #include "../AVLTree/BSTree.hpp" 5 6 struct BSTree_Fixture 7 { 8 public: 9 BSTree_Fixture() 10 { 11 testBSTree = new BSTree<int>(); 12 } 13 ~BSTree_Fixture() 14 { 15 delete testBSTree; 16 } 17 18 BSTree<int> * testBSTree; 19 }; 20 21 BOOST_FIXTURE_TEST_SUITE(BSTree_Test_Suite, BSTree_Fixture) 22 23 BOOST_AUTO_TEST_CASE(BSTree_Normal_Test) 24 { 25 // isEmpty & getHight----------------------------- 26 BOOST_REQUIRE(testBSTree->isEmpty() == true); 27 BOOST_REQUIRE(testBSTree->getHeight() == 0); 28 29 // addNode & searchNode --------------------------- 30 BOOST_REQUIRE(testBSTree->addNode(1, 1) == true); 31 BOOST_REQUIRE(testBSTree->searchNode(1) != NULL); 32 BOOST_REQUIRE((testBSTree->searchNode(1))->data == 1); 33 BOOST_REQUIRE(testBSTree->isEmpty() == false); 34 BOOST_REQUIRE(testBSTree->getHeight() == 1); 35 36 BOOST_REQUIRE(testBSTree->addNode(0, 0) == true); 37 BOOST_REQUIRE(testBSTree->searchNode(0) != NULL); 38 BOOST_REQUIRE((testBSTree->searchNode(0))->data == 0); 39 BOOST_REQUIRE(testBSTree->getHeight() == 2); 40 41 BOOST_REQUIRE(testBSTree->addNode(2, 2) == true); 42 BOOST_REQUIRE(testBSTree->searchNode(2) != NULL); 43 BOOST_REQUIRE((testBSTree->searchNode(2))->data == 2); 44 BOOST_REQUIRE(testBSTree->getHeight() == 2); 45 46 BOOST_REQUIRE(testBSTree->addNode(3, 3) == true); 47 BOOST_REQUIRE(testBSTree->searchNode(3) != NULL); 48 BOOST_REQUIRE((testBSTree->searchNode(3))->data == 3); 49 BOOST_REQUIRE(testBSTree->getHeight() == 3); 50 51 // getMinimum & getMaxmum ---------------------- 52 BOOST_REQUIRE(testBSTree->getMinimum() == 0); 53 BOOST_REQUIRE(testBSTree->getMaxmum() == 3); 54 55 // preOrder ------------------------------------ 56 testBSTree->preOrder(); 57 BOOST_REQUIRE(getTestData(*testBSTree, 0) == 1); 58 BOOST_REQUIRE(getTestData(*testBSTree, 1) == 0); 59 BOOST_REQUIRE(getTestData(*testBSTree, 2) == 2); 60 BOOST_REQUIRE(getTestData(*testBSTree, 3) == 3); 61 62 // inOrder ------------------------------------- 63 testBSTree->inOrder(); 64 BOOST_REQUIRE(getTestData(*testBSTree, 0) == 0); 65 BOOST_REQUIRE(getTestData(*testBSTree, 1) == 1); 66 BOOST_REQUIRE(getTestData(*testBSTree, 2) == 2); 67 BOOST_REQUIRE(getTestData(*testBSTree, 3) == 3); 68 69 // postOrder ----------------------------------- 70 testBSTree->postOrder(); 71 BOOST_REQUIRE(getTestData(*testBSTree, 0) == 0); 72 BOOST_REQUIRE(getTestData(*testBSTree, 1) == 3); 73 BOOST_REQUIRE(getTestData(*testBSTree, 2) == 2); 74 BOOST_REQUIRE(getTestData(*testBSTree, 3) == 1); 75 76 // destroy ------------------------------------- 77 testBSTree->destroy(); 78 79 // creatBSTree -------------------------------- 80 int key[] = { 7, 3, 1, 2, 5, 4, 6, 9, 8, 10, 11 }; 81 int value[] = { 7, 3, 1, 2, 5, 4, 6, 9, 8, 10, 11 }; 82 unsigned len = sizeof(key) / sizeof(int); 83 testBSTree->creatTree(key, value, len); 84 85 // getPredecessor ------------------------------ 86 BOOST_REQUIRE(testBSTree->getPredecessor(7) == NULL); 87 BOOST_REQUIRE((testBSTree->getPredecessor(2))->data == 1); 88 BOOST_REQUIRE((testBSTree->getPredecessor(5))->data == 4); 89 90 // getSuccessor -------------------------------- 91 BOOST_REQUIRE(testBSTree->getSuccessor(7)->data == 8); 92 BOOST_REQUIRE(testBSTree->getSuccessor(6)->data == 7); 93 BOOST_REQUIRE(testBSTree->getSuccessor(9)->data == 10); 94 BOOST_REQUIRE(testBSTree->getSuccessor(11) == NULL); 95 96 } 97 98 BOOST_AUTO_TEST_CASE(BSTree_delNode_Test) 99 { 100 // creatBSTree -------------------------------- 101 int key[] = { 7, 3, 1, 0, 5, 4, 6, 9, 8, 10, 11 }; 102 int value[] = { 7, 3, 1, 0, 5, 4, 6, 9, 8, 10, 11 }; 103 unsigned len = sizeof(key) / sizeof(int); 104 testBSTree->creatTree(key, value, len); 105 106 // delNode ---------------------------------- 107 // delete root with two children 108 Node<int> * treeRoot = testBSTree->searchNode(7); 109 BOOST_REQUIRE((treeRoot->left)->data == 3); 110 BOOST_REQUIRE((treeRoot->right)->data == 9); 111 BOOST_REQUIRE(testBSTree->delNode(7) == true); 112 113 BOOST_REQUIRE(testBSTree->searchNode(7) == NULL); 114 treeRoot = testBSTree->searchNode(8); 115 BOOST_REQUIRE((treeRoot->left)->data == 3); 116 BOOST_REQUIRE((treeRoot->right)->data == 9); 117 118 // delete node (not root) with two children 119 Node<int> * treeNode = testBSTree->searchNode(3); 120 BOOST_REQUIRE((treeNode->left)->data == 1); 121 BOOST_REQUIRE((treeNode->right)->data == 5); 122 BOOST_REQUIRE(testBSTree->delNode(3) == true); 123 124 treeNode = testBSTree->searchNode(4); 125 BOOST_REQUIRE((treeNode->left)->data == 1); 126 BOOST_REQUIRE((treeNode->right)->data == 5); 127 128 // delete node with only one left child 129 treeNode = testBSTree->searchNode(1); 130 BOOST_REQUIRE((treeNode->left)->data == 0); 131 BOOST_REQUIRE(treeNode->right == NULL); 132 BOOST_REQUIRE(testBSTree->delNode(1) == true); 133 134 BOOST_REQUIRE(testBSTree->searchNode(1) == NULL); 135 treeNode = testBSTree->searchNode(4); 136 BOOST_REQUIRE((treeNode->left)->data == 0); 137 BOOST_REQUIRE((treeNode->right)->data == 5); 138 139 // delete node with two children (right->right, without any left child) 140 treeNode = testBSTree->searchNode(9); 141 BOOST_REQUIRE((treeNode->parent)->data == 8); 142 BOOST_REQUIRE(treeNode->left == NULL); 143 BOOST_REQUIRE((treeNode->right)->data == 10); 144 BOOST_REQUIRE(testBSTree->delNode(9) == true); 145 146 treeNode = testBSTree->searchNode(10); 147 BOOST_REQUIRE((treeNode->parent)->data == 8); 148 BOOST_REQUIRE(treeNode->left == NULL); 149 BOOST_REQUIRE((treeNode->right)->data == 11); 150 151 // delete node with only one right child 152 BOOST_REQUIRE(testBSTree->delNode(10) == true); 153 154 treeNode = testBSTree->searchNode(11); 155 BOOST_REQUIRE((treeNode->parent)->data == 8); 156 BOOST_REQUIRE(treeNode->left == NULL); 157 BOOST_REQUIRE(treeNode->right == NULL); 158 159 BOOST_REQUIRE(testBSTree->delNode(11) == true); 160 161 // delete root with only left tree 162 treeNode = testBSTree->searchNode(4); 163 BOOST_REQUIRE((treeNode->parent)->data == 8); 164 BOOST_REQUIRE(testBSTree->delNode(8) == true); 165 166 treeNode = testBSTree->searchNode(4); 167 BOOST_REQUIRE(treeNode->parent == NULL); 168 169 // delete other noods 170 BOOST_REQUIRE(testBSTree->delNode(0) == true); 171 BOOST_REQUIRE(testBSTree->delNode(5) == true); 172 BOOST_REQUIRE(testBSTree->delNode(6) == true); 173 174 // delete root with left or right child 175 treeNode = testBSTree->searchNode(4); 176 BOOST_REQUIRE(treeNode->left == NULL); 177 BOOST_REQUIRE(treeNode->right == NULL); 178 BOOST_REQUIRE(testBSTree->delNode(4) == true); 179 180 BOOST_REQUIRE(testBSTree->searchNode(4) == NULL); 181 182 } 183 184 //BOOST_AUTO_TEST_CASE(BSTree_CopyConstructor_Test) 185 //{ 186 // // leave blank 187 //} 188 // 189 //BOOST_AUTO_TEST_CASE(BSTree_EqualOperator_Test) 190 //{ 191 // // leave blank 192 //} 193 194 BOOST_AUTO_TEST_SUITE_END()
本篇博文的代码均托管到Github.