搜索二叉树是一种具有良好排序和查找性能的二叉树数据结构,包括多种操作,本篇只介绍插入,排序(遍历),和删除操作,重点是删除操作比较复杂,用到的例子也是本人亲自画的
用到的测试图数据例子
第一、构建节点
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 template <typename T> class BST; 2 template <typename T> class BSTNode { 3 public: 4 friend class BST<T>; 5 BSTNode() { 6 lChild = rChild = parent = NULL; 7 data = NULL; 8 } 9 BSTNode(T d) { 10 lChild = rChild = parent = NULL; 11 data = d; 12 } 13 private: 14 BSTNode<T> *lChild, *rChild, *parent; 15 T data; 16 };
第二、二叉树头文件定义
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 template<typename T> class BST { 2 public: 3 BST() { } 4 5 //插入操作 6 void insert(BSTNode<T>*node); 7 8 //二叉查找树的中序遍历,就相当于排序了 9 void inSort(BSTNode<T>*node); 10 11 //按节点删除 12 void deleteNode(BSTNode<T>* node); 13 14 //按数值删除 15 void deleteNode(const T& t); 16 17 BSTNode<T>* search(T key); 18 BSTNode<T>* root=NULL; 19 20 private: 21 int count; 22 };
第三、搜索二叉树的插入
1)如果二叉树查找树为空节点,则插入节点就为根节点
2)如果二叉查找树为非空节点,就需要先找到待插入节点,查找原则就是从根节点开始,如果大于根就右边走,小于根就左边走,直到找到合适节点,
下面代码中的最终找到的temp 就是待插入节点.
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 template<typename T> 2 void BST<T>::insert(BSTNode<T>* node) 3 { 4 BSTNode<T>* curr, *temp = NULL; 5 curr = root; 6 while (NULL!= curr) //遍历二叉树,找到应该插入的父节点 7 { 8 temp = curr; 9 if (node->data>curr->data) 10 { 11 curr = curr->rChild; 12 } 13 else { 14 curr = curr->lChild; 15 } 16 } 17 node->parent = temp;//temp 代码当前最后遍历的node,设置node->parent为该节点 18 if (temp==NULL) 19 { 20 root = node; 21 count++; 22 } 23 else { 24 if (node->data<temp->data) 25 { 26 temp->lChild = node; 27 count++; 28 } 29 else { 30 temp->rChild = node; 31 count++; 32 } 33 } 34 }
第四、搜索二叉树的删除
删除包含多种情况,
1. 如果节点没有子女,修改其父节点指针为NULL,删除即可
2. 如果该节点有左孩子情况,修改其父亲节点的指针和其左孩子的parent指针即可
3. 如果该节点有右孩子情况,修改其父亲节点的指针和其右孩子的parent指针即可
4.如果同时有左右孩子的情况,情况比较复杂,一般有2种方法处理
1) 用节点右边孩子的最小值替换该节点,其他节点位置保持不变(本篇用这种方法)
2)用节点左边孩子的最大值替换该节点,其他节点位置保持不变
后面测试例子是删除18 node,通过程序找到右边最小值20,用20 替换18,其他节点位置保持不动。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 template<typename T> 2 inline void BST<T>::deleteNode(BSTNode<T>* node) 3 { 4 BSTNode<T>*p = node->parent;//获取node的父节点,这里很重要 5 if (node->lChild==NULL && node->rChild==NULL) //叶子节点直接删除 6 { 7 if (node==node->parent->lChild) 8 { 9 node->parent->lChild = NULL; 10 } 11 else { 12 node->parent->rChild = NULL; 13 } 14 delete node; 15 count--; 16 } 17 else if (node->rChild != NULL && node->lChild == NULL) {//存在右孩子 18 if (p==NULL)//说明节点为根节点 19 { 20 root = node->rChild; 21 count--; 22 } 23 else { 24 node->rChild->parent = p; 25 if (p->lChild==node) //判断是父节点的左孩子还是右孩子 26 { 27 p->lChild = node->rChild; 28 } 29 else { 30 p->rChild = node->rChild; 31 } 32 delete node; 33 count--; 34 } 35 } 36 else if (node->lChild!=NULL && node->rChild==NULL)//存在左孩子 37 { 38 if (p==NULL) 39 { 40 root = root->lChild; 41 count--; 42 } 43 else { 44 node->lChild->parent = p; 45 if (p->lChild==node) 46 { 47 p->lChild = node->lChild; 48 } 49 else { 50 p->rChild = node->lChild; 51 } 52 delete node; 53 count--; 54 } 55 } 56 else { 57 BSTNode<T>*left, *curp=NULL; 58 left = node->rChild; //本方案是找右侧最小值,替换node节点,其他节点保持不动即可 59 while (left!=NULL) 60 { 61 curp = left; 62 left = left->lChild; 63 } 64 65 if (curp->rChild!=NULL) 66 { 67 if (curp->lChild==curp) 68 { 69 curp->parent->lChild = curp->rChild; 70 } 71 else { 72 curp->parent->rChild = curp->rChild; 73 } 74 } 75 else { 76 if (curp->parent->lChild==curp) 77 { 78 curp->parent->lChild = NULL; 79 } 80 else { 81 curp->parent->rChild = NULL; 82 } 83 //curp->parent->lChild = NULL; 84 } 85 //替curp 替换 node 86 curp->parent = p; 87 curp->lChild = node->lChild; 88 curp->rChild = node->rChild; 89 90 if (p->lChild==node)//判断node 是p 的左孩子还是右孩 91 { 92 p->lChild = curp; 93 } 94 else { 95 p->rChild = curp; 96 } 97 delete node; 98 count--; 99 } 100 }
第五、二叉树的搜索查找
由于搜索二叉树本身是已经排序好的,查找过程相对简单,从根节点,逐个排查,大于根向右,小于根向左,直到叶子节点.
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
template<typename T> inline BSTNode<T>* BST<T>::search(T k) { BSTNode<T>*node = root; while (node!=NULL) { if (k<node->data) { node = node->lChild; } else if (k> node->data) { node = node->rChild; } else { break; } } return node; }
第六、二叉搜索树的排序
根据二叉所有树的特性,这里所谓排序,其实就是二叉树的中序遍历,其他的几种遍历不在这里赘述,知识调整下结构即可
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
template<typename T> void BST<T>::inSort(BSTNode<T>* node) { if (node!=NULL) { inSort(node->lChild); std::cout << node->data<<","; inSort(node->rChild); } }
第七、测试程序
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include "pch.h" 2 #include <iostream> 3 #include "BSTree.h" 4 using namespace std; 5 6 int main() 7 { 8 // 树结构示意 9 // 30 10 // / \ 11 // 15 25 12 // / \ 13 //9 18 14 // / \ 15 // 16 25 16 // / \ 17 // 20 26 18 BST<int> sbt; 19 sbt.insert(new BSTNode<int>(30)); 20 sbt.insert(new BSTNode<int>(15)); 21 sbt.insert(new BSTNode<int>(9)); 22 sbt.insert(new BSTNode<int>(18)); 23 sbt.insert(new BSTNode<int>(16)); 24 sbt.insert(new BSTNode<int>(25)); 25 sbt.insert(new BSTNode<int>(20)); 26 sbt.insert(new BSTNode<int>(26)); 27 sbt.insert(new BSTNode<int>(35)); 28 29 cout << "搜索树排序后:"; 30 sbt.inSort(sbt.root); 31 32 sbt.deleteNode(18); 33 34 cout << endl << "删除18 后排序:"; 35 36 sbt.inSort(sbt.root); 37 }
测试结果
所有完整程序代码
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #pragma once 2 template <typename T> class BST; 3 template <typename T> class BSTNode { 4 public: 5 friend class BST<T>; 6 BSTNode() { 7 lChild = rChild = parent = NULL; 8 data = NULL; 9 } 10 BSTNode(T d) { 11 lChild = rChild = parent = NULL; 12 data = d; 13 } 14 private: 15 BSTNode<T> *lChild, *rChild, *parent; 16 T data; 17 }; 18 19 template<typename T> class BST { 20 public: 21 BST() { } 22 23 //插入操作 24 void insert(BSTNode<T>*node); 25 26 //二叉查找树的中序遍历,就相当于排序了 27 void inSort(BSTNode<T>*node); 28 29 //按节点删除 30 void deleteNode(BSTNode<T>* node); 31 32 //按数值删除 33 void deleteNode(const T& t); 34 35 BSTNode<T>* search(T key); 36 BSTNode<T>* root=NULL; 37 38 private: 39 int count; 40 }; 41 42 template<typename T> 43 void BST<T>::insert(BSTNode<T>* node) 44 { 45 BSTNode<T>* curr, *temp = NULL; 46 curr = root; 47 while (NULL!= curr) //遍历二叉树,找到应该插入的父节点 48 { 49 temp = curr; 50 if (node->data>curr->data) 51 { 52 curr = curr->rChild; 53 } 54 else { 55 curr = curr->lChild; 56 } 57 } 58 node->parent = temp;//temp 代码当前最后遍历的node,设置node->parent为该节点 59 if (temp==NULL) 60 { 61 root = node; 62 count++; 63 } 64 else { 65 if (node->data<temp->data) 66 { 67 temp->lChild = node; 68 count++; 69 } 70 else { 71 temp->rChild = node; 72 count++; 73 } 74 } 75 } 76 77 template<typename T> 78 void BST<T>::inSort(BSTNode<T>* node) 79 { 80 if (node!=NULL) 81 { 82 inSort(node->lChild); 83 std::cout << node->data<<","; 84 inSort(node->rChild); 85 } 86 } 87 88 template<typename T> 89 inline void BST<T>::deleteNode(BSTNode<T>* node) 90 { 91 BSTNode<T>*p = node->parent;//获取node的父节点,这里很重要 92 if (node->lChild==NULL && node->rChild==NULL) //叶子节点直接删除 93 { 94 if (node==node->parent->lChild) 95 { 96 node->parent->lChild = NULL; 97 } 98 else { 99 node->parent->rChild = NULL; 100 } 101 delete node; 102 count--; 103 } 104 else if (node->rChild != NULL && node->lChild == NULL) {//存在右孩子 105 if (p==NULL)//说明节点为根节点 106 { 107 root = node->rChild; 108 count--; 109 } 110 else { 111 node->rChild->parent = p; 112 if (p->lChild==node) //判断是父节点的左孩子还是右孩子 113 { 114 p->lChild = node->rChild; 115 } 116 else { 117 p->rChild = node->rChild; 118 } 119 delete node; 120 count--; 121 } 122 } 123 else if (node->lChild!=NULL && node->rChild==NULL)//存在左孩子 124 { 125 if (p==NULL) 126 { 127 root = root->lChild; 128 count--; 129 } 130 else { 131 node->lChild->parent = p; 132 if (p->lChild==node) 133 { 134 p->lChild = node->lChild; 135 } 136 else { 137 p->rChild = node->lChild; 138 } 139 delete node; 140 count--; 141 } 142 } 143 else { 144 BSTNode<T>*left, *curp=NULL; 145 left = node->rChild; //本方案是找右侧最小值,替换node节点,其他节点保持不动即可 146 while (left!=NULL) 147 { 148 curp = left; 149 left = left->lChild; 150 } 151 152 if (curp->rChild!=NULL) 153 { 154 if (curp->lChild==curp) 155 { 156 curp->parent->lChild = curp->rChild; 157 } 158 else { 159 curp->parent->rChild = curp->rChild; 160 } 161 } 162 else { 163 if (curp->parent->lChild==curp) 164 { 165 curp->parent->lChild = NULL; 166 } 167 else { 168 curp->parent->rChild = NULL; 169 } 170 //curp->parent->lChild = NULL; 171 } 172 //替curp 替换 node 173 curp->parent = p; 174 curp->lChild = node->lChild; 175 curp->rChild = node->rChild; 176 177 if (p->lChild==node)//判断node 是p 的左孩子还是右孩 178 { 179 p->lChild = curp; 180 } 181 else { 182 p->rChild = curp; 183 } 184 delete node; 185 count--; 186 } 187 } 188 189 template<typename T> 190 inline void BST<T>::deleteNode(const T & k) 191 { 192 BSTNode<T>*node = search(k); 193 if (node!=NULL) 194 { 195 deleteNode(node); 196 } 197 } 198 199 200 template<typename T> 201 inline BSTNode<T>* BST<T>::search(T k) 202 { 203 BSTNode<T>*node = root; 204 while (node!=NULL) 205 { 206 if (k<node->data) 207 { 208 node = node->lChild; 209 } 210 else if (k> node->data) 211 { 212 node = node->rChild; 213 } 214 else { 215 break; 216 } 217 } 218 return node; 219 }