首页 > 代码库 > BinarySearchTree示例——C++模板实现
BinarySearchTree示例——C++模板实现
数据结构和算法理解很简单,深感算法导论的介绍更是精辟而无累赘。
例如:1. 直接切入二叉搜索树,而不是从树开始介绍各种繁琐的表示方式,最后的重点结果还是二叉搜索和几种平衡树,算法导论介绍知识的时候数学性虽强,但应用性也十足,它的 应用性不在于给你代码,而在于给你应用的场景,告诉你各种结构的优劣和代价,这才是学习数据结构和算法应该掌握的精华,而不在一些教材上展示的可以称之为垃圾的代 码上,实际上,关于数据结构的实现代码,工业级的STL源码可以给你最高屋建瓴的精华。
2. 遍历方法仅重点分析中序遍历,为何?因为按照二叉搜索树的性质其中序即使orderd,其它序也有作用,比如某一道习题提到的位二叉树,其pre-order才是orderd,但 比上来让你实现几个遍历,滚瓜烂熟之后也不知在何处用(只会用来display数据除外);
3. 不止一次在网上看到人们评价算导的数据结构部分过于简单,又跑回去啃严版教材,实乃买椟还珠,为何他们觉得简单,我简单分析一下,认为他们一不做或者不思考习题, 对于二叉搜索树而言,最难的(其实也不难)地方在于迭代遍历(pre,in,post),算法导论的习题中不仅有,而且还提出一种使用stack模拟,另一种不借助stack,要求 读者独立完成。倘使不做,自然无法得其中奥义,只能回去啃别人代码,一读便懂,回头即忘。
所以就我个人阅读感受而言,算法导论一书造诣颇高,比大多数相关书籍不知道高明多少,十分推荐。
我在以前只学习数据结构的时候就已经用模板实现了二叉搜索树,但是看完算法导论再加之一些STL源码的阅读体验,感觉之前的代码臭不可闻,接口错乱,实现冗杂,实乃错误之典范,究其根本还在于理解了但是不明白用来干嘛。当然,我偶然搜索了一下,发现大多数学习者在互相抄袭,完全相同的代码和用词出现在了好多的博文上,而其抄袭的代码本身也不是什么优秀之作。既然是学习,不管好与坏,自己做得才有进步,复制粘贴就。。。
所以最近得空重新实现一下,虽然还是有诸多不满之处,但比之前要好很多了。
下面在代码中分析一下:(设置为虚函数的函数是要做red-black tree中重新给出实现的操作)
算法的部分不难,理解之后还有很多设计上的问题,即接口和实现的分离、node类和tree类之间的耦合和内聚等等。
自己从头撸一个,还是有一些好处的。
1 #include<iostream> 2 using namespace std; 3 4 //结点类 5 template<typename T> 6 class TreeNode 7 { 8 //声明为二叉搜索树的友元类 9 template<class T> friend class BinarySearchTree; 10 //方便<<操作符访问结点成员 11 template<typename T> friend ostream& operator<<(ostream &os, BinarySearchTree<T>&BST); 12 13 private: 14 T value; 15 TreeNode<T>* lchild; 16 TreeNode<T>* rchild; 17 TreeNode<T>* parent;//带parent结点要方便的多 18 19 TreeNode<T>* _increase();//自增,即中序下的后继 20 TreeNode<T>* _decrease();//自减,即中序下的前驱 21 public: 22 //三个构造函数 23 TreeNode() :value(0), lchild(NULL), rchild(NULL),parent(NULL){} 24 TreeNode(T v) :value(v), lchild(NULL), rchild(NULL),parent(NULL){} 25 TreeNode(TreeNode<T> &node) :value(node.value), lchild(node.lchild), rchild(node.rchild),parent(node.parent){} 26 virtual ~TreeNode(){} //析构函数设置为虚函数 27 void _test_display() //此函数只是测试使用,应该删去 28 { 29 cout << "value: " << this->value<<" "; 30 if (this->lchild!=NULL) 31 cout <<"lchild: "<< this->lchild->value<<" "; 32 else cout << "lchild: NULL"<<" "; 33 if (this->rchild != NULL) 34 cout << "rchild: " << this->rchild->value << " "; 35 else cout << "rchild: NULL" << " "; 36 if (this->parent != NULL) 37 cout << "parent: " << this->parent->value << " "; 38 else cout << "parent: NULL" << " "; 39 cout << endl; 40 } 41 42 }; 43 44 //二叉搜索树类 45 template<typename T> 46 class BinarySearchTree 47 { 48 49 private: 50 TreeNode<T> *root; //根节点 51 int size; //结点数量 52 53 TreeNode<T>* _copy(TreeNode<T> *node,TreeNode<T>* q); //私有函数,node表示复制以node为根节点的树,参数q实际上指向node的父节点,是实现的小技巧 54 TreeNode<T>* _mininum(TreeNode<T>* node); //私有函数,找到以node为根节点的树中的最小结点 55 TreeNode<T>* _maxinum(TreeNode<T>* node); 56 57 virtual TreeNode<T>* _insert(T& value,TreeNode<T>* node);//私有函数,用于实现Insert操作 58 virtual void _delete(TreeNode<T>* _delete_node,TreeNode<T>* node);//私有函数,用于实现Delete操作 59 TreeNode<T>* _search(T& value, TreeNode<T>* node); //私有函数,用于实现Search操作 60 virtual void _init(T* array,int length); //通过数组初始化二叉搜索树 61 virtual void _clear(TreeNode<T>* node); //清空node为根节点的树 62 63 64 65 public: 66 //构造和析构函数 67 BinarySearchTree() :root(NULL), size(0){} 68 BinarySearchTree(T* array, int length) { _init(array, length); } 69 BinarySearchTree(BinarySearchTree<T> &tree){ root = _copy(tree.root, NULL); size = tree.size; } 70 virtual ~BinarySearchTree() { _clear(root); size = 0; } 71 //赋值操作符的重载 72 virtual BinarySearchTree<T>& operator=(BinarySearchTree<T> &tree){ _clear(root); root = _copy(tree.root, NULL); size = tree.size; return *this; } 73 //判断树是否为空 74 bool isEmpty() { return size == 0; } 75 //返回树中结点个数 76 int Size() { return size; } 77 //基本操作,Insert、Delete、Search 78 virtual TreeNode<T>* Insert(T& value){ return _insert(value, root); } 79 virtual void Delete(TreeNode<T>* node){ return _delete(node, root); } 80 TreeNode<T>* Search(T& value){ return _search(value, root); } 81 82 //返回树中value最大和最小的结点的value 83 T& mininum(){ return _mininum(root)->value; } 84 T& maxinum(){ return _maxinum(root)->value; } 85 //返回某个节点的parent 86 TreeNode<T>* parent(TreeNode<T> *node){ return node->parent; } 87 //<<操作符必须设置为友元,不可以是成员 88 template<typename T> friend ostream& operator<<(ostream &os, BinarySearchTree<T>&BST); 89 90 //一个测试函数 91 void __test(){ cout << "测试_ decrease" << --(this->root->rchild->lchild->lchild)->value << endl; }; 92 93 }; 94 95 template<typename T> 96 TreeNode<T>* BinarySearchTree<T>::_copy(TreeNode<T>* node,TreeNode<T>* q) 97 { 98 //这里q保存node的父节点,调用时初始化为NULL(root的parent为NULL) 99 100 if (node == NULL)101 return NULL;102 103 TreeNode<T>* p = new TreeNode<T>(node->value);104 p->parent = q;105 p->lchild = _copy(node->lchild,p);//递归复制106 p->rchild = _copy(node->rchild,p);107 return p;108 }109 110 111 template<typename T>112 TreeNode<T>* BinarySearchTree<T>::_mininum(TreeNode<T>* node)//最左端结点为最小113 {114 TreeNode<T> * p = node;115 TreeNode<T>* q=NULL;116 while (p != NULL)117 {118 q = p;119 p = p->lchild;120 }121 return q;122 }123 template<typename T>124 TreeNode<T>* BinarySearchTree<T>::_maxinum(TreeNode<T>* node)//最右端结点为最大125 {126 TreeNode<T>* p = node;127 TreeNode<T>* q = NULL;128 while(p != NULL)129 {130 q= p;131 p = p->rchild;132 }133 return q;134 }135 template<typename T>136 TreeNode<T>* TreeNode<T>::_increase()137 {138 if (this == NULL)139 return NULL;140 else141 {142 if (this->rchild != NULL) //当前结点如果有右孩子,则后继为右子树中最小的结点143 {144 TreeNode<T> * p = this->rchild;145 TreeNode<T>* q=p;146 while (p != NULL)147 {148 q= p;149 p = p->lchild;150 }151 152 return q;153 }154 else //否则,则向上回溯,直到第一次出现 q 是 p 的左孩子结点为止155 {156 TreeNode<T> *q = this;157 TreeNode<T> *p = this->parent;158 //cout<<"parent:" << p->value << endl;159 //cout <<"cur: "<< q->value << endl;160 while(q != p->lchild)161 {162 q = p;163 p = p->parent;164 if (p == NULL)165 break;166 }167 //cout << "parent: " << p->value << endl;168 169 return p;170 }171 }172 173 }174 template<typename T>175 TreeNode<T>* TreeNode<T>::_decrease()176 {177 if (this == NULL)178 return NULL;179 else180 {181 if (this->lchild != NULL) //当前结点如果有左孩子,则后继为右子树中最大的结点182 { 183 TreeNode<T> *p = this->lchild;184 TreeNode<T> *q = p;185 while (p != NULL)186 {187 q = p;188 p = p->rchild;189 }190 return q;191 }192 else //否则,则向上回溯,直到第一次出现 q 是 p 的右孩子结点为止193 {194 TreeNode<T> *q = this;195 TreeNode<T> *p = this->parent;196 while (q != p->rchild)197 {198 q = p;199 p = p->parent;200 if (p == NULL)201 break;202 }203 return p;204 }205 }206 207 }208 209 template<typename T>210 TreeNode<T>* BinarySearchTree<T>::_insert(T& value, TreeNode<T>* node) //insert操作的返回值为指向插入结点的指针211 {212 TreeNode<T> *p = new TreeNode<T>(value);213 TreeNode<T> *parent_node = NULL;214 215 while (node != NULL)216 {217 if (p->value < node->value)218 { 219 parent_node = node;220 node = node->lchild;221 }222 else223 {224 parent_node = node;225 node = node->rchild;226 }227 } 228 // 找到待插入结点parent_node229 if (parent_node != NULL)230 {231 p->parent = parent_node;232 if (p->value < parent_node->value)233 {234 parent_node->lchild = p;235 }236 else237 {238 parent_node->rchild = p;239 }240 }241 else //当前树为空242 {243 root=p;244 }245 return p;246 247 }248 template<typename T>249 void BinarySearchTree<T>::_delete(TreeNode<T>* _delete_node, TreeNode<T>* node)250 { 251 TreeNode<T> *y, *x;252 if (_delete_node->lchild == NULL || _delete_node->rchild == NULL) //如果待删除结点有一个孩子或者没有孩子,那么要被移除的结点就是它自己253 y = _delete_node;254 else y = _delete_node->_increase(); //如果有两个结点,那么要移除的结点就是它的后继(然后把它的后继的value赋值给它)255 256 if (y->lchild != NULL)257 x = y->lchild; //如果y的左孩子不空的话,赋值给x258 else x = y->rchild; //否则,无论是右孩子空不空,都赋值给x259 260 TreeNode<T> *parent_of_y = parent(y);261 262 if (y != _delete_node)263 {264 _delete_node->value = http://www.mamicode.com/y->value;265 x->parent = parent_of_y;266 if (y == parent_of_y->lchild)267 parent_of_y->lchild = x;268 else269 parent_of_y->rchild = x;270 delete y;271 }272 else273 {274 x->parent = parent_of_y;275 if (parent_of_y == NULL)276 {277 node = x;278 279 delete y;280 }281 else282 {283 if (parent_of_y->lchild == y)284 parent_of_y->lchild = x;285 else286 parent_of_y->rchild = x;287 delete y;288 }289 }290 291 }292 template<typename T>293 TreeNode<T>* BinarySearchTree<T>::_search(T& value, TreeNode<T>* node) //search是其最擅长的操作,返回值为找到结点的指针294 {295 TreeNode<T>* p = node;296 while (p != NULL)297 {298 if (value < p->value)299 p = p->lchild;300 else if (value > p->value)301 p = p->rchild;302 else return p;303 }304 return NULL;305 }306 template<typename T>307 void BinarySearchTree<T>::_init(T* array,int length) //反复调用insert操作来初始化,并且增大size308 { 309 310 for (int i = 0; i < length; ++i)311 {312 _insert(array[i], root);313 ++size;314 }315 }316 317 template<typename T>318 void BinarySearchTree<T>::_clear(TreeNode<T>* node) //递归调用来删除319 {320 if (node == NULL)321 return;322 323 TreeNode<T>* p = node->lchild;324 TreeNode<T>* q = node->rchild;325 delete node;326 _clear(p);327 _clear(q);328 }329 330 template<typename T>331 ostream& operator<<(ostream &os, BinarySearchTree<T>& BST) //这里其实是一个迭代版(不用辅助stack)的方法332 {333 TreeNode<T>* node = BST.root;334 while (true)335 {336 if (node->lchild != NULL) //一直访问到当前最左边结点337 node = node->lchild;338 else339 {340 os << node->value << " "; //输出当前结点的value341 while (node->rchild == NULL) //如果无右孩子,则访问其后继,注意这里是循环342 { 343 344 node=node->_increase();345 346 if (node != NULL)347 os << node->value << " ";348 else break;349 }350 if (node !=NULL) //如果有右孩子,访问其右孩子(这里是一个尾递归优化而来的迭代,容易理解)351 {352 node = node->rchild;353 }354 else break;355 356 }357 358 }359 return os;360 }361 int main()362 {363 const int length = 9;364 int array[length] = { 13,9,17,5,12,15,18,2,19};365 //检测_init _insert operator<< _increase366 BinarySearchTree<int> BST(array, length);367 cout <<"BST: "<< BST << endl;368 int v = 14;369 BST.Insert(v);370 cout<<"BST insert one node with value 14: " << BST << endl;371 372 373 //检测_copy,okay374 BinarySearchTree<int> Bst(BST);375 cout << Bst << endl;376 377 //检测operator=,okay378 BinarySearchTree<int> bst,bsT;379 bsT= bst = Bst;380 cout <<"!"<< bst<<endl;381 cout <<"!"<< bsT << endl;382 383 //检测_mininum _maxinum,okay384 cout << "maxinum" << BST.maxinum()<<endl;385 cout << "mininum" << BST.mininum()<<endl;386 387 //检测 _decrease,okay388 BST.__test();389 390 //检测_search,okay391 TreeNode<int> *p=BST.Search(array[0]);392 p->_test_display();393 p = BST.Search(array[7]);394 p->_test_display();395 p = BST.Search(array[8]);396 p->_test_display();397 398 399 //检测_delete,okay400 p = BST.Search(array[2]);401 BST.Delete(p);402 cout << "delete the node with value 17"<<endl;403 cout << BST << endl;404 405 //测试size 406 cout <<"BST size: "<< BST.Size() << endl;407 cout <<"bsT size: "<< bsT.Size() << endl;408 system("pause");409 410 }