当前位置: 首页 > wzjs >正文

天津网站建设好公司动易网络 官方网站

天津网站建设好公司,动易网络 官方网站,购物网站开发背景需求,常州网站制作案例封装红黑树实现mymap和myset 1. 源码及框架分析2. 模拟实现map和set2.1 实现出复⽤红⿊树的框架,并⽀持insert2.2 ⽀持iterator的实现2.3 map⽀持[]2.4 完整实现 1. 源码及框架分析 SGI-STL30版本源代码,map和set的源代码在map/set/stl_map.h/stl_set.h…

封装红黑树实现mymap和myset

  • 1. 源码及框架分析
  • 2. 模拟实现map和set
    • 2.1 实现出复⽤红⿊树的框架,并⽀持insert
    • 2.2 ⽀持iterator的实现
    • 2.3 map⽀持[]
    • 2.4 完整实现

1. 源码及框架分析

SGI-STL30版本源代码,map和set的源代码在map/set/stl_map.h/stl_set.h/stl_tree.h等⼏个头⽂件
中。
map和set的实现结构框架核⼼部分截取出来如下:

// set
#ifndef __SGI_STL_INTERNAL_TREE_H
#include <stl_tree.h>
#endif
#include <stl_set.h>
#include <stl_multiset.h>
// map
#ifndef __SGI_STL_INTERNAL_TREE_H
#include <stl_tree.h>
#endif
#include <stl_map.h>
#include <stl_multimap.h>
// stl_set.h
template <class Key, class Compare = less<Key>, class Alloc = alloc>
class set {
public:// typedefs:typedef Key key_type;typedef Key value_type;
private:typedef rb_tree<key_type, value_type, identity<value_type>, key_compare, Alloc> rep_type;rep_type t; // red-black tree representing set
};
// stl_map.h
template <class Key, class T, class Compare = less<Key>, class Alloc = alloc>
class map {
public:
// typedefs:typedef Key key_type;typedef T mapped_type;typedef pair<const Key, T> value_type;
private:typedef rb_tree<key_type, value_type, select1st<value_type>, key_compare, Alloc> rep_type;rep_type t; // red-black tree representing map
};
// stl_tree.h
struct __rb_tree_node_base
{typedef __rb_tree_color_type color_type;typedef __rb_tree_node_base* base_ptr;color_type color; base_ptr parent;base_ptr left;base_ptr right;
};
// stl_tree.h
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc 
= alloc>
class rb_tree {
protected:typedef void* void_pointer;typedef __rb_tree_node_base* base_ptr;typedef __rb_tree_node<Value> rb_tree_node;typedef rb_tree_node* link_type;typedef Key key_type;typedef Value value_type;
public:// insert⽤的是第⼆个模板参数左形参 pair<iterator,bool> insert_unique(const value_type& x);// erase和find⽤第⼀个模板参数做形参 size_type erase(const key_type& x);iterator find(const key_type& x);
protected:size_type node_count; // keeps track of size of treelink_type header;
};
template <class Value>
struct __rb_tree_node : public __rb_tree_node_base
{typedef __rb_tree_node<Value>* link_type;Value value_field;};

SGI版本中插入的结点中数据类型是value_type,通过key_type进行查找。

• set实例化rb_tree时第⼆个模板参数给的是key,map实例化rb_tree时第⼆个模板参数给的是pair<const key,T>,这样⼀颗红⿊树既可以实现set也可以实现map

• rb_tree第⼆个模板参数Value已经控制了红⿊树结点中存储的数据类型,为什么还要传第⼀个模板参数Key呢?尤其是set,两个模板参数是⼀样的,但是是为了代码能复用。这样在针对map的情况下就不需要重新定义模版了

2. 模拟实现map和set

2.1 实现出复⽤红⿊树的框架,并⽀持insert

• 参考源码框架,map和set复⽤之前我们实现的红⿊树。
• 我们这⾥相⽐源码调整⼀下,key参数就⽤K,value参数就⽤V,红⿊树中的数据类型,我们使⽤T。
• 其次因为RBTree实现了泛型不知道T参数导致是K,还是pair<K,V>,那么insert内部进⾏插⼊的是T逻辑⽐较的是K,而set中T和K是一个东西,map中T和K不是同一个东西所以我们在map和set层分别实现⼀个MapKeyOfT和SetKeyOfT的仿函数传给RBTree的KeyOfT,然后RBTree中通过KeyOfT仿函数取出T类型对象中的key,再进⾏⽐较,具体细节参考如下代码实现。

class map
{struct MapKeyOfT{const K& operator()(const pair<K, V>& kv){return kv.first;}};public:typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::Iterator iterator;typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::ConstIterator const_iterator;
template<class K>
class set
{struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:typedef typename RBTree<K, const K, SetKeyOfT>::Iterator iterator;typedef typename RBTree<K, const K, SetKeyOfT>::ConstIterator const_iterator;
template<class K, class T, class KeyOfT>
class RBTree
{
private:typedef RBTreeNode<T> Node;Node* _root = nullptr;public:bool Insert(const T& data){if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;return true;}KeyOfT kot;Node* parent = nullptr;Node* cur = _root;while (cur){if (kot(cur->_data) < kot(data)){parent = cur;cur = cur->_right;}else if (kot(cur->_data) > kot(data)){parent = cur;cur = cur->_left;}else{return false;}}cur = new Node(data);Node* newnode = cur;// 新增结点。颜⾊给红⾊ cur->_col = RED;if (kot(parent->_data) < kot(data)){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;//...return true;}
}

2.2 ⽀持iterator的实现

iterator实现思路分析
• iterator实现的⼤框架跟list的iterator思路是⼀致的,⽤⼀个类型封装结点的指针,再通过重载运算符实现,迭代器像指针⼀样访问的⾏为。
• 这⾥的难点是operator++和operator–的实现。map和set的迭代器⾛的是中序遍历,左⼦树->根结点->右⼦树,那么begin()会返回中序第⼀个结点的iterator也就是最左的结点
• 迭代器++的核⼼逻辑就是不看全局,只看局部,只考虑当前中序局部要访问的下⼀个结点。
• 迭代器++时,如果it指向的结点的右⼦树不为空,代表当前结点已经访问完了(指左结点当前结点),++要访问下⼀个结点是当前结点的右⼦树的最左结点即可。
• 迭代器++时,如果it指向的结点的右⼦树空,代表当前结点已经访问完了且当前结点所在的⼦树也访问完了(要返回了),要访问的下⼀个结点在当前结点的祖先⾥⾯,所以要沿着当前结点到根的祖先路径向上找。
• 如果当前结点是⽗亲的左,根据中序左⼦树->根结点->右⼦树,那么下⼀个访问的结点就是当前结点的⽗亲;
• 如果当前结点是⽗亲的右,根据中序左⼦树->根结点->右⼦树,当前当前结点所在的⼦树访问完了,当前结点所在⽗亲的⼦树也访问完了,那么下⼀个访问的需要继续往根的祖先中去找,直到找到孩⼦是⽗亲左的那个祖先就是中序要问题的下⼀个结点。
• end()如何表⽰呢?到根时没有⽗亲,没有找到孩⼦是⽗亲左的那个祖先,这是⽗亲为空了,那我们就把it中的结点指针置为nullptr,我们⽤nullptr去充当end。

如何这样的话无法实现end()–
stl源码中红⿊树增加了⼀个哨兵位头结点做为end(),这哨兵位头结点和根互为⽗亲,左指向最左结点,右指向最右结点。
• 迭代器–的实现跟++的思路完全类似,逻辑正好反过来即可,因为他访问顺序是右⼦树->根结点->左⼦树,具体参考下⾯代码实现。
• set的iterator也不⽀持修改,我们把set的第⼆个模板参数改成const K即可, RBTree<K, const K, SetKeyOfT> _t;
• map的iterator不⽀持修改key但是可以修改value,我们把map的第⼆个模板参数pair的第⼀个参数改成const K即可, RBTree<K, pair<const K, V>, MapKeyOfT> _t;

template<class T, class Ref, class Ptr>
struct RBTreeIterator
{typedef RBTreeNode<T> Node;typedef RBTreeIterator<T, Ref, Ptr> Self;Node* _node;Node* _root;RBTreeIterator(Node* node, Node* root):_node(node), _root(root)//为了支持end()--的操作,否则逻辑实现起来比较复杂{}Self operator++(){if (_node->_right){// 右不为空,中序下一个访问的节点是右子树的最左(最小)节点Node* min = _node->_right;while (min->_left){min = min->_left;}_node = min;}else{// 右为空,祖先里面孩子是父亲左的那个祖先Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_right){cur = parent;parent = cur->_parent;}_node = parent;}return *this;}Self operator--(){if (_node == nullptr)  // --end(){// --end()我们要去找到中序遍历的最后一个结点,找这个结点得从根开始遍历但是迭代器没有封装根我们如何去找呢?因此这里要封装根Node* rightMost = _root;while (rightMost && rightMost->_right){rightMost = rightMost->_right;}_node = rightMost;}else if (_node->_left){// 左子树不为空,中序左子树最后一个Node* rightMost = _node->_left;while (rightMost->_right){rightMost = rightMost->_right;}_node = rightMost;}else{// 孩子是父亲右的那个祖先Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_left){cur = parent;parent = cur->_parent;}_node = parent;}return *this;}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator!= (const Self& s) const{return _node != s._node;}bool operator== (const Self& s) const{return _node == s._node;}
};

2.3 map⽀持[]

• map要⽀持[]主要需要修改insert返回值⽀持,修改RBtree中的insert返回值为
pair<Iterator, bool> Insert(const T& data)• 有了insert⽀持[]实现就很简单了,具体参考下⾯代码实现

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

2.4 完整实现

template<class K, class V>
class map
{struct MapKeyOfT{const K& operator()(const pair<K, V>& kv){return kv.first;}};public:typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::Iterator iterator;typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::ConstIterator const_iterator;iterator begin(){return _t.Begin();}iterator end(){return _t.End();}const_iterator begin() const{return _t.Begin();}const_iterator end()  const{return _t.End();}pair<iterator, bool> insert(const pair<K, V>& kv){return _t.Insert(kv);}V& operator[](const K& key){pair<iterator, bool> ret = insert({ key, V() });return ret.first->second;}private:RBTree<K, pair<const K, V>, MapKeyOfT> _t;
};
http://www.dtcms.com/wzjs/819964.html

相关文章:

  • 网站mp3播放器代码wordpress用户注册之后不显示密码
  • 响应式网页设计网站建设济南手机建站公司
  • 书写网站建设策划书中国建筑网官网视频
  • 国内有名的网站设计公司制作网站要多少费用
  • 网站建设 牛商网技术提供怎样设置个人官方网站
  • 网站建设互联网推广网站备案哪里管
  • 门户网站有哪些类型家政网站模板下载
  • 百度建设公司网站赣州app开发
  • 科技公司网站模板下载创建企业营销网站包括哪些内容
  • 全栈网站开发商标设计网免费
  • 网站后台无法修改做挂的网站
  • 工商核名在哪个网站百度seo官网
  • 专门做免费东西试吃的网站沈阳犀牛云做网站怎么样
  • 晚上睡不着看点害羞的东西app拼多多关键词优化步骤
  • 如何用普通电脑做网站服务器网站导入链接
  • 邢台做网站的公司有那个小游戏免费入口
  • 枣庄市住房和城乡建设局网站办网站除了域名备案 还需要什么
  • 搜索引擎网站模板华强北商城官网入口
  • 有没有公司直招的网站郑州抖音seo推广
  • 兰州网站建设lst0931整站seo哪家服务好
  • 网站响应时间 标准食堂网站建设
  • 网站工程就业前景西安网站建设招骋
  • 软件开发和网站建设哪个好做网站公司 备案
  • 网站建设技术部职责外贸管理软件免费
  • 医院网站建设的重要性软件开发定制案例
  • 免费做网站的网址有哪些郑州网站设计专家
  • 专业零基础网站建设教学建站seo推广
  • 网站建设必须要虚拟主机吗wordpress免费教程视频
  • 西安wordpress建站购物网站功能设计
  • 网站建设的公司价格谷歌地图下载