zoukankan      html  css  js  c++  java
  • 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     else
    141     {
    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     else
    180     {
    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         else
    223         {
    224             parent_node = node;
    225             node = node->rchild;
    226         }
    227     }  
    228     // 找到待插入结点parent_node
    229     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         else
    237         {
    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的左孩子不空的话,赋值给x
    258     else x = y->rchild;        //否则,无论是右孩子空不空,都赋值给x
    259 
    260     TreeNode<T> *parent_of_y = parent(y);
    261 
    262     if (y != _delete_node)
    263     {
    264         _delete_node->value = y->value;
    265         x->parent = parent_of_y;
    266         if (y == parent_of_y->lchild)
    267             parent_of_y->lchild = x;
    268         else
    269             parent_of_y->rchild = x;
    270         delete y;
    271     }
    272     else
    273     {
    274         x->parent = parent_of_y;
    275         if (parent_of_y == NULL)
    276         {
    277             node = x;
    278             
    279             delete y;
    280         }
    281         else
    282         {
    283             if (parent_of_y->lchild == y)
    284                 parent_of_y->lchild = x;
    285             else
    286                 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操作来初始化,并且增大size
    308 {    
    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         else
    339         {
    340             os << node->value << "  ";  //输出当前结点的value
    341             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<<    _increase
    366     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,okay
    374     BinarySearchTree<int> Bst(BST);
    375     cout << Bst << endl;
    376 
    377     //检测operator=,okay
    378     BinarySearchTree<int> bst,bsT;
    379     bsT= bst = Bst;
    380     cout <<"!"<< bst<<endl;
    381     cout <<"!"<< bsT << endl;
    382 
    383     //检测_mininum  _maxinum,okay
    384     cout << "maxinum" << BST.maxinum()<<endl;
    385     cout << "mininum" << BST.mininum()<<endl;
    386 
    387     //检测 _decrease,okay
    388     BST.__test();
    389 
    390     //检测_search,okay
    391     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,okay
    400     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 }
  • 相关阅读:
    利用子查询解决复杂sql问题
    如何用临时表代替游标进行表记录的拷贝
    SQL新函数, 排名函数 ROW_NUMBER(), RANK(), DENSE_RANK()
    SQL SERVER2005 中的错误捕捉与处理
    用户自定义函数代替游标进行循环拼接
    使用游标进行循环数据插入
    Oracle中利用存储过程建表
    SQL SERVER中强制类型转换cast和convert的区别
    SQL如何修改被计算字段引用的字段类型
    1.官方网站:http://www.mplayerhq.hu/design7/dload.html
  • 原文地址:https://www.cnblogs.com/gaoduan/p/3917734.html
Copyright © 2011-2022 走看看