zoukankan      html  css  js  c++  java
  • Red_Black_Tree C++

    红黑树

    总的来说 掌握思想就好:细节没记住

    //算法导论书中的else表示case3要改成具体情况:还有不存在的情况要跳过
    //例如:else = else if(z == z.p.left)

    知识点:

    1、指针比较地址 :z->right == nil     *(z->right )== *nil 报错:没有定义 operator==      因为:RBT_note_type<T> right 是类类型

          所以 加一个bool nil 成员处理 或者定义 operator==

     2、auto 需要初始化 :静态成员初始化要常量 而这里是<T> 不可以

          c++14 中 auto可以作为返回类型,需要注意auto remove const and &

    3、constexpr:如果传递给一个constexpr function 的实参在编译期已知,结果也是在编译期已知

    例如 :《Effective Modern C++》

    #pragma once
    class Point
    {
    public:
        constexpr Point(double xVal = 0, double yVal = 0) noexcept
            :x(xVal), y(yVal) {}
        constexpr double xValue() const noexcept { return x; }
        constexpr double yValue() const noexcept { return y; }
    
        void setX(double newX) noexcept { x = newX; }
        void setY(double newY) noexcept { y = newY; }
    private:
        double x;
        double y;
    };
    
    constexpr
    Point midpoint(const Point& p1, const Point& p2) noexcept
    {
        return { (p1.xValue() + p2.xValue()) / 2,
            (p1.yValue() + p2.yValue()) / 2 };
    }
    
    constexpr auto mid = midpoint(p1, p2);
    
    static_cast<int>(mid.xValue()*10) 可用于模板形参

    红黑树是每个节点都带有颜色属性的二叉查找树,颜色为红色黑色。在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:

    1. 节点是红色或黑色。
    2. 根是黑色。
    3. 所有叶子都是黑色(叶子是NIL节点)。
    4. 每个红色节点必须有两个黑色的子节点。(从每个叶子到根的所有路径上不能有两个连续的红色节点。)
    5. 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。

    下面是一个具体的红黑树的图

    这些约束确保了红黑树的关键特性:从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果是这个树大致上是平衡的。因为操作比如插入、删除和查找某个值的最坏情况时间都要求与树的高度成比例,这个在高度上的理论上限允许红黑树在最坏情况下都是高效的,而不同于普通的二叉查找树

    要知道为什么这些性质确保了这个结果,注意到性质4导致了路径不能有两个毗连的红色节点就足够了。最短的可能路径都是黑色节点,最长的可能路径有交替的红色和黑色节点。因为根据性质5所有最长的路径都有相同数目的黑色节点,这就表明了没有路径能多于任何其他路径的两倍长。

    在很多树数据结构的表示中,一个节点有可能只有一个子节点,而叶子节点包含数据。用这种范例表示红黑树是可能的,但是这会改变一些性质并使算法复杂。为此,本文中我们使用"nil叶子"或"空(null)叶子",如上图所示,它不包含数据而只充当树在此结束的指示。这些节点在绘图中经常被省略,导致了这些树好像同上述原则相矛盾,而实际上不是这样。与此有关的结论是所有节点都有两个子节点,尽管其中的一个或两个可能是空叶子。

    #RED_BLACK_TREE_NOTE.h

    #pragma once
    #include<memory>
    #include<iostream>
    
    //优先选用限定作用域的enum
    // 降低空间污染
    //不会隐式转换
    
    //color
    enum class color
    {
        //默认const int不能默认转换
        red,black
    };
    
    //友元所需声明
    template<typename T> class Red_Black_Tree;
    template<typename T> class Red_Black_Tree_Note;
    //using 声明
    template<typename T>
    using RBT_note_type = std::shared_ptr<Red_Black_Tree_Note<T>>;
    template<typename T>
    void Right_Rotate(Red_Black_Tree<T> &Tree
        , RBT_note_type<T> y);
    template<typename T>
    void Left_Rotate(Red_Black_Tree<T> &Tree,
        RBT_note_type<T> x);
    template<typename T>
    void RB_Transplant(Red_Black_Tree<T>& Tree
        , RBT_note_type<T> &u, RBT_note_type<T> &v);
    
    //Note
    template<typename T>
    class Red_Black_Tree_Note
    {
        friend class Red_Black_Tree<T>;
        friend void Left_Rotate<T>(Red_Black_Tree<T>&
            , RBT_note_type<T>);
        friend void Right_Rotate<T>(Red_Black_Tree<T>&
            , RBT_note_type<T>);
        friend void RB_Transplant<T>(Red_Black_Tree<T>& Tree
            , RBT_note_type<T> &u, RBT_note_type<T> &v);
    public:
        Red_Black_Tree_Note(const T& _key = T())
            :key(_key),left(std::make_shared<Red_Black_Tree_Note<T>>('*')),
            right(std::make_shared<Red_Black_Tree_Note<T>>('*')), p(nullptr),tree_color(color::black),nil(false) {}
        Red_Black_Tree_Note(char)
            :key(T()),left(nullptr), right(nullptr), p(nullptr), tree_color(color::black),nil(true) {}
    
    private:
        T key;
        RBT_note_type<T> left;
        RBT_note_type<T> right;
        RBT_note_type<T> p;
        color tree_color;
        bool nil;
    };
    //左旋
    template<typename T>
    void Left_Rotate(Red_Black_Tree<T> &Tree, RBT_note_type<T> x)
    {
        auto y(x->right);
        x->right = y->left;
        if (y->left->nil != true)
            y->left->p = x;
        y->p = x->p;
        if (x->p->nil == true)
            Tree.root = y;
        else if (x == x->p->left)
            x->p->left = y;
        else
            x->p->right = y;
        y->left = x;
        x->p = y;
    }
    //右旋
    template<typename T>
    void Right_Rotate(Red_Black_Tree<T> &Tree
        , RBT_note_type<T> y)
    {
        auto x(y->left);
        y->left = x->right;
        if (x->right->nil != true)
            x->right->p = y;
        x->p = y->p;
        if (y->p->nil == true)
            //C2232“->Red_Black_Tree<int>::root”: 左操作数有“class”类型,使用“.”
            Tree.root = x;
        else if (y == y->p->right)
            y->p->right = x;
        else
            y->p->left = x;
        x->right = y;
        y->p = x;
    }
    //移植
    template<typename T>
    void RB_Transplant(Red_Black_Tree<T>& Tree
        ,RBT_note_type<T> &u,RBT_note_type<T> &v)
    {
        //u->p 不存在
    //    if (u->p == Tree.nil)
        if(u->p->nil == true)
            Tree.root = v;
        //报错:读取访问权限冲突:解决把函数放在Tree类 private
        else if (u == u->p->left)
            u->p->left = v;
        else
            u->p->right = v;
        v->p = u->p;
    }

    #RED_BLACK_TREE.h

    #pragma once
    //算法导论书中的else表示case3要改成具体情况:还有不存在的情况要跳过
    //例如:else = else if(z == z.p.left)
    #include<iostream>
    #include<functional> //less
    #include"RED_BLACK_TREE_NOTE.h"
    
    template<typename T>
    class Red_Black_Tree
    {
        friend void Left_Rotate<T>(Red_Black_Tree<T> &Tree
            , RBT_note_type<T> x);
        friend void Right_Rotate<T>(Red_Black_Tree<T> &Tree
            , RBT_note_type<T> x);
        friend void RB_Transplant<T>(Red_Black_Tree<T>& Tree
            , RBT_note_type<T> &u, RBT_note_type<T> &v);
    public:
        Red_Black_Tree() :nil(std::make_shared<Red_Black_Tree_Note<T>>('*')),root(std::make_shared<Red_Black_Tree_Note<T>>('*')) {}
        //中序遍历
        void Iorder_Tree_Walk(const RBT_note_type<T> &x);
        void Iorder_Tree_Walk() { Iorder_Tree_Walk(root); }
        //迭代查找 迭代改变要搜索的x 不能引用&x
        //c++14 中 auto可以作为返回类型,需要注意auto remove const and &
        //若要完成版 则:decltype(auto) return std::forward<T>(x); forward 处理右值情况
        auto Iterative_Tree_Search(const T& key, RBT_note_type<T> x);
        bool Iterative_Tree_Search(const T& key)
        {
            auto p = Iterative_Tree_Search(key, root);
            if (p != nullptr && p->nil != true)
                return true;
            else
                return false;
        }
        //最小值 : 迭代搜索 不能 &x ,不能返回引用:p是局部变量程序
        RBT_note_type<T> Tree_Minimum(RBT_note_type<T> x);
        T Tree_Minimum()
        {
            auto p = Tree_Minimum(root);
            return p->key;
        }
        //插入
        void RB_INSERT(const RBT_note_type<T> &z);
        void RB_Insert(const T& key)
        {
            auto z = std::make_shared<Red_Black_Tree_Note<T>>(key);
            RB_INSERT(z);
        }
        //删除 
        void RB_DELETE(RBT_note_type<T> z);
        void RB_Delete(const T& key)
        {
            auto z = Iterative_Tree_Search(key, root);
            if (z == nullptr || z->nil == true)
                std::cerr << "nodata!";
            else
                RB_DELETE(z);
        }
    
    private:
        RBT_note_type<T> root;
        //非静态成员不能使用auto 
        //静态成员初始化要用常量 这里是模板<T>
        RBT_note_type<T> nil;
    
        void RB_INSERT_FIXUP(RBT_note_type<T> z);
        void RB_DELETE_FIXUP(RBT_note_type<T> z);
    };
    //中序遍历中nil的key值要排除
    template<typename T>
    inline void Red_Black_Tree<T>::Iorder_Tree_Walk(const RBT_note_type<T> &x)
    {
        if (x != nullptr&&x->nil != true)
        {
            Iorder_Tree_Walk(x->left);
            std::cout << x->key << " ";
            Iorder_Tree_Walk(x->right);
        }
    }
    template<typename T>
    inline auto Red_Black_Tree<T>::Iterative_Tree_Search(const T& key, RBT_note_type<T> x)
    {
        while (x != nullptr && x->nil != true && key != x->key)
        {
            if (key < x->key)
    //        if(std::less<T>(key,x->key)) //const key 无法转换
                x = x->left;
            else
                x = x->right;
        }
        return x;
    }
    //最小值
    template<typename T>
    RBT_note_type<T>
    Red_Black_Tree<T>::Tree_Minimum(RBT_note_type<T> x)
    {
        while (x->left != nullptr && x->left->nil != true)
            x = x->left;
        return x;
    }
    
    //插入
    template<typename T>
    void Red_Black_Tree<T>::RB_INSERT_FIXUP(RBT_note_type<T> z)
    {
        while (z->p->tree_color == color::red)
        {
            if (z->p == z->p->p->left)
            {
                auto y(z->p->p->right);
                if (y->tree_color == color::red)
                {
                    z->p->tree_color = color::black;
                    y-> tree_color = color::black;
                    z-> p-> p->tree_color = color::black;
                    z = z->p->p;
                }
                else if (z == z->p->right)
                {
                    z = z->p;
                    Left_Rotate<T>(*this, z);
                }
                else if (z == z->p->left)
                {
                    z->p->tree_color = color::black;
                    z->p->p->tree_color = color::red;
                    Right_Rotate(*this, z->p->p);
                }
            }
            else if (z->p == z->p->p->right)
            {
                    auto y(z->p->p->left);
                    //case1
                    if (y->tree_color == color::red)
                    {
                        z->p->tree_color = color::black;
                        y->tree_color = color::black;
                        z->p->p->tree_color = color::black;
                        z = z->p->p;
                    }
                    //case2
                    else if (z == z->p->left)
                    {
                        z = z->p;
                        Right_Rotate(*this, z);
                    }
                    //case3
                    else if (z == z->p->right)
                    {
                        z->p->tree_color = color::black;
                        //在插入第三个数时,因为case1 z = z.p.p执行后z为root
                        //则z.p.p为无效内存,不可访问会报错
                        z->p->p->tree_color = color::red;
                        Left_Rotate<T>(*this, z->p->p);
                    }
            }
                root->tree_color = color::black;
        }
    }
    
    template<typename T>
    void Red_Black_Tree<T>::RB_INSERT(const RBT_note_type<T> &z)
    {
        auto y(nil);
        auto x(root);
        //不知道为什么 while(x != nil) 条件会通过 <BRT_note_type> 没有 operator!=
        // x = root = nil = ('*')
        while (x->nil != true)
        {
            y = x;
            if (z->key < x->key)
                x = x->left;
            else
                x = x->right;
        }
        z->p = y;
        if (y->nil == true)
            root = z;
        else if (z->key < y->key)
            y->left = z;
        else
            y->right = z;
        z->left = nil;
        z->right = nil;
        z->tree_color = color::red;//如果黑色必然违反规则:每条路上黑色结点数相同
        RB_INSERT_FIXUP(z);
    }
    
    //删除
    template<typename T>
    void Red_Black_Tree<T>::RB_DELETE_FIXUP(RBT_note_type<T> x)
    {
        while (x != root && x->tree_color == color::black)
        {
            if (x == x->p->left)
            {
                auto w(x->p->right);
                //case1
                if (w->tree_color == color::red)
                {
                    w->tree_color = color::black;
                    x->p->tree_color = color::red;
                    Left_Rotate(*this, x->p);
                    w = x->p->right;
                }
                //case2
                if (w->left->tree_color == color::black && w->right->tree_color == color::black)
                {
                    w->tree_color = color::red;
                    x = x->p;
                }
                //case3
                else if (w->right->tree_color == color::black)
                {
                    w->left->tree_color = color::black;
                    w->tree_color = color::red;
                    Right_Rotate(*this, w);
                    w = x->p->right;
                }
                w->tree_color = x->p->tree_color;
                x->p->tree_color = color::black;
                w->right->tree_color = color::black;
                Left_Rotate(*this, x->p);
                x = root;
            }
            if (x == x->p->right)
            {
                auto w(x->p->left);
                if (w->tree_color == color::red)
                {
                    w->tree_color = color::black;
                    x->p->tree_color = color::red;
                    Right_Rotate(*this, x->p);
                    w = x->p->left;
                }
                if (w->right->tree_color == color::black && w->left->tree_color == color::black)
                {
                    w->tree_color = color::red;
                    x = x->p;
                }
                else if (w->left->tree_color == color::black)
                {
                    w->right->tree_color = color::black;
                    w->tree_color = color::red;
                    Left_Rotate(*this, w);
                    w = x->p->left;
                }
                w->tree_color = x->p->tree_color;
                x->p->tree_color = color::black;
                w->left->tree_color = color::black;
                Right_Rotate(*this, x->p);
                x = root;
            }
        }
        x->tree_color = color::black;
    }
    template<typename T>
    void Red_Black_Tree<T>::RB_DELETE(RBT_note_type<T> z)
    {
        auto y(z);
        auto x(nil);
        color y_original_color = y->tree_color;
        if (z->left->nil == true)
        {
            x=z->right;
            RB_Transplant(*this, z, z->right);
        }
        //else if (z->right == nil || z->right == nullptr) 会跳过
        else if (z->right->nil == true)
        {
            x = z->left;
            RB_Transplant(*this, z, z->left);
        }
        else
        {
            y = Tree_Minimum(z->right);
            y_original_color = y->tree_color;
            x = y->right;
            if (y->p == z)
                x->p = y;
            else
            {
                RB_Transplant(*this, y, y->right);
                y->right = z->right;
                y->right->p = y;
            }
            RB_Transplant(*this, z, y);
            y->left = z->left;
            y->left->p = y;
            y->tree_color = z->tree_color;
        }
        if (y_original_color == color::black)
            RB_DELETE_FIXUP(x);
    }

    main.cpp

    #include<iostream>
    #include<vector>
    #include"Binary_Seach_Tree.h"
    #include"RED_BLACK_TREE.h"
    
    
    using namespace std;
    /*
    void BSTree()
    {
        vector<int> vi{ 1,2,5,8,6,9,6 };
        BST<int> t;
        //插入
        for (auto i = 0;i != vi.size();++i)
            t.Tree_Insert(vi[i]);
        cout << "中序遍历" << endl;
        t.Iorder_Tree_Walk();
        cout << endl;
        cout << "最大值" << endl;
        cout << t.Tree_Maximum() << endl;
        cout << "最小值" << endl;
        cout << t.Tree_Minimum() << endl;
        cout << "查找" << endl;
        cout << boolalpha << t.Tree_Seach(8) << endl;
        cout << "删除" << endl;
        t.Tree_Delete(8);
        cout << boolalpha << t.Iterative_Tree_Search(8) << endl;
    }
    */
    
    void RBT()
    {
        vector<int> vi{ 1,2,5,4,6,3,99,1,-6 };
        Red_Black_Tree<int> t;
        for (const auto& i : vi)
            t.RB_Insert(i);
        t.Iorder_Tree_Walk();
        cout << endl;
        t.RB_Delete(99);
        t.Iorder_Tree_Walk();
        cout << endl;
        t.RB_Delete(1);
        t.Iorder_Tree_Walk();
    }
    int main()
    {
        RBT();
        string s1{ "abc" };
        string s2{ "acd" };
        if (s1 > s2)
            cout << "66";
        const int i = 0;
        auto y = i;
        y = 6;
        return 0;
    }
  • 相关阅读:
    win10自动休眠解决方法
    创世纪游戏、黄金分割比
    placeholder和assign速度对比
    内耗
    windows下编写dll
    北航院系和数字的对应关系
    maven Could not resolve dependencies
    java9模块不可见问题
    maven-dependencies插件的模拟实现
    Freemarker简单封装
  • 原文地址:https://www.cnblogs.com/Z-s-c11/p/14021943.html
Copyright © 2011-2022 走看看