• Binary_Seach_Tree(BST) C++


    Wiki:二叉查找树(英语:Binary Search Tree),也称为二叉搜索树有序二叉树ordered binary tree)或排序二叉树sorted binary tree),是指一棵空树或者具有下列性质的二叉树

    1. 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
    2. 若任意节点的右子树不空,则右子树上所有节点的值均大于或等于它的根节点的值;
    3. 任意节点的左、右子树也分别为二叉查找树

    总的来说:《c++ primr 5th》每次看都觉得厉害

    1、shared_ptr 是真的香

    2、template 友元用的时候在看

    3、函数传递:指针形参属于传值(拷贝),shared_ptr引用传递 没必要:动态内存(猜测)

    4、cosnt 成员函数适用:不能把this指针 绑定到常量对象(如const double pi = 3.14):return pi;

    具体学习到什么 看code注释

      1 #pragma once
      2 //编译器需要掌握函数模板或模板成员函数的定义:成员函数定义 也在头文件中
      3 //成员函数定义在类外使用默认实参 报错:不允许使用默认参数(原因还未知)
      4 //原因:非静态数据成员不能作为默认实参:因为它的值本身属于对象的一部分,
      5 //这么做的结果是:无法真正提供一个对象以便从中获取成员的值
      6 
      7  /*
      8  指针传递:形参是指针的拷贝,两个指针是不同的指针 但是可以间接修改所指向对象的值
      9  尽量使用引用传递:避免拷贝的效率和空间
     10  尽量使用值初始化:避免多余默认初始化
     11  type* & :指向指针的引用 :引用本身不是对象所以不能定义指向引用的指针
     12  =运算符在结点上的意义是什么? 指针之间的赋值操作:所以不需要定义赋值运算符不是类之间操作
     13  类的行为像指针:共享状态 最好的方法是使用shared_ptr
     14  */
     15 
     16 #include<iostream>
     17 #include<memory> //shared_ptr
     18 template<typename T> class BST;//前置声明:友元所需要
     19 template<typename T>
     20 //在Tree_Note类内:直接使用模板名而不提供实参:Tree_Note = Tree_Note<T>
     21 class Tree_Note
     22 {
     23     friend class BST<T>;//每个Tree_Note实例将访问权限授予用相同类型实例化的BST
     24 public:
     25     //构造函数
     26     Tree_Note(const T& _key = T())
     27         :left(nullptr), right(nullptr), parent(nullptr),key(_key){}
     28     /*
     29     stack overflow why??? 
     30     答:make_shared 调用Tree_Note构造函数则造成无线循环
     31         而用内置已经存在构造函数的则不会 :data(make_shared<vector<string>>()):data = ""
     32         :left(std::make_shared<Tree_Note>()),
     33         right(std::make_shared<Tree_Note>()), parent(std::make_shared<Tree_Note>()),key(_key) {}
     34     */
     35     /* 没用上拷贝构造
     36     //为了与内置运算符一致:返回指向左侧运算对象的引用:
     37     decltype(auto) operator=(std::make_ptr<Tree_Note> right)
     38     {//decltype(auto)详见:《Effective Modern C++》P31
     39         key = right.key;
     40         return maked_shared<Tree_Note>(*this);
     41     }
     42     */
     43 private:
     44     T key;
     45     std::shared_ptr<Tree_Note> left;
     46     std::shared_ptr<Tree_Note> right;
     47     std::shared_ptr<Tree_Note> parent;
     48 };
     49 
     50 template<typename T>
     51 class BST
     52 {
     53 public:
     54     //若root(nullptr) 则:报错访问内存受限
     55     BST() :root(nullptr) {} //若使用构造函数则 root.key = 0
     56     //中序遍历
     57     void Iorder_Tree_Walk(const std::shared_ptr<Tree_Note<T>> x);
     58     void Iorder_Tree_Walk() {Iorder_Tree_Walk(root);}
     59     //递归查找
     60     std::shared_ptr<Tree_Note<T>> Tree_Search(const T& key,const std::shared_ptr<Tree_Note<T>> x);
     61     bool Tree_Seach(const T& key)
     62     {
     63         auto p = Tree_Search(key, root);
     64         if (p != nullptr)
     65             return true;
     66         else
     67             return false;
     68     }
     69     //迭代查找:对于大多数计算机,迭代版本的效率要高的多 :调用函数开销
     70     std::shared_ptr<Tree_Note<T>> Iterative_Tree_Search(const T& key,std::shared_ptr<Tree_Note<T>> x);
     71     bool Iterative_Tree_Search(const T& key)
     72     {
     73         auto p = Iterative_Tree_Search(key, root);
     74         if (p != nullptr)
     75             return true;
     76         else
     77             return false;
     78     }
     79 
     80     //最小值
     81     std::shared_ptr<Tree_Note<T>> Tree_Minimum(std::shared_ptr<Tree_Note<T>> x);
     82     T Tree_Minimum()
     83     {
     84         auto p = Tree_Minimum(root);
     85         return p->key;
     86     }
     87     //最大值
     88     std::shared_ptr<Tree_Note<T>> Tree_Maximum(std::shared_ptr<Tree_Note<T>> x);
     89     T Tree_Maximum() 
     90     {
     91         auto p = Tree_Maximum(root);
     92         return p->key;
     93     }
     94 
     95     //后继和前驱:最接近(大小)该节点的大、小节点
     96     std::shared_ptr<Tree_Note<T>> Tree_Successor(std::shared_ptr<Tree_Note<T>> x);
     97     std::shared_ptr<Tree_Note<T>> Tree_Predecessor(std::shared_ptr<Tree_Note<T>> x);
     98 
     99     //插入和删除
    100     void Tree_Insert(std::shared_ptr<Tree_Note<T>> z); //当为空树是z要赋值给root 而root不能是const,所以z不是const
    101     void Tree_Insert(const T& key)
    102     {
    103         auto z = std::make_shared<Tree_Note<T>>(key);
    104         Tree_Insert(z);
    105     }
    106     void Tree_Delete(std::shared_ptr<Tree_Note<T>> z);
    107     void Tree_Delete(const T& key)
    108     {
    109         auto z = Iterative_Tree_Search(key, root);
    110         if (z == nullptr)
    111             std::cerr << "nodata!";
    112         Tree_Delete(z);
    113     }
    114 private:
    115     std::shared_ptr<Tree_Note<T>> root;
    116     //移植节点 :u = v(不包括左右孩子)
    117     void Transplant(std::shared_ptr<Tree_Note<T>> u, std::shared_ptr<Tree_Note<T>> v)
    118     {
    119         //指针给指针赋值:右侧地址赋值给左侧地址(指针存储的是地址) 
    120         if (u->parent == nullptr) //如果u是根节点
    121             root = v;
    122         //都用 v替代u了 u的父节点不也被替代了么?---属于指针的赋值而不是类所以不用定于赋值运算符
    123         else if (u == u->parent->left) //如果U是左孩子
    124             u->parent->left = v;
    125         else
    126             u->parent->right = v;        
    127         if (v->parent != nullptr)
    128             v->parent = u->parent;//不改变被替换树的上层
    129     }
    130 };
    131 
    132 //成员函数定义在类外使用默认实参 报错:不允许使用默认参数
    133 //原因(P271 《c++ prime 5th》):非静态数据成员不能作为默认实参:因为它的值本身属于对象的一部分,
    134 //这么做的结果是:无法真正提供一个对象以便从中获取成员的值
    135 
    136 //递归查找
    137 template<typename T>
    138 std::shared_ptr<Tree_Note<T>> 
    139 BST<T>::Tree_Search(const T& key,const std::shared_ptr<Tree_Note<T>> x)
    140 {
    141     if (x == nullptr || key == x->key)
    142         return x;
    143     if (key < x->key)//在左侧子树
    144         return Tree_Search(key,x->left);
    145     else//右侧子树
    146         return Tree_Search(key,x->right);
    147 }
    148 //迭代查找:对于大多数计算机,迭代版本的效率要高的多 :调用函数开销
    149 template<typename T>
    150 std::shared_ptr<Tree_Note<T>>
    151 BST<T>::Iterative_Tree_Search(const T& key,std::shared_ptr<Tree_Note<T>> x)
    152 {
    153     while (x != nullptr && key != x->key)
    154     {
    155         if (key < x->key)
    156             x = x->left;
    157         else
    158             x = x->right;
    159     }
    160     return x;
    161 }
    162 //中序遍历
    163 template<typename T>
    164 void BST<T>::Iorder_Tree_Walk(const std::shared_ptr<Tree_Note<T>> x)
    165 {
    166     if (x != nullptr)
    167     {
    168         Iorder_Tree_Walk(x->left);
    169         std::cout << x->key << " ";
    170         Iorder_Tree_Walk(x->right);
    171     }
    172 }
    173 //最小值
    174 template<typename T>
    175 std::shared_ptr<Tree_Note<T>>
    176 BST<T>::Tree_Minimum(std::shared_ptr<Tree_Note<T>> x)
    177 {
    178     while (x->left != nullptr)
    179         x = x->left;
    180     return x;
    181 }
    182 //最大值
    183 template<typename T>
    184 std::shared_ptr<Tree_Note<T>>
    185 BST<T>::Tree_Maximum(std::shared_ptr<Tree_Note<T>> x)
    186 {
    187     while (x->right != nullptr)
    188         x = x->right;
    189     return x;
    190 }
    191 //后继和前驱
    192 template<typename T>
    193 std::shared_ptr<Tree_Note<T>>
    194 BST<T>::Tree_Successor(std::shared_ptr<Tree_Note<T>> x)
    195 {
    196     if (x->right != nullptr) // 对接近大于x的节点 处在右子树中最小值
    197         return Tree_Minimum(x->right);
    198     //从x开始向上寻找节点:该结点不是父节点的右孩子 (如果是右孩子则x.right不会为空)
    199     auto y(x->parent);
    200     while (y != nullptr && x == y->right)
    201     {
    202         x = y;
    203         y = y->parent;
    204     }
    205     return y;//第一个不是右孩子的节点
    206 }
    207 template<typename T>
    208 std::shared_ptr<Tree_Note<T>> 
    209 BST<T>::Tree_Predecessor(std::shared_ptr<Tree_Note<T>> x)
    210 {
    211     if (x->left != nullptr)
    212         return Tree_Maximum(x->right);
    213     auto y = x->parent;
    214     while (y != nullptr && x == y->left)
    215     {
    216         x = y;
    217         y = y->parent;
    218     }
    219     return y;
    220 }
    221 
    222 //插入和删除
    223 template<typename T>
    224 void BST<T>::Tree_Insert(std::shared_ptr<Tree_Note<T>> z)
    225 {
    226     //临时量用于确定z位置:不要调用make_shared 则不满足 !=nullptr 为空树时条件
    227     std::shared_ptr<Tree_Note<T>> y = nullptr;
    228 //    auto y = std::make_shared<Tree_Note<T>>();
    229     auto x(root);
    230     //当x为空时,x就是待插入的位置
    231     while (x != nullptr) 
    232     {
    233         y = x;
    234         if (z->key < x->key)
    235             x = x->left;
    236         else//包括相等的情况 具有稳定性:后插入的在右边
    237             x = x->right;
    238     }
    239     z->parent = y;
    240     if (y == nullptr)
    241         root = z;
    242     else if (z->key < y->key)
    243         y->left = z;
    244     else
    245         y->right = z;
    246 }
    247 
    248 template<typename T>
    249 void BST<T>::Tree_Delete(std::shared_ptr<Tree_Note<T>> z)
    250 {
    251     if (z->left == nullptr) //(a)
    252         Transplant(z, z->right);
    253     else if (z->right == nullptr) //(b)
    254         Transplant(z, z->left);
    255     else
    256     {
    257         auto y = Tree_Minimum(z->right);
    258         if (y->parent != z) //(c):y不是z的右孩子 
    259         {
    260             Transplant(y, y->right);
    261             y->right = z->right;
    262             y->right->parent = y;
    263         }
    264         //(d):y是z的右孩子 且y,left == nullptr 如果y的左孩子不是空则 y不是z的后继
    265         Transplant(z, y);
    266         y->left = z->left; //y的左孩子(拼接)指向被删除点z的左孩子
    267         y->left->parent = y; //相当于 z = y
    268     }
    269 }

    main

     1 #include<iostream>
     2 #include<vector>
     3 #include"Binary_Seach_Tree.h"
     4 using namespace std;
     5 
     6 void BSTree()
     7 {
     8     vector<int> vi{ 1,2,5,8,6,9,6 };
     9     BST<int> t;
    10     //插入
    11     for (auto i = 0;i != vi.size();++i)
    12         t.Tree_Insert(vi[i]);
    13     cout << "中序遍历" << endl;
    14     t.Iorder_Tree_Walk();
    15     cout << endl;
    16     cout << "最大值" << endl;
    17     cout << t.Tree_Maximum() << endl;
    18     cout << "最小值" << endl;
    19     cout << t.Tree_Minimum() << endl;
    20     cout << "查找" << endl;
    21     cout << boolalpha << t.Tree_Seach(8) << endl;
    22     cout << "删除" << endl;
    23     t.Tree_Delete(8);
    24     cout << boolalpha << t.Iterative_Tree_Search(8) << endl;
    25 }
    26 
    27 
    28 int main()
    29 {
    30     BSTree();
    31     return 0;
    32 }

    删除:form 《算法导论》 P167

    关于其他操作请看二叉查找树(二)之 C++的实现

  • 相关阅读:
    06月14日总结
    06月11日总结
    高并发、高性能、高可用技术论述
    GCC制作静态库过程和使用
    每日总结
    GCC制作共享库过程和使用
    每日总结
    每日总结
    每日总结
    每日总结
  • 原文地址:https://www.cnblogs.com/Z-s-c11/p/13940670.html
Copyright © 2020-2023  润新知