map和set的使用,二叉搜索树,红黑树的实现

Use set

Set简介:具有指定顺序的容器,不允许修改节点的值,可以插入或者删除节点的值,根据Compare来比较(compare是内部仿函数,默认是严格的小于)。(底层是红黑树)
介绍几个关键的:
find:find会在set里面去寻找相同的节点,若找到,则返回指其的iterator(迭代器),没找到返回end(),也是迭代器。
在这里插入图片描述
erase:如下图,有三种情况,删除某迭代器指定位置,删除某个值,删除某段迭代器区间。

iterator erase (const_iterator position);
如果没有这个位置,程序会直接崩掉
返回值是删除的节点的下一个节点
如果删除的是最后一个就返回end()

size_type erase (const value_type& val);
返回成功删除的值的个数

iterator erase (const_iterator first, const_iterator last);
删除迭代器区间
返回值是删除的最后一个节点的下一个节点
如果删除的是最后一个就返回end()

在这里插入图片描述

loewr_bound:返回一个迭代器,其指向的相等或者之后的。(默认情况的严格小于排序就是>=,有闭区间那意思),意思就是说,可以给一个值位于其存在的区间之间,返回下一个值。
例:已经插入的值 :2,10,20
结果就是:lower_bound(8) == 10

iterator lower_bound (const value_type& val);
const_iterator lower_bound (const value_type& val) const;

upper_bound:返回一个迭代器,其指向于val之后的一个值(有开区间那味道)
例子:插入值为12,20,30

upper_bound(20)
upper_bound(21)
默认情况下:上面两个结果都是30

iterator upper_bound (const value_type& val);const_iterator upper_bound (const value_type& val) const;

equal_range:返回迭代器区间,对这个区间左闭有开的看法,必然包含val这个元素。不代表对迭代器遍历就会有这个元素,只是返回区间包含。

pair<const_iterator,const_iterator> equal_range (const value_type& val) const;pair<iterator,iterator>

测试代码:

void test_1()
{
    set<int> s;//random number test
    s.insert(5);
    s.insert(1);
    s.insert(1);//值已经有了,就不会再插入//通过键值对绑定一个bool值来实现
    s.insert(1);
    s.insert(3);
    s.insert(2);
    s.insert(4);
    s.insert(6);
    set<int>::iterator it = s.begin();
    while(it!=s.end()) 
    {
        cout<<*it<<" ";
        it++;
    }
    cout<<endl;

    it = s.find(2);
    if(it!=s.end())
    {
        s.erase(it);
    }
    // s.erase(it);//给迭代器的话,删除的值不存在程序会直接崩溃

    cout<<s.erase(2);//直接erase,某个值,就算不存在,就会返回一些值。返回删除该值的个数
    cout<<endl;
    for(auto num:s)
    {
        cout<<num<<" ";
    }
    cout<<endl;
    return ;
}


void test_2()
{
    set<int> s;
    for(int i=0;i<10;i++){
        s.insert(i*10);
    }
    auto itlow = s.lower_bound(25);
    auto itup = s.upper_bound(70);//这里返回的是实际比70大的下一个值的迭代器
    // cout<<*itup<<endl;//这里打印的值就是80
    s.erase(itlow,itup);//删除这段区间的值,而且删除的是闭区间,
    for(auto num:s)
    {
        cout<<num<<" ";
    }
    cout<<endl;
}

void test_3()
{
    set<int> s;
    for(int i=0;i<10;i++){
        s.insert(i*10);
    }

    pair<set<int>::iterator,set<int>::iterator> ret = s.equal_range(20);//找到相等的值,返回相等的值开始及其下一个区间
    ret  =s.equal_range(35);//这里返回的是大于当前值的下一个值。
    cout<<*(ret.first)<<" "<<*(ret.second)<<endl;
}

void test_Mutiset()
{
    multiset<int> s;//其就是底层的pair不再是bool值,而是变成了其他的计数类型
    s.insert(5);
    s.insert(1);
    s.insert(2);
    s.insert(2);
    s.insert(2);
    s.insert(4);
    s.insert(6);
    auto it = s.find(2);
    while(it!=s.end()){
        cout<<*it<<' ';
        it++;
    }
    cout<<endl;

    cout<<s.erase(2)<<endl;//显示了成功删除的个数

    pair<multiset<int>::iterator,multiset<int>::iterator> ret = s.equal_range(2);//对于mutiset,就会返回set
    while(ret.first!=ret.second)
    {
        cout<<*ret.first;
        s.erase(ret.first++);
    }
    cout<<endl;
    return ;
}

Use map

Map是一种映射,存在key value 和mapped value之间存在映射(就像函数一样),允许使用“ [] ”来通过key值去访问映射值,底层是二叉搜索树。
其他的使用基本都和set是一样的。
着重讲一下 []的
其实现是

(*((this->insert(make_pair(k,mapped_type()))).first))
((this->insert(make_pair(k,mapped_type()))).first)
*((this->insert(make_pair(k,mapped_type())))
(this->insert(make_pair(k,mapped_type()))
this->insert(make_pair(k,mapped_type())

再来看看insert,意思就是说成功,返回插入的值的迭代器指向的第一个元素,如果有,返回已有迭代器。

The single element versions (1) return a pair, with its member
pair::first set to an iterator pointing to either the newly inserted
element or to the element with an equivalent key in the map. The
pair::second element in the pair is set to true if a new element was
inserted or false if an equivalent key already existed.

测试代码:

void test_map2(){
    string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜","苹果", "香蕉", "苹果", "香蕉" };
    map<string, int> m;
    for(auto& str:arr)
    {
        // auto it = m.find(str);
        // if(it == m.end())//没有这个元素
        // {
        //     m.insert(make_pair(str,1));
        //     continue;
        // }
        // else
        // {
        //     it->second++;
        // }

        m[str]++;//在map里面,提供了[]的接口,可以替代上面
        //其底层实际就是调用了一次insert
        //(*((this->insert(make_pair(k,mapped_type()))).first)).
        //有了,那个key值,就会插入失败,并且对当前节点修改
        //这表征了,如果再次插入相同的值,map就不会再多
        //mutimap就可以可以插入多个相同的key值当value值不同
    }
}

map和set的底层实际都是红黑树,红黑树又是以二叉搜索树为基准。

底层实现

先介绍:二叉搜索树。

二叉搜索树

二叉搜索树的性质就是,完成左子树的节点总是比父节点的值小,右子树总是比父节点大。

二叉搜索树的插入:这个相对较简单,就是找到一个节点,如果节点的值满足比插入值小,且右节点为空,或者比插入值大,左节点为空。

示例代码

#include <bits/stdc++.h>
using namespace  std;
template <class T>
struct BSTNode
{
    BSTNode(const T &x = T())
    :data(x)
    ,left(nullptr)
    ,right(nullptr)
    {}
    T data;
    BSTNode<T> *left, *right;
};


template<class T>
class BSTree
{
    private:
    	typedef RBTreeNode<KeyType,ValueType>* RBTreeNodePtr;
    RBTreeNodePtr m_root;
        typedef BSTNode<T> Node;
        Node *root;
    public:
    BSTree()
    :root(nullptr)
    {

    }
    bool insert(const T& data)
    {
        if(root==nullptr)//单独处理下头结点
        {
            root = new Node;
            root->data = data;
            return true;
        }
        Node *curNode = root;
        while(curNode!=nullptr)
        {
            if(data<curNode->data)
            {
                if(curNode->left==nullptr)
                {
                    curNode->left = new Node;
                    curNode->left->data = data;
                    return true;
                }
                curNode = curNode->left;
            }
            else if(data>curNode->data)
            {
                if(curNode->right==nullptr)
                {
                    curNode->right = new Node;
                    curNode->right->data = data;
                    return true;
                }
                curNode = curNode->right;
            }
            else
            {
            	//有相同的插入失败。
                curNode = nullptr;
                break;
            }

        }
        return false;
    }

稍微麻烦点的是删除
erase:删除某个节点,通过二叉搜索树先找到这个节点。(find可以自己去实现比较简单,逻辑和insert类似)找到某个节点之后。
分以下几种:
1.删除节点左节点为空,或者右节点为空。
那么,让其右节点或者左节点顶替即可。
右节点为空示意图
在这里插入图片描述
2,删除节点左右节点都为空,删除该节点,将其父节点指向置为空即可。
3,若左右节点都不为空,则找到其左边最小,或者右边最小节点来与其交换,然后删除出交换的那个节点位置即可。
在这里插入图片描述

**上面就是删除节点的基本思路,虽然思路是那样,但是里面有一个特殊的节点删除值得注意,那就是根节点,根节点是没有父节点,erase时是需要额外注意的。

bool erase(const T&data)
    {
        Node* parent = root;
        Node* curnode = root;
        while(curnode)
        {
            if(curnode->data>data)
            {
                parent = curnode;
                curnode = curnode->left;
            }
            else if(curnode->data<data)
            {
                parent = curnode;
                curnode = curnode->right;
            }
            else//开始删除
            {
                if(curnode->left==nullptr)
                {
                    if(curnode==root)
                    {
                        root=curnode->right;
                    }
                    else
                    {
                        if(parent->left==curnode)
                        {
                            parent->left = curnode->right;

                        }
                        else
                        {
                            parent->right = curnode->right;
                        }
                    }
                }
                else if(curnode->right==nullptr)
                {
                    if(curnode==root)
                    {
                        root=curnode->left;
                    }
                    else
                    {
                        if(parent->left==curnode)
                        {
                            parent->left = curnode->left;
                        }
                        else
                        {
                            parent->right = curnode->left;
                        }
                    }
                }
                else
                {
                	//说明要找左边最大或者右边最小,就必有父节点
                	//这里找的右边
                    Node* ChildLeft = curnode->right;
                    parent = curnode;
                    while(ChildLeft->left)
                    {
                        parent = ChildLeft;
                        ChildLeft = ChildLeft->left;
                    }
                    swap(ChildLeft->data,curnode->data);
                    //这里判断一次,是为了防止右节点的左子树直接就是空
                    //这里就需要吧右节点直接顶替,考虑情况,算下左右节点。
                    if(ChildLeft==parent->left)
                    {
                        parent->left = ChildLeft->right;
                    }
                    else
                    {
                        parent->right = ChildLeft->right;
                    }
                    delete ChildLeft;
                    ChildLeft = nullptr;
                }
                
                return 1;
            }
        }
        return 0;
    }

红黑树

对二叉搜索树搞明白之后,接下来看红黑树。
满足以下条件,我们称之为红黑树:
1.每个节点要么是红色,要么是黑色。
2.根节点必须是黑色。
3.所有叶子节点(这里叶子结点实际指的就是空节点)都应该是黑色(或者叫都算作黑色)。
4.如果一个节点是红色,则它的两个子节点都是黑色。(红不连续,有说法红黑相见,其实不对,因为有黑-黑的情况)
5.对于每一条从节点到其子孙节点的路径,该路径上的黑色节点数量相同。(任意路径相同的黑色高度)

满足上面的条件,二叉树之间高度差,不会超过两倍,其具体原理就不再介绍了。

红黑树的节点设立如下,为了方便寻找父节点,设立成三叉树,同时设立一个颜色,对于key和val值不重点,整体理解成key值即可。

enum BackgroundColor{
    BLACK = 0,RED=1,
};
template <class KeyType,class ValueType>
struct RBTreeNode{
    typedef RBTreeNode<KeyType,ValueType>* RBTreeNodePtr;
    
    RBTreeNode(pair<KeyType,ValueType> kv = make_pair(KeyType(),ValueType()),BackgroundColor Inicolor =RED)
    : _kv(kv),left(nullptr),right(nullptr),parent(nullptr),color(Inicolor)
    {
        ;
    }
    pair<KeyType,ValueType> _kv;
    RBTreeNodePtr left;
    RBTreeNodePtr right;
    RBTreeNodePtr parent;
    BackgroundColor color;
};

下面是插入的代码,其基本体是和二叉搜索树是一样的,这里由于后面封装的缘故,做了些头结点连接的操作。
因为插入黑节点总是破坏平衡,所以我们插入默认是红,这样即使破坏,也不用破坏路径。
剩下就是调整了。

RBTree中做了些重定义:
typedef RBTreeNode<KeyType,ValueType> * RBTreeNodePtr;
这是为了后序表达更简洁

红黑树的插入

bool insert(const pair<KeyType,ValueType>& kv)
    {
        if(nullptr==m_root)
        {
            //让header指向父亲指向根节点,左指向最小,右指向最大
            m_root = new RBTreeNode<KeyType,ValueType>(kv,BLACK);
            m_header->left = m_root;
            m_header->right = m_root;

            //根节点父节点是header
            m_header->parent = m_root;
            m_root->parent = m_header;
            return true;
        }
        if(kv.first==36)
        {
            int cc = 100;
        }
            RBTreeNodePtr cur = m_root;
            RBTreeNodePtr CurPrt = nullptr;
            while(cur)
            {
                if(cur->_kv.first > kv.first)
                {
                    if(nullptr==cur->left)
                    {
                        cur->left = new RBTreeNode(kv);
                        cur->left->parent = cur;
                        adjust(cur->left,cur);
                        break;
                    }
                    else
                    {
                        cur = cur->left;
                        CurPrt = cur;
                    }
                }
                else if(cur->_kv.first < kv.first)
                {
                    if(nullptr==cur->right)
                    {
                        cur->right = new RBTreeNode(kv);
                        cur->right->parent = cur;
                        adjust(cur->right,cur);
                        break;
                    }
                    else
                    {
                        cur = cur->right;
                        CurPrt = cur;
                    }
                }
                else
                {
                    //已经存在,暂时先不做处理,认为插入失败
                    break;
                    return false;
                }
            }
            m_root->color= BLACK;
            m_header->left = LeftestNode();
            m_header->right = RightestNode();
            return true;
    }

插入节点后的调整

首先我们就要考虑什么时候要调整:
1.父亲是黑色:不需要调整,符合规则,直接退出
2.父亲是红色节点:那么就要考虑如何做了,是不是总得对当前节点调整颜色,那么会影响的什么?
调整的话会对哪些有影响:
1.父亲节点,
2.祖父节点
3.舅舅节点

倘若Cur变成黑色,是不是这三个会被影响,可能由于他们之间的关系,导致路径距离不一样,所以我们需要考虑做如下调整。
进行分类
一:Unc是红色,进行如下调整即可,交换祖父和Cur的节点即可。
在这里插入图片描述
二:Unc是黑色(不论是空还是是黑色,因为空也算黑色)
1.左左,即父亲是爷爷左儿子,儿子是父亲的左儿子, 那我们是不是让父亲作为祖父那个节点,使Cur作为左节点,G作为父亲的右节点即可。
旋转上选择所谓的右旋(被旋转节点对旋转中心而言的右旋也就是顺时针),就会得到下面的结果,且其整个黑色节点高度不会改变。
在这里插入图片描述
2.1:剩下就是左右,父节点是爷爷节点的左节点,Cur是父节点的右节点。
这种情况下,先对父亲左旋(逆时针),再对祖父右旋(顺时针即可)。
在这里插入图片描述
3.1和3.2分别是右右和右左,这里不过多介绍。其实和上面两种情况是对称的,不多赘述。

实现代码如下:

RBTreeNodePtr  RightRotate(RBTreeNodePtr root)//传要传输的旋转的父节点其父亲所指向的那个节点
    {
        RBTreeNodePtr left = root->left;
        RBTreeNodePtr Childright = left->right;
        
        root->left = Childright;
        if(Childright)
        {
            Childright->parent = root;
        }
        //节点之间的值就算交换完毕
        
        left->right = root;
        root->parent = left;

        return left;
    }
    void Rotate(RBTreeNodePtr parent,RBTreeNodePtr(RBTree<KeyType, ValueType>::*Rotatefunc)(RBTreeNodePtr))
    {
        RBTreeNodePtr PP = parent->parent;
        if(PP && PP!=m_header)
        {
            RBTreeNodePtr Child = (this->*Rotatefunc)(parent);
            if(PP->left == parent)
            {
                PP->left = Child;
                Child->parent = PP;
            }
            else
            {
                PP->right = Child;
                Child->parent = PP;
            }
        }
        else//说明遇见了根节点
        {
            m_root= (this->*Rotatefunc)(parent);
            m_root->parent = m_header;
            m_header ->parent = m_root;
        }
    }
    RBTreeNodePtr LeftRotate(RBTreeNodePtr root)
    {
        RBTreeNodePtr right = root->right;
        RBTreeNodePtr Childleft = right->left;

        root->right = Childleft;
        if(Childleft)
        {
            Childleft->parent = root;
        }

        right->left = root;
        root->parent = right;

        return right;
    }

    bool adjust(RBTreeNodePtr Cur,RBTreeNodePtr CurPrt)
    {
        //在节点插入中,Cur一来应该不会是根节点,调整到根节点,直接退出
        //应该说,父亲不应该会空,应为根节点会直接插入

        RBTreeNodePtr CurGrp = CurPrt->parent;
        RBTreeNodePtr CurUnc= nullptr;
        
        while(Cur && Cur!=m_root)//直到不会是根节点
        {
            if(CurPrt->color==BLACK)
            {
                //理论上说,color节点new的时候默认是红,这里防止出现意外操作下
                Cur->color = RED;
                return true;
            }
            //每次的舅舅节点
            if(CurGrp->left==CurPrt)
            {
                CurUnc = CurGrp->right;
            }
            else{
                CurUnc = CurGrp->left;
            }
            if(CurUnc&& CurUnc->color==RED)//舅舅节点是红色,向上调整
            {
                CurPrt->color = BLACK;
                CurUnc->color = BLACK;
                Cur->color = RED;
                //处理祖孙的颜色变化

                Cur = CurGrp;
                Cur->color = RED;
                //调整其父亲,祖父节点,因为每次舅舅节点都会算,就不需要额外调整
                CurPrt = Cur->parent;
                CurGrp = CurPrt->parent;
            }
            else//舅舅节点是黑色
            {
                if(CurPrt==CurGrp->left)
                {
                    if(Cur==CurPrt->left)
                    {
                        //左左,对祖父节点进行右单旋
                        CurGrp->color = RED;
                        CurPrt->color = BLACK;
                        Rotate(CurGrp,&RightRotate);
                    }
                    else{
                        //左右,先对父亲左单旋,再对祖父右单旋
                        //
                        Cur->color = BLACK;
                        CurGrp->color = CurPrt->color = RED;
                        Rotate(CurPrt,&LeftRotate);
                        Rotate(CurGrp,&RightRotate);
                    }
                }
                else if(CurPrt==CurGrp->right)
                {
                    if(Cur==CurPrt->right)
                    {
                        //右右
                        CurGrp->color = BackgroundColor::RED;
                        CurPrt->color = BLACK;
                        Rotate(CurGrp,&LeftRotate);
                    }
                    else
                    {
                        //右左
                        Cur->color = BLACK;
                        CurGrp->color = CurPrt->color = RED;
                        Rotate(CurPrt,&RightRotate);
                        Rotate(CurGrp,&LeftRotate);
                    }
                }
                //不用在进行调整,至此结束
                break;
            }
        }
        return false;
    }

红黑树的删除:由于目前能力及时间问题未能实现更新,后序会更新出红黑树底层的删除

目前完整的代码:

#pragma once
#include <bits/stdc++.h>
using namespace std;

enum BackgroundColor{
    BLACK = 0,RED=1,
};
template <class KeyType,class ValueType>
struct RBTreeNode{
    typedef RBTreeNode<KeyType,ValueType>* RBTreeNodePtr;
    
    RBTreeNode(pair<KeyType,ValueType> kv = make_pair(KeyType(),ValueType()),BackgroundColor Inicolor =RED)
    : _kv(kv),left(nullptr),right(nullptr),parent(nullptr),color(Inicolor)
    {
        ;
    }
    pair<KeyType,ValueType> _kv;
    RBTreeNodePtr left;
    RBTreeNodePtr right;
    RBTreeNodePtr parent;
    BackgroundColor color;
};


template <class KeyType,class ValueType>
class RBTree{
    private:
    typedef RBTreeNode<KeyType,ValueType>* RBTreeNodePtr;
    RBTreeNodePtr m_root;
    RBTreeNodePtr m_header;

    private:
    RBTreeNodePtr LeftestNode()
    {
        RBTreeNodePtr cur = m_root;
        while(cur && cur->left)
        {
            cur = cur->left;
        }
        return cur;
    }
    
    RBTreeNodePtr RightestNode()
    {
        RBTreeNodePtr cur = m_root;
        while(cur&&cur->right)
        {
            cur = cur->right;
        }
        return cur;
    }
    RBTreeNodePtr  RightRotate(RBTreeNodePtr root)//传要传输的旋转的父节点其父亲所指向的那个节点
    {
        RBTreeNodePtr left = root->left;
        RBTreeNodePtr Childright = left->right;
        
        root->left = Childright;
        if(Childright)
        {
            Childright->parent = root;
        }
        //节点之间的值就算交换完毕
        
        left->right = root;
        root->parent = left;

        return left;
    }
    void Rotate(RBTreeNodePtr parent,RBTreeNodePtr(RBTree<KeyType, ValueType>::*Rotatefunc)(RBTreeNodePtr))
    {
        RBTreeNodePtr PP = parent->parent;
        if(PP && PP!=m_header)
        {
            RBTreeNodePtr Child = (this->*Rotatefunc)(parent);
            if(PP->left == parent)
            {
                PP->left = Child;
                Child->parent = PP;
            }
            else
            {
                PP->right = Child;
                Child->parent = PP;
            }
        }
        else//说明遇见了根节点
        {
            m_root= (this->*Rotatefunc)(parent);
            m_root->parent = m_header;
            m_header ->parent = m_root;
        }
    }
    RBTreeNodePtr LeftRotate(RBTreeNodePtr root)
    {
        RBTreeNodePtr right = root->right;
        RBTreeNodePtr Childleft = right->left;

        root->right = Childleft;
        if(Childleft)
        {
            Childleft->parent = root;
        }

        right->left = root;
        root->parent = right;

        return right;
    }

    bool adjust(RBTreeNodePtr Cur,RBTreeNodePtr CurPrt)
    {
        //在节点插入中,Cur一来应该不会是根节点,调整到根节点,直接退出
        //应该说,父亲不应该会空,应为根节点会直接插入

        RBTreeNodePtr CurGrp = CurPrt->parent;
        RBTreeNodePtr CurUnc= nullptr;
        
        while(Cur && Cur!=m_root)//直到不会是根节点
        {
            if(CurPrt->color==BLACK)
            {
                //理论上说,color节点new的时候默认是红,这里防止出现意外操作下
                Cur->color = RED;
                return true;
            }
            //每次的舅舅节点
            if(CurGrp->left==CurPrt)
            {
                CurUnc = CurGrp->right;
            }
            else{
                CurUnc = CurGrp->left;
            }
            if(CurUnc&& CurUnc->color==RED)//舅舅节点是红色,向上调整
            {
                CurPrt->color = BLACK;
                CurUnc->color = BLACK;
                Cur->color = RED;
                //处理祖孙的颜色变化

                Cur = CurGrp;
                Cur->color = RED;
                //调整其父亲,祖父节点,因为每次舅舅节点都会算,就不需要额外调整
                CurPrt = Cur->parent;
                CurGrp = CurPrt->parent;
            }
            else//舅舅节点是黑色
            {
                if(CurPrt==CurGrp->left)
                {
                    if(Cur==CurPrt->left)
                    {
                        //左左,对祖父节点进行右单旋
                        CurGrp->color = RED;
                        CurPrt->color = BLACK;
                        Rotate(CurGrp,&RightRotate);
                    }
                    else{
                        //左右,先对父亲左单旋,再对祖父右单旋
                        //
                        Cur->color = BLACK;
                        CurGrp->color = CurPrt->color = RED;
                        Rotate(CurPrt,&LeftRotate);
                        Rotate(CurGrp,&RightRotate);
                    }
                }
                else if(CurPrt==CurGrp->right)
                {
                    if(Cur==CurPrt->right)
                    {
                        //右右
                        CurGrp->color = BackgroundColor::RED;
                        CurPrt->color = BLACK;
                        Rotate(CurGrp,&LeftRotate);
                    }
                    else
                    {
                        //右左
                        Cur->color = BLACK;
                        CurGrp->color = CurPrt->color = RED;
                        Rotate(CurPrt,&RightRotate);
                        Rotate(CurGrp,&LeftRotate);
                    }
                }
                //不用在进行调整,至此结束
                break;
            }
        }
        return false;
    }
    public:
    void InorderPrint()
    {
        InorderPrintR(m_root);
        cout<<"\n";
    }
    void InorderPrintR(RBTreeNodePtr root)
    {
        if(root==nullptr)
        {
            return ;
        }
        InorderPrintR(root->left);
        cout<<root->_kv.first<<" ,";
        InorderPrintR(root->right);
    }
    RBTree()
    : m_root(nullptr)
    {
        //
        m_header = new RBTreeNode(make_pair(KeyType(),ValueType()));
        m_header->left = m_header->right = m_header->parent = nullptr;
        m_header->color = BLACK;
    }
    bool insert(const pair<KeyType,ValueType>& kv)
    {
        if(nullptr==m_root)
        {
            //让header指向父亲指向根节点,左指向最小,右指向最大
            m_root = new RBTreeNode<KeyType,ValueType>(kv,BLACK);
            m_header->left = m_root;
            m_header->right = m_root;

            //根节点父节点是header
            m_header->parent = m_root;
            m_root->parent = m_header;
            return true;
        }
        if(kv.first==36)
        {
            int cc = 100;
        }
            RBTreeNodePtr cur = m_root;
            RBTreeNodePtr CurPrt = nullptr;
            while(cur)
            {
                if(cur->_kv.first > kv.first)
                {
                    if(nullptr==cur->left)
                    {
                        cur->left = new RBTreeNode(kv);
                        cur->left->parent = cur;
                        adjust(cur->left,cur);
                        break;
                    }
                    else
                    {
                        cur = cur->left;
                        CurPrt = cur;
                    }
                }
                else if(cur->_kv.first < kv.first)
                {
                    if(nullptr==cur->right)
                    {
                        cur->right = new RBTreeNode(kv);
                        cur->right->parent = cur;
                        adjust(cur->right,cur);
                        break;
                    }
                    else
                    {
                        cur = cur->right;
                        CurPrt = cur;
                    }
                }
                else
                {
                    //已经存在,暂时先不做处理,认为插入失败
                    break;
                    return false;
                }
            }
            m_root->color= BLACK;
            m_header->left = LeftestNode();
            m_header->right = RightestNode();
            return true;
    }
    

    int height(RBTreeNodePtr root)
    {
        if(root==nullptr)
        {
            return 0;
        }
        int leftheight = height(root->left);
        int rightheight = height(root->right);
        return 1+(leftheight>rightheight?leftheight:rightheight);
    }
    vector<vector<pair<pair<KeyType,ValueType>,BackgroundColor>>> LevelPrint()
    {
        const char* COLOR[2] = {"BLACK","RED"};
        cout<<"********************************\n\n";
        vector<vector<pair<pair<KeyType,ValueType>,BackgroundColor>>> res;
        list<RBTreeNodePtr> nodelist(1,m_root);
        int NowNodeNum = 1,nextLevelNodeNum = 0;
        vector<pair<pair<KeyType,ValueType>,BackgroundColor>> nowlevel;
        while(nodelist.size())
        {
            RBTreeNodePtr p = nodelist.front();
            nodelist.pop_front();
            nowlevel.push_back(make_pair(p->_kv,p->color));
            if(p->left)
            {
                nodelist.push_back(p->left);
                nextLevelNodeNum++;
            }
            if(p->right)
            {
                nodelist.push_back(p->right);
                nextLevelNodeNum++;
            }

            if(--NowNodeNum==0)
            {
                res.push_back(nowlevel);
                nowlevel.clear();
                NowNodeNum = nextLevelNodeNum;
                nextLevelNodeNum = 0;
            }
        }
        for (int i = 0; i < res.size(); i++)
        {
            for (int j = 0; j < res[i].size(); j++)
            {
                cout << res[i][j].first.first << " " <<COLOR[res[i][j].second]<<"\t";
            }
            cout<<endl;
        }
        cout<<"********************************\n\n";
        return res;
    }

    bool test()
    {
        RBTreeNodePtr Cur = m_root;
        int count = 1;
        while(Cur)
        {
            if(Cur->color==BLACK)
            {
                count++;
            }
            Cur = Cur->left;
        }
        return Judge(m_root,0,count);
    }
    bool Judge(RBTreeNodePtr root,size_t k,size_t count)
    {
        if(root==nullptr)
        {
            return k+1==count;
        }
        if(root->color==BLACK)
        {
            k++;
        }
        return Judge(root->left,k,count)&&Judge(root->right,k,count);
    }
    
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值