[C++]STL--set与map的封装

一、红黑树结点设计

        由于set是K模型的而map是KV模型的,并且他们两个都复用的是同一份红黑树代码,所以我们不能将红黑树的保存的数据类型定死,我们可以利用模版将data设置为T类型的,这样红黑树也不知道数据是什么类型的,只有set和map给他实例化的时候,传入什么类型数据就是什么类型

ps:红黑树实现博客

示意图:

二、红黑树插入设计

在插入的模块中,一定涉及到了结点数据大小的比较,由于红黑树本身并不知道数据data的类型是什么,可能是就是一个值,也可能是pair的结构体,所以不可以直接进行比较。例如set就是根据key值进行比较,而map虽然也是根据key值比较,但是key和value是封装正在pair中的,pair本身也是支持比较大小的,但是其比较逻辑不符合map,为了解决比较大小的问题,我们可以利用仿函数,返回需要比较的元素

ps:这里有一个问题,模版参数为什么要多一个K(key的类型)呢?set本身就是根据key进行比较的,写这个仿函数有什么意义呢?

【解释】:对于插入来说set和map都用不着这个K,但是对于Find来说map只需要根据key来查找,虽然pair中也存在key,但是用pair会很麻烦,为了让map使用key方便,所以多加了一个类型。而set不论是比较还是Find,set自己本身就不需要仿函数和多一个类型,但是由于set和map复用的是同一份红黑树的代码,为了兼容map,set也只能这样做了

三、迭代器

3.1 红黑树迭代器设计
template<class T, class Ref, class Ptr>
struct __RBTreeIterator
{
	typedef RBTreeNode<T> Node;
	typedef __RBTreeIterator<T, Ref, Ptr> Self;
	Node* _node;   //封装一个node

	__RBTreeIterator(Node* node)
		:_node(node)
	{}
    
	Ref operator*()
	{
		return _node->_data;
	}

	Ptr operator->()
	{
		return &_node->_data;
	}

	bool operator!=(const Self& s)
	{
		return _node != s._node;
	}
}
3.2 迭代器++

红黑树的遍历是中序遍历,要满足左 根 右的遍历顺序,当迭代器++找下一个元素时,如果该节点存在右子树,下一个访问的节点一定是右子树的最左节点,如果该节点不存在右子树,就说明以该结点为根的子树已经全部访问过了,此时下一个访问的节点应该向上寻找,找节点是父亲结点左边的祖先(要注意下一个访问的节点不一定是父亲结点)

Self& operator++()
{
    if (_node->_right)
    {
        Node *LeftMin = _node->_right;
        while (LeftMin && LeftMin->_left)
        {
            LeftMin = LeftMin->_left;
        }
        _node = LeftMin;
    }
    else
    {
        // 找孩子为父亲左边的那个祖先
        Node *cur = _node;
        Node *parent = cur->_parent;
        while (parent && parent->_right == cur)
        {
            cur = parent;
            parent = parent->_parent;
        }
        _node = parent;
    }
    return *this;
}
3.3 迭代器Begin()与End()

Begin()返回的是树的最左节点,而End()一般返回的是最后一个节点的下一个节点,这里我们将它设置为空

Iterator Begin()
{
    Node *LeftMin = _root;
    while (LeftMin && LeftMin->_left)
    {
        LeftMin = LeftMin->_left;
    }
    return Iterator(LeftMin);
}

Iterator End()
{
    return Iterator(nullptr);
}

四、map的[ ]实现

对于set和map来说,map还支持[ ],在方括号中传入key值,就会返回对应的value值,[ ]的实现其实是利用insert来实现的。插入函数的返回值其实是一个pair类型,第一个参数是结点的迭代器,第二个参数是bool类型,当插入对应的key时,若树中已存在,则设置该节点的迭代器并将bool置为false,如果是新插入的节点,也会返回这个节点的迭代器,并将bool置为true。所以我们需要将插入函数的返回值改变一下。

[ ]实现:

V& operator[](const K& key)
{
	pair<iterator, bool> ret = _t.Insert(make_pair(key,V()));
	return ret.first->second;
}

红黑树实现及set、map封装详细代码:begining: Record my growth - Gitee.com

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张呱呱_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值