1. 二叉查找树
二叉查找树(Binary Search Tree),也称为二叉搜索树、有序二叉树(ordered binary tree)或排序二叉树(sorted binary tree),是指一棵空树或者具有下列性质的二叉树:
- 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
- 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
- 任意节点的左、右子树也分别为二叉查找树;
- 没有键值相等的节点。
2. 节点类
1 class BSTNode{ 2 public: 3 int data; 4 BSTNode *left; 5 BSTNode *right; 6 BSTNode(int x): 7 data(x), left(NULL), right(NULL){} 8 };
在写代码的过程中发现有的类方法需要经常使用某节点的父节点,所以可以考虑在数据成员中添加父节点 BSTNode* parents ,本文是在BSTree的方法中添加了函数 BSTNode* BSTree::getParents(int value)
3. 二叉搜索树类
1 class BSTree{ 2 public: 3 BSTNode *root; 4 BSTree(): 5 root(NULL){} 6 ~BSTree(){destory(root);} 7 8 // 是否为空 9 bool isEmpty(); 10 // 深度 11 int depth(BSTNode *&proot); 12 // 节点数 13 int size(BSTNode *&proot); 14 // 叶子节点数 15 int leafsize(BSTNode *&proot); 16 17 // 前序遍历 18 void preOrder(BSTNode* &pRoot); 19 // 中序遍历 20 void inOrder(BSTNode* &pRoot); 21 // 后序遍历 22 void postOrder(BSTNode* &pRoot); 23 // 层序遍历 24 void levelOrder(BSTNode* &pRoot); 25 26 // 查找 27 bool search(int value); 28 // 插入 29 void insert(int value); 30 // 删除 31 void remove(int value); 32 33 // 寻找前驱节点 34 BSTNode* predecessor(int value); 35 // 寻找后继节点 36 BSTNode* successor(int value); 37 38 // 最小值 39 int minimum(); 40 // 最大值 41 int maximum(); 42 43 // 销毁BST 44 void destory(BSTNode *&proot); 45 46 private: 47 // 获取value节点的地址 48 BSTNode* getAddr(int value); 49 // 获取value父节点的地址 50 BSTNode* getParents(int value); 51 };
4. 主要方法
对于基本的方法,如深度、节点数、叶子节点数没什么难点;
对于三种遍历方法使用的是经典的递归方法;
对于BST的最大/最小值,主要记住最小值永远在根节点的最左边,最大值永远在根节点的最右边,只需要不停的向最左或最优遍历即可,直到空节点结束(最大最小值也可能是根节点);
BST的难点可能就在节点删除的部分,以下图所示的树为对象,讲一下节点删除:
/* * 62 * / * 58 88 * / / * 47 73 99 * / / * 35 51 93 * / / * 29 37 49 56 * / / * 36 48 50 * */
被删除的节点可能是一下3种情况之一:
1. 叶子节点 2. 只含有左子树或只含有右子树的节点 3. 同时含有左右子树的节点
细分:
1. 叶子节点
1.1 树只含有一个节点,删除叶子节点
如果树只有一个节点,则该节点即是根节点又是叶节点,删除时需要将root置空
1.2 树含有至少2个节点,删除叶子节点
如图上的 29 36 73等,删除叶子节点对BST没有影响,删除即可,同时需要维护指针;
2. 仅有左或者右子树的节点
2.1 仅有左子树的节点,同时该节点是根节点
2.2 仅有左子树的节点,同时该节点非根节点
2.3 仅有右子树的节点,同时该节点是根节点
2.4 仅有右子树的节点,同时该节点非根节点
上述四种情况只需要将待删节点的左右孩子放到待删节点的位置即可,同时注意是不是需要维护根节点
3. 左右子树都有的节点
首先寻找待删节点的直接前驱,然后用直接前驱代替待删节点。如删除47,47的前驱是37,那么将37节点的数据复制到47节点,释放37,同时将35的右孩子指向36,原47节点的右子树不动。
以上具体细节见完整代码
5. 完整代码
1 #include<iostream> 2 #include<vector> 3 #include<queue> 4 using namespace std; 5 6 class BSTNode{ 7 public: 8 int data; 9 BSTNode *left; 10 BSTNode *right; 11 BSTNode(int x): 12 data(x), left(NULL), right(NULL){} 13 }; 14 15 class BSTree{ 16 public: 17 BSTNode *root; 18 BSTree(): 19 root(NULL){} 20 ~BSTree(){destory(root);} 21 22 // 是否为空 23 bool isEmpty(); 24 // 深度 25 int depth(BSTNode *&proot); 26 // 节点数 27 int size(BSTNode *&proot); 28 // 叶子节点数 29 int leafsize(BSTNode *&proot); 30 31 // 前序遍历 32 void preOrder(BSTNode* &pRoot); 33 // 中序遍历 34 void inOrder(BSTNode* &pRoot); 35 // 后序遍历 36 void postOrder(BSTNode* &pRoot); 37 // 层序遍历 38 void levelOrder(BSTNode* &pRoot); 39 40 // 查找 41 bool search(int value); 42 // 插入 43 void insert(int value); 44 // 删除 45 void remove(int value); 46 47 // 寻找前驱节点 48 BSTNode* predecessor(int value); 49 // 寻找后继节点 50 BSTNode* successor(int value); 51 52 // 最小值 53 int minimum(); 54 // 最大值 55 int maximum(); 56 57 // 销毁BST 58 void destory(BSTNode *&proot); 59 60 private: 61 // 获取value节点的地址 62 BSTNode* getAddr(int value); 63 // 获取value父节点的地址 64 BSTNode* getParents(int value); 65 }; 66 67 bool BSTree::isEmpty(){ 68 return root==NULL; 69 } 70 71 int BSTree::depth(BSTNode *&proot){ 72 if(proot == NULL) 73 return 0; 74 int left = depth(proot->left); 75 int right = depth(proot->right); 76 if(left > right) 77 return left + 1; 78 else 79 return right + 1; 80 } 81 82 int BSTree::size(BSTNode *&proot){ 83 if(proot == NULL) 84 return 0; 85 int left = size(proot->left); 86 int right = size(proot->right); 87 return left + right + 1; 88 } 89 90 int BSTree::leafsize(BSTNode *&proot){ 91 if(proot == NULL) 92 return 0; 93 if(proot->left == NULL && proot->right == NULL) 94 return 1; 95 int leftLeaf = leafsize(proot->left); 96 int rightLeaf = leafsize(proot->right); 97 return leftLeaf + rightLeaf; 98 } 99 100 BSTNode* BSTree::getParents(int value){ 101 if(BSTree::search(value) == true){ 102 BSTNode* pRoot = root; 103 BSTNode* parents; // 用于存储value节点的父节点 104 while(pRoot->data!=value){ 105 parents = pRoot; 106 if(pRoot->data > value) 107 pRoot = pRoot->left; 108 else 109 pRoot = pRoot->right; 110 } 111 if(pRoot == root){ 112 //cout<<"the value is root of the tree, NO PARENTS."<<endl; 113 return NULL; 114 } 115 else 116 return parents; 117 } 118 else{ 119 cout<<"the value is not in the tree."<<endl; 120 return NULL; 121 } 122 } 123 124 BSTNode* BSTree::getAddr(int value){ 125 if(BSTree::search(value) == true){ 126 BSTNode* pRoot = root; 127 while(pRoot->data!=value){ 128 if(pRoot->data > value) 129 pRoot = pRoot->left; 130 else 131 pRoot = pRoot->right; 132 } 133 return pRoot; 134 } 135 else{ 136 cout<<"the value is not in the tree."<<endl; 137 return NULL; 138 } 139 } 140 141 // 若value不在树内或者value没有前驱,返回null,否则,返回前驱节点地址 142 BSTNode* BSTree::predecessor(int value){ 143 if(!search(value)){ 144 cout<<"the value is not in the tree."<<endl; 145 return NULL; 146 } 147 else if(BSTree::minimum() == value){ 148 cout<<"节点"<<value<<"没有前驱节点"<<endl; 149 return NULL; 150 } 151 else{ 152 BSTNode* pRoot = getAddr(value);// 用于存储value节点的地址 153 BSTNode* parents = getParents(value); // 用于存储value的父节点地址 154 // 含左子树的节点 155 if(pRoot->left != NULL){ 156 BSTNode* pre = pRoot->left; 157 while(pre->right != NULL){ 158 pre = pre->right; 159 } 160 return pre; 161 } 162 //没有左子树的节点 163 else{ 164 if(parents->right == pRoot) 165 return parents; 166 else if(parents->left == pRoot){ 167 while(parents->data > value) 168 parents = getParents(parents->data); 169 return parents; 170 } 171 } 172 } 173 } 174 175 // 若value不在树内或者value没有后继,返回null,否则,返回前后继节点地址 176 BSTNode* BSTree::successor(int value){ 177 if(!search(value)){ 178 cout<<"the value is not in the tree."<<endl; 179 return NULL; 180 } 181 else if(BSTree::maximum() == value){ 182 cout<<"节点"<<value<<"没有后继节点"<<endl; 183 return NULL; 184 } 185 else{ 186 BSTNode* pRoot = getAddr(value);// 用于存储value节点的地址 187 BSTNode* parents = getParents(value); // 用于存储value的父节点地址 188 // 含右子树的节点 189 if(pRoot->right != NULL){ 190 BSTNode* pre = pRoot->right; 191 while(pre->left != NULL){ 192 pre = pre->left; 193 } 194 return pre; 195 } 196 //没有右子树的节点 197 else{ 198 if(parents->left == pRoot) 199 return parents; 200 else if(parents->right == pRoot){ 201 while(parents->data < value) 202 parents = getParents(parents->data); 203 return parents; 204 } 205 } 206 } 207 } 208 209 int BSTree::minimum(){ 210 BSTNode* proot = root; 211 while(proot->left != NULL){ 212 proot = proot->left; 213 } 214 return proot->data; 215 } 216 217 int BSTree::maximum(){ 218 BSTNode* proot = root; 219 while(proot->right != NULL){ 220 proot = proot->right; 221 } 222 return proot->data; 223 } 224 225 /* 226 * 62 227 * / 228 * 58 88 229 * / / 230 * 47 73 99 231 * / / 232 * 35 51 93 233 * / / 234 * 29 37 49 56 235 * / / 236 * 36 48 50 237 * 238 * 删除节点的3种情况: 239 * 1. 叶子节点 240 * 1.1 树只含有一个节点,删除叶子节点 241 * 1.2 树含有至少2个节点,删除叶子节点 242 * 2. 仅有左或者右子树的节点 243 * 2.1 仅有左子树的节点,删除根节点 244 * 2.2 仅有左子树的节点,删除非根节点 245 * 2.3 仅有右子树的节点,删除根节点 246 * 2.4 仅有右子树的节点,删除非根节点 247 * 3. 左右子树都有的节点 248 * 249 */ 250 251 void BSTree::remove(int value){ 252 if(!search(value)){ 253 cout<<"the value is not in the tree. please check."<<endl; 254 return ; 255 } 256 else{ 257 // 查找value节点 258 BSTNode* pRoot = getAddr(value);// 用于存储value节点的地址 259 BSTNode* parents = getParents(value); // 用于存储待删除节点的父节点 260 // 删除value节点 261 // 1.叶节点 262 // 1.1 树只含有一个节点 263 if(pRoot == root && pRoot->left == NULL && pRoot->right == NULL){ 264 root = NULL; 265 free(pRoot); 266 } 267 // 1.2 树含有至少2个节点 268 else if(pRoot != root && pRoot->left == NULL && pRoot->right == NULL){ 269 // 待删节点是父节点的右孩子 270 if(parents->right != NULL && parents->right->data == value){ 271 parents->right = NULL; 272 free(pRoot); 273 } 274 // 待删节点是父节点的左孩子 275 else{ 276 parents->left = NULL; 277 free(pRoot); 278 } 279 } 280 // 2. 仅有左子树或右子树的节点 281 // 2.1 仅有左子树,且删除根节点 282 else if(pRoot == root && pRoot->left != NULL && pRoot->right == NULL){ 283 root = pRoot->left; 284 free(pRoot); 285 } 286 // 2.2 仅有左子树的节点,删除非根节点 287 else if(pRoot != root && pRoot->left != NULL && pRoot->right == NULL){ 288 // 待删节点是父节点的右孩子 289 if(parents->right != NULL && parents->right->data == value){ 290 parents->right = pRoot->left; 291 free(pRoot); 292 } 293 // 待删节点是父节点的左孩子 294 else{ 295 parents->left = pRoot->left; 296 free(pRoot); 297 } 298 } 299 // 2.3 仅有右子树的节点,删除根节点 300 else if(pRoot == root && pRoot->left == NULL && pRoot->right != NULL){ 301 root = pRoot->right; 302 free(pRoot); 303 } 304 // 2.4 仅有右子树的节点, 删除非根节点 305 else if(pRoot != root && pRoot->left == NULL && pRoot->right != NULL){ 306 // 待删节点是父节点的右孩子 307 if(parents->right != NULL && parents->right->data == value){ 308 parents->right = pRoot->right; 309 free(pRoot); 310 } 311 // 待删节点是父节点的左孩子 312 else{ 313 parents->left = pRoot->right; 314 free(pRoot); 315 } 316 } 317 // 3. 左右子树都有的节点 318 else{ 319 // 寻找待删除节点的直接前驱 320 BSTNode* pre = predecessor(value);// pre存储直接前驱 321 pRoot->data = pre->data;// 数据覆盖 322 // 寻找直接前驱的左/右节点 323 if(pre->right != NULL){ 324 BSTNode *pRootNext = pRoot->right; 325 BSTNode *temp = pre->right; 326 if(pre == pRootNext) 327 pRoot->right = temp; 328 else 329 pRootNext->left = temp; 330 free(pre); 331 } 332 else if(pre->left != NULL){ 333 BSTNode *pRootNext = pRoot->left; 334 BSTNode *temp = pre->left; 335 if(pre == pRootNext) 336 pRoot->left = temp; 337 else 338 pRootNext->right = temp; 339 free(pre); 340 } 341 else if(pre->left == NULL && pre->right == NULL){ 342 pRoot->left = NULL; 343 free(pre); 344 } 345 } 346 } 347 } 348 349 350 bool BSTree::search(int value){ 351 BSTNode* pRoot = root; 352 while(pRoot!=NULL && pRoot->data!=value){ 353 if(pRoot->data > value) 354 pRoot = pRoot->left; 355 else 356 pRoot = pRoot->right; 357 } 358 if(pRoot == NULL) 359 return false; 360 else 361 return true; 362 } 363 364 void BSTree::insert(int value){ 365 // value节点已经存在 366 if(BSTree::search(value) == true){ 367 cout<<"the value "<<value<<" in the tree already."<<endl; 368 return ; 369 } 370 // value节点不存在 371 else{ 372 BSTNode* pRoot = root; 373 // 空树 374 if(pRoot == NULL) 375 root = new BSTNode(value); 376 // 非空 377 else{ 378 BSTNode* temp; 379 while(pRoot!= NULL && pRoot->data!=value){ 380 temp = pRoot; 381 if(pRoot->data > value) 382 pRoot = pRoot->left; 383 else 384 pRoot = pRoot->right; 385 } 386 pRoot = temp; 387 if(pRoot->data>value) 388 pRoot->left = new BSTNode(value); 389 else 390 pRoot->right = new BSTNode(value); 391 } 392 } 393 cout<<"the value "<<value<<" is inserted."<<endl; 394 } 395 396 void BSTree::preOrder(BSTNode* &pRoot){ 397 if(pRoot == NULL) 398 return ; 399 cout<<pRoot->data<<' '; 400 preOrder(pRoot->left); 401 preOrder(pRoot->right); 402 } 403 404 void BSTree::inOrder(BSTNode* &pRoot){ 405 if(pRoot == NULL) 406 return ; 407 inOrder(pRoot->left); 408 cout<<pRoot->data<<' '; 409 inOrder(pRoot->right); 410 } 411 412 void BSTree::postOrder(BSTNode* &pRoot){ 413 if(pRoot == NULL) 414 return ; 415 postOrder(pRoot->left); 416 postOrder(pRoot->right); 417 cout<<pRoot->data<<' '; 418 } 419 420 void BSTree::levelOrder(BSTNode *&pRoot){ 421 queue<BSTNode*> p; 422 if(pRoot == NULL) 423 return ; 424 p.push(pRoot); 425 while (!p.empty()){ 426 BSTNode *temp = p.front(); 427 cout<<temp->data<<' '; 428 p.pop(); 429 if(temp->left) 430 p.push(temp->left); 431 if(temp->right) 432 p.push(temp->right); 433 } 434 } 435 436 void BSTree::destory(BSTNode *&proot){ 437 if (proot== NULL) 438 return ; 439 destory(proot->left); 440 destory(proot->right); 441 cout<<"free value "<<proot->data<<endl; 442 free(proot); 443 proot = NULL; 444 } 445 446 447 int main(int argc, char const *argv[]) 448 { 449 BSTree tree; 450 int arr[] = {62, 58, 47, 35, 29, 451 37, 36, 51, 49, 48, 452 50, 56, 88, 73, 99, 93}; 453 for(int i=0; i<16; i++) 454 tree.insert(arr[i]); 455 456 cout<<"前序遍历: "; 457 tree.preOrder(tree.root); 458 cout<<endl; 459 cout<<"中序遍历: "; 460 tree.inOrder(tree.root); 461 cout<<endl; 462 cout<<"最小值: "<<tree.minimum()<<endl; 463 cout<<"最大值: "<<tree.maximum()<<endl; 464 465 cout<<"深度: "<<tree.depth(tree.root)<<endl; 466 cout<<"节点数: "<<tree.size(tree.root)<<endl; 467 cout<<"叶子节点数: "<<tree.leafsize(tree.root)<<endl; 468 469 int index = 2; 470 BSTNode *pre = tree.predecessor(arr[index]); 471 if(pre != NULL) 472 cout<<"节点"<<arr[index]<<"的前驱节点是"<<pre->data<<endl; 473 474 BSTNode *suc = tree.successor(arr[index]); 475 if(suc != NULL) 476 cout<<"节点"<<arr[index]<<"的后继节点是"<<suc->data<<endl; 477 478 cout<<"删除节点: "<<arr[index]<<endl; 479 tree.remove(arr[index]); 480 481 cout<<"前序遍历: "; 482 tree.preOrder(tree.root); 483 cout<<endl; 484 cout<<"中序遍历: "; 485 tree.inOrder(tree.root); 486 cout<<endl; 487 488 tree.destory(tree.root); 489 return 0; 490 }
6. 运行结果
6.1 测试使用的二叉搜索树
/* * 62 * / * 58 88 * / / * 47 73 99 * / / * 35 51 93 * / / * 29 37 49 56 * / / * 36 48 50 * */
6.2 运行结果
1 the value 62 is inserted. 2 the value 58 is inserted. 3 the value 47 is inserted. 4 the value 35 is inserted. 5 the value 29 is inserted. 6 the value 37 is inserted. 7 the value 36 is inserted. 8 the value 51 is inserted. 9 the value 49 is inserted. 10 the value 48 is inserted. 11 the value 50 is inserted. 12 the value 56 is inserted. 13 the value 88 is inserted. 14 the value 73 is inserted. 15 the value 99 is inserted. 16 the value 93 is inserted. 17 前序遍历: 62 58 47 35 29 37 36 51 49 48 50 56 88 73 99 93 18 中序遍历: 29 35 36 37 47 48 49 50 51 56 58 62 73 88 93 99 19 最小值: 29 20 最大值: 99 21 深度: 6 22 节点数: 16 23 叶子节点数: 7 24 节点47的前驱节点是37 25 节点47的后继节点是48 26 删除节点: 47 27 前序遍历: 62 58 37 35 29 36 51 49 48 50 56 88 73 99 93 28 中序遍历: 29 35 36 37 48 49 50 51 56 58 62 73 88 93 99 29 free value 29 30 free value 36 31 free value 35 32 free value 48 33 free value 50 34 free value 49 35 free value 56 36 free value 51 37 free value 37 38 free value 58 39 free value 73 40 free value 93 41 free value 99 42 free value 88 43 free value 62 44 [Finished in 2.1s]