网站建设对电子商务的作用,海外营销是干什么的,wordpress上一个,手机网站的特效目录 
一、set/map的底层结构 
1、set/map的源码 
2、利用模板区分set/map 
3、利用仿函数控制比较大小 
二、set/map的迭代器#xff08;红黑树的迭代器#xff09; 
1、红黑树的begin、end迭代器 
2、红黑树迭代器的operator 
3、红黑树迭代器的operator-- 
三、set的const… 目录 
一、set/map的底层结构 
1、set/map的源码 
2、利用模板区分set/map 
3、利用仿函数控制比较大小 
二、set/map的迭代器红黑树的迭代器 
1、红黑树的begin、end迭代器 
2、红黑树迭代器的operator 
3、红黑树迭代器的operator-- 
三、set的const迭代器 
四、map的const迭代器 
五、迭代器类的拷贝构造 
六、整体代码 
1、RBTree.h 
2、Set.h 
3、map.h 本文相关往期内容可按需查阅 1、【C】set/multiset、map/multimap的使用 
2、【数据结构】二叉搜索树的实现 
3、【数据结构】平衡二叉树 
4、【数据结构】手撕红黑树 
本文难点使用红黑树封装set和map必须保证两种数据结构复用同一棵红黑树且满足set和map的性质set的value不可被改变而map的value可以被改变。 
一、set/map的底层结构 
1、set/map的源码 扒一扒STL库中set和map的底层结构不难发现set和map的底层用的都是红黑树且均为key/value模型。 
只不过set的key/value均为key值填充而map的key/value使用key和pairconst Key,T进行填充。因此set和map中底层虽然都是红黑树但这两种数据结构中的红黑树实例化类型并不相同。 
那么使用同一颗红黑树的模板如何实例化出适配set和/map的对象 
2、利用模板区分set/map 
template class T//T类型代表value
struct RBTreeNode
{RBTreeNode(const T data):_parent(nullptr), _left(nullptr), _right(nullptr), _data(data), _col(RED){}RBTreeNodeT* _parent;RBTreeNodeT* _left;RBTreeNodeT* _right;T _data;Color _col;
}; map和set的区别在于value的不同红黑树模板参数T代表value用以区分set和map。 
3、利用仿函数控制比较大小 我们会发现红黑树的插入等接口会对key值进行比较大小像set直接对key进行比较这没问题但是map中的节点装的是pairK,V,pair的比较规则是first比完之后可能会再去比较second而我们仅仅想要比较first该比较规则不适用。 
通过源码启发我们可以对红黑树新增一个模板参数仿函数KeyOfT在set和map类中完善该仿函数的比较对象用于区分set和map的比较 
template class K
class set
{//仿函数用于比较大小struct SetKeyOfT{const K operator()(const K key)//传入节点的值{return key;//返回key}};
private:RBTreeK, K, SetKeyOfT _t;
};
class map
{struct MapKeyOfT{const K operator()(const pairK, V kv)//传入节点的值{return kv.first;//返回kv.first}};
private:RBTreeconst K, pairK,V, MapKeyOfT _t;
};
//利用模板确定传入对象是set还是map
template class K, class T,class KeyOfT
class RBTree//红黑树
{}; 利用仿函数传入节点的值set将会返回key值map将会的返回pair的first。这样就解决了比较大小的规则问题。 二、set/map的迭代器红黑树的迭代器 
因为红黑树的中序遍历是有序的可以根据中序遍历作为迭代器--的依据。 
STL源码采用下图结构多搞了一个头结点。迭代器begin()可以指向header的左迭代器end()指向header。 不过本文采用无头结点的常规红黑树仿写红黑树的迭代器。 
1、红黑树的begin、end迭代器 2、红黑树迭代器的operator 
1、如果当前节点的右不为空迭代器返回右子树的最左节点 
2、如果当前节点的右为空迭代器返回祖先当前节点是父亲的左(end()-1迭代器返回nullptr即end()) 
template class T
struct __RBTreeIterator
{typedef RBTreeNodeT Node;typedef __RBTreeIteratorT Self;Node* _node;__RBTreeIterator(Node* node):_node(node){}//1、右不为空下一个节点是右树的最小节点//2、右为空去找右是父亲左的最近祖先Self operator()//找中序的下一个节点,即根的右树的最左节点,返回值是一个迭代器的对象{if (_node-_right ! nullptr){Node* min  _node-_right;while (min-_left ! nullptr){min  min-_left;}_node  min;}else{Node* cur  _node;Node* parent  cur-_parent;while (parent ! nullptr  cur  parent-_right){cur  cur-_parent;parent  parent-_parent;}_node  parent;}return *this;}bool operator!(const Self s){return _node ! s._node;}
}; 3、红黑树迭代器的operator-- 
1、如果当前节点的左不为空迭代器--返回左子树的最右节点 
2、如果当前节点的左为空迭代器--返回祖先当前节点是父亲的右 
template class T
struct __RBTreeIterator
{typedef RBTreeNodeT Node;typedef __RBTreeIteratorT Self;Node* _node;__RBTreeIterator(Node* node):_node(node){}Self operator--(){if (_node-_left!nullptr){Node* max  _node;while (max-_right){max  max-_right;}_node  max;}else{Node* cur  _node;Node* parent  cur-_parent;while (parent ! nullptr  cur  parent-_left){cur  cur-_parent;parent  parent-_parent;}_node  parent;}return *this;}
}; 三、set的const迭代器 
对于set和map它们的key都是不能改的。set的value不能修改map的value可以修改。 
因为set的value是不能改的所以它的底层将普通迭代器和const迭代器全部封装成const迭代器来“解决” 
//自己实现的不代表STL
typedef typename RBTreeK, K, SetKeyOfT::const_iterator iterator;
typedef typename RBTreeK, K, SetKeyOfT::const_iterator const_iterator; 封装之后又会出现新问题set使用迭代器其实都是在使用const迭代器但是自己实现的红黑树的迭代器接口返回普通类型的迭代器在Set.h中对this加上const“解决” 
iterator begin()const
{return _t.begin();
}
iterator end()const
{return _t.end();
} 这时使用迭代器调用上方函数会发现红黑树返回了普通迭代器类型的迭代器类型不匹配。在红黑树中补齐const版本的迭代器函数解决 
const_iterator begin()const//找红黑树最左节点
{Node* left  _root;while (left ! nullptr  left-_left ! nullptr){left  left-_left;}return const_iterator(left);
}
const_iterator end()const
{return const_iterator(nullptr);
} 四、map的const迭代器 
map的value是可以改的所以要分别设计普通迭代器和const迭代器。 
typedef typename RBTreeconst K, pairconst K, V, MapKeyOfT::iterator iterator;
typedef typename RBTreeconst K, pairconst K, V, MapKeyOfT::const_iterator 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();
} 五、迭代器类的拷贝构造 
STL库中的普通迭代器都可以转换为const迭代器这是迭代器类的拷贝构造所支持的。 
这个拷贝构造有点特殊 
//红黑树的迭代器
template class T,class Ref,class Ptr//key/value、T、T*
struct __RBTreeIterator
{typedef RBTreeNodeT Node;typedef __RBTreeIteratorT, Ref, Ptr Self;typedef __RBTreeIteratorT, T, T* iterator;Node* _node;__RBTreeIterator(Node* node):_node(node){}__RBTreeIterator(const iterator it)//const iterator本质还是普通迭代器:_node(it._node){}
}; 1、当这个模板的的Ref和PTR被实例化为T和T*时__RBTreeIterator(const iterator it)就是一个拷贝构造(没啥意义) 
2、当这个模板的的Ref和PTR被实例化为const T和const T*时__RBTreeIterator(const iterator it)就是一个构造函数支持用普通迭代器去构造const迭代器。此时const迭代器的拷贝构造函数则由编译器自动生成刚好满足迭代器值拷贝的特点。 
六、整体代码 
1、RBTree.h 
#pragma once
#include iostream
#include map
#include set
#include string
using namespace std;
enum Color
{RED,BLACK,
};
template class T//T类型代表value
struct RBTreeNode
{RBTreeNode(const T data):_parent(nullptr), _left(nullptr), _right(nullptr), _data(data), _col(RED){}RBTreeNodeT* _parent;RBTreeNodeT* _left;RBTreeNodeT* _right;T _data;Color _col;
};
//红黑树的迭代器
//        key/value T        T*
template class T,class Ref,class Ptr
struct __RBTreeIterator
{typedef RBTreeNodeT Node;typedef __RBTreeIteratorT, Ref, Ptr Self;typedef __RBTreeIteratorT, T, T* iterator;Node* _node;__RBTreeIterator(Node* node):_node(node){}__RBTreeIterator(const iterator it):_node(it._node){}Ref operator*(){return _node-_data;}Ptr operator-()//返回类型的地址{return _node-_data;}//1、右不为空下一个节点是右树的最小节点//2、右为空去找右是父亲左的最近祖先Self operator()//找中序的下一个节点,即根的右树的最左节点,返回值是一个迭代器的对象{if (_node-_right ! nullptr){Node* min  _node-_right;while (min-_left ! nullptr){min  min-_left;}_node  min;}else{Node* cur  _node;Node* parent  cur-_parent;while (parent ! nullptr  cur  parent-_right){cur  cur-_parent;parent  parent-_parent;}_node  parent;}return *this;}Self operator--(){if (_node-_left!nullptr){Node* max  _node;while (max-_right){max  max-_right;}_node  max;}else{Node* cur  _node;Node* parent  cur-_parent;while (parent ! nullptr  cur  parent-_left){cur  cur-_parent;parent  parent-_parent;}_node  parent;}return *this;}bool operator!(const Self s)const{return _node ! s._node;}bool operator(const Self s)const{return _node  s._node;}
};
//pair的比较是如果first小还要比second我们只要比first所以加了仿函数KeyOfT用以取出first进行比较
//set-RBTreeK, K, SetKeyOfT
//map-RBTreeconst K, pairK,V, MapKeyOfT
template class K, class T,class KeyOfT
class RBTree
{
public:typedef __RBTreeIteratorT,T,T* iterator;typedef __RBTreeIteratorT, const T, const T* const_iterator;iterator begin()//找红黑树最左节点{Node* left  _root;while (left!nullptrleft-_left!nullptr){left  left-_left;}return iterator(left);}iterator end(){return iterator(nullptr);}const_iterator begin()const//找红黑树最左节点{Node* left  _root;while (left ! nullptr  left-_left ! nullptr){left  left-_left;}return const_iterator(left);}const_iterator end()const{return const_iterator(nullptr);}typedef RBTreeNodeT Node;pairiterator,bool Insert(const T data)//对于map来说data是pair{if (_root  nullptr){_root  new Node(data);_root-_col  BLACK;//根节点给黑色return make_pair(iterator(_root), true);//返回插入的节点}KeyOfT kot;//搞一个仿函数对象//_root不为空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 make_pair(iterator(cur),false);//插入失败说明找到了返回被查找节点的迭代器}//开始插入cur  new Node(data);Node* newNode  cur;//记录cur的地址make_pair返回插入节点的地址cur-_col  RED;//新插入节点给红色可能违反规则。如果给黑色会导致其他路径的黑色节点数量不相同必定违反规则。  if (kot(parent-_data)  kot(data)){parent-_right  cur;cur-_parent  parent;//维护cur的父指针}else{parent-_left  cur;cur-_parent  parent;}//调整while (parent  parent-_col  RED){Node* grandfather  parent-_parent;//找到祖父if (grandfather-_left  parent)//如果父亲是祖父的左孩子{Node* uncle  grandfather-_right;//找到叔叔//情况一叔叔存在且为红if (uncle ! nullptr  uncle-_col  RED){//变色parent-_col  uncle-_col  BLACK;grandfather-_col  RED;cur  grandfather;parent  cur-_parent;}else//情况二或情况三{if (cur  parent-_left)//情况二直线{RotateRight(grandfather);//右单旋parent-_col  BLACK;grandfather-_col  RED;}else//情况三折线{RotateLeft(parent);//左单旋RotateRight(grandfather);//右单旋cur-_col  BLACK;grandfather-_col  RED;}break;}}else//如果父亲是祖父的右孩子{Node* uncle  grandfather-_left;if (uncle ! nullptr  uncle-_col  RED){parent-_col  uncle-_col  BLACK;grandfather-_col  RED;cur  grandfather;parent  cur-_parent;}else{if (cur  parent-_right)//情况二直线{//g//  p//    cRotateLeft(grandfather);//左单旋parent-_col  BLACK;grandfather-_col  RED;}else//情况三折线{//g//  p//c   RotateRight(parent);//右单旋RotateLeft(grandfather);//左单旋cur-_col  BLACK;grandfather-_col  RED;}break;}}}_root-_col  BLACK;return make_pair(iterator(newNode), true);//返回插入的节点}void Inorder(){_Inorder(_root);}bool IsBalance(){return _IsBalance();}
private:void _Inorder(Node* root){if (root  nullptr)return;_Inorder(root-_left);cout  kot(root-_data)  :  root-_data.second  endl;_Inorder(root-_right);}bool Check(Node* root, int blackNum, const int ref)//检查有没有连续红节点{if (root  nullptr){if (blackNum ! ref){cout  路径上黑节点数量不一致  endl;return false;}return true;}if (root-_col  BLACK){blackNum;}if (root-_col  RED  root-_parent-_col  RED){cout  违反规则父子均为红  endl;return false;}return Check(root-_left, blackNum, ref)  Check(root-_right, blackNum, ref);}bool _IsBalance(){if (_root  nullptr)return true;if (_root-_col ! BLACK){return false;}//数一下一条路径黑色节点数量int ref  0;//统计一条路上黑色节点的数量Node* left  _root;while (left ! nullptr){if (left-_col  BLACK){ref;}left  left-_left;}return Check(_root, 0, ref);}void RotateLeft(Node* parent)//左单旋{Node* grandfather  parent-_parent;Node* cur  parent-_right;if (parent  _root){_root  cur;cur-_parent  nullptr;}else{if (grandfather-_left  parent)//需要判定parent原来属于grandfather的哪一边grandfather-_left  cur;elsegrandfather-_right  cur;cur-_parent  grandfather;}parent-_right  cur-_left;if (cur-_left ! nullptr)cur-_left-_parent  parent;cur-_left  parent;parent-_parent  cur;}void RotateRight(Node* parent)//右单旋{Node* grandfather  parent-_parent;Node* cur  parent-_left;if (parent  _root){_root  cur;cur-_parent  nullptr;}else{if (grandfather-_left  parent){grandfather-_left  cur;cur-_parent  grandfather;}else{grandfather-_right  cur;cur-_parent  grandfather;}}parent-_parent  cur;parent-_left  cur-_right;if (cur-_right ! nullptr)cur-_right-_parent  parent;cur-_right  parent;}
private:Node* _root  nullptr;
}; 迭代器的begin(),end()接口放在红黑树这个类中而operator--放在迭代器这个类中自己写一下循环遍历红黑树的代码就知道为什么这样设计了。 
2、Set.h 
#pragma once
#include RBTree.h
namespace jly
{template class Kclass set{struct SetKeyOfT{const K operator()(const K key)//传入value{return key;}};public:typedef typename RBTreeK, K, SetKeyOfT::const_iterator iterator;typedef typename RBTreeK, K, SetKeyOfT::const_iterator const_iterator;pairiterator, bool insert(const K key){pairtypename RBTreeK, K, SetKeyOfT::iterator,bool ret _t.Insert(key);return pairiterator, bool(ret.first, ret.second);}iterator begin()const{return _t.begin();}iterator end()const{return _t.end();}private:RBTreeK, K, SetKeyOfT _t;};void test2(){//int a[]  { 8, 3, 1, 10, 6, 4, 7, 14, 13 };//int a[]  { 16, 3, 7, 11, 9, 26, 18, 14, 15 };int a[]  { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };//int a[]  { 9,8,7,6,5,4,3,2,1};setint s;for (auto e : a){s.insert(e);}setint::iterator it  s.begin();while (it ! s.end()){cout  *it   ;it;}}
} 3、map.h 
#pragma once
#include RBTree.h
namespace jly
{template class K,class Vclass map{struct MapKeyOfT{const K operator()(const pairK, V kv)//传入value{return kv.first;}};public://typename是C中用于指定一个类的类型的关键字。//通常用于表示某个类型是一个类类型而不是其他类型如int等。//这里不加typedef编译器无法区分iterator是一个类型还是一个静态变量。因为他俩都可以这么写。。//所以从类模板取出内嵌类型就需要加typedeftypedef typename RBTreeconst K, pairconst K, V, MapKeyOfT::iterator iterator;typedef typename RBTreeconst K, pairconst K, V, MapKeyOfT::const_iterator const_iterator;pairiterator,bool insert(const pairK, V kv){return _t.Insert(kv);}iterator begin(){return _t.begin();}iterator end(){return _t.end();}const_iterator begin()const{return _t.begin();}const_iterator end()const{return _t.end();}V operator[](const K key)//传入key值{pairiterator,bool ret _t.Insert(key,V());return ret.first-second;//找到retmake_pairiterator,bool的first解引用找到节点value}private:RBTreeconst K, pairconst K,V, MapKeyOfT _t;};void test1(){int a[]  { 8, 3, 1, 10, 6, 4, 7, 14, 13 };//int a[]  { 16, 3, 7, 11, 9, 26, 18, 14, 15 };//int a[]  { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };//int a[]  { 9,8,7,6,5,4,3,2,1};mapint,int m;for (auto e : a){m.insert(make_pair(e,e));}mapint, int::iterator it  m.begin();while (it ! m.end()){cout  (* it).first   ;it;}cout  endl;for (auto e : m){cout  e.first ;}}
} 文章转载自: http://www.morning.yhplt.cn.gov.cn.yhplt.cn http://www.morning.tbplf.cn.gov.cn.tbplf.cn http://www.morning.zxhhy.cn.gov.cn.zxhhy.cn http://www.morning.ldnrf.cn.gov.cn.ldnrf.cn http://www.morning.tkfnp.cn.gov.cn.tkfnp.cn http://www.morning.kwwkm.cn.gov.cn.kwwkm.cn http://www.morning.rpwm.cn.gov.cn.rpwm.cn http://www.morning.tygn.cn.gov.cn.tygn.cn http://www.morning.qzfjl.cn.gov.cn.qzfjl.cn http://www.morning.ggnjq.cn.gov.cn.ggnjq.cn http://www.morning.tnhg.cn.gov.cn.tnhg.cn http://www.morning.qdzqf.cn.gov.cn.qdzqf.cn http://www.morning.qydgk.cn.gov.cn.qydgk.cn http://www.morning.dlrsjc.com.gov.cn.dlrsjc.com http://www.morning.ghryk.cn.gov.cn.ghryk.cn http://www.morning.bbxbh.cn.gov.cn.bbxbh.cn http://www.morning.svrud.cn.gov.cn.svrud.cn http://www.morning.nxpqw.cn.gov.cn.nxpqw.cn http://www.morning.gxcym.cn.gov.cn.gxcym.cn http://www.morning.hsrpr.cn.gov.cn.hsrpr.cn http://www.morning.zpzys.cn.gov.cn.zpzys.cn http://www.morning.jxscp.cn.gov.cn.jxscp.cn http://www.morning.lgznc.cn.gov.cn.lgznc.cn http://www.morning.rcbdn.cn.gov.cn.rcbdn.cn http://www.morning.rgmd.cn.gov.cn.rgmd.cn http://www.morning.wflpj.cn.gov.cn.wflpj.cn http://www.morning.pdmc.cn.gov.cn.pdmc.cn http://www.morning.pfnlc.cn.gov.cn.pfnlc.cn http://www.morning.tnyanzou.com.gov.cn.tnyanzou.com http://www.morning.hmlpn.cn.gov.cn.hmlpn.cn http://www.morning.wsxly.cn.gov.cn.wsxly.cn http://www.morning.dqcpm.cn.gov.cn.dqcpm.cn http://www.morning.mwcqz.cn.gov.cn.mwcqz.cn http://www.morning.gprzp.cn.gov.cn.gprzp.cn http://www.morning.nlrp.cn.gov.cn.nlrp.cn http://www.morning.dqzcf.cn.gov.cn.dqzcf.cn http://www.morning.lynkz.cn.gov.cn.lynkz.cn http://www.morning.kxqfz.cn.gov.cn.kxqfz.cn http://www.morning.nmhpq.cn.gov.cn.nmhpq.cn http://www.morning.mprtj.cn.gov.cn.mprtj.cn http://www.morning.gbyng.cn.gov.cn.gbyng.cn http://www.morning.ydtdn.cn.gov.cn.ydtdn.cn http://www.morning.zyslyq.cn.gov.cn.zyslyq.cn http://www.morning.fhntj.cn.gov.cn.fhntj.cn http://www.morning.btrfm.cn.gov.cn.btrfm.cn http://www.morning.lqchz.cn.gov.cn.lqchz.cn http://www.morning.fpbj.cn.gov.cn.fpbj.cn http://www.morning.ypcd.cn.gov.cn.ypcd.cn http://www.morning.ltxgk.cn.gov.cn.ltxgk.cn http://www.morning.xykst.cn.gov.cn.xykst.cn http://www.morning.hxmqb.cn.gov.cn.hxmqb.cn http://www.morning.fnxzk.cn.gov.cn.fnxzk.cn http://www.morning.wwgpy.cn.gov.cn.wwgpy.cn http://www.morning.shsh1688.com.gov.cn.shsh1688.com http://www.morning.txtgy.cn.gov.cn.txtgy.cn http://www.morning.ylyzk.cn.gov.cn.ylyzk.cn http://www.morning.ynjhk.cn.gov.cn.ynjhk.cn http://www.morning.kcxtz.cn.gov.cn.kcxtz.cn http://www.morning.knpmj.cn.gov.cn.knpmj.cn http://www.morning.rynq.cn.gov.cn.rynq.cn http://www.morning.wdhzk.cn.gov.cn.wdhzk.cn http://www.morning.stsnf.cn.gov.cn.stsnf.cn http://www.morning.lcqrf.cn.gov.cn.lcqrf.cn http://www.morning.fqhbt.cn.gov.cn.fqhbt.cn http://www.morning.qlbmc.cn.gov.cn.qlbmc.cn http://www.morning.qpljg.cn.gov.cn.qpljg.cn http://www.morning.kgqpx.cn.gov.cn.kgqpx.cn http://www.morning.dzgyr.cn.gov.cn.dzgyr.cn http://www.morning.xrtsx.cn.gov.cn.xrtsx.cn http://www.morning.pffqh.cn.gov.cn.pffqh.cn http://www.morning.sskkf.cn.gov.cn.sskkf.cn http://www.morning.cmldr.cn.gov.cn.cmldr.cn http://www.morning.rqxmz.cn.gov.cn.rqxmz.cn http://www.morning.mzcsp.cn.gov.cn.mzcsp.cn http://www.morning.kwrzg.cn.gov.cn.kwrzg.cn http://www.morning.rymd.cn.gov.cn.rymd.cn http://www.morning.kpzbf.cn.gov.cn.kpzbf.cn http://www.morning.bfybb.cn.gov.cn.bfybb.cn http://www.morning.piekr.com.gov.cn.piekr.com http://www.morning.jsmyw.cn.gov.cn.jsmyw.cn