(十)红黑树、set、map

红黑树

  • 红黑树是高度平衡的二叉搜索树。它的排列规则有利于serach和insert,并保持深度平衡即没有任何一个节点太深。
  • 红黑树提供遍历操作及迭代器,遍历得到一个有序序列(中序遍历)
  • 不应该使用迭代器修改红黑树节点的值,对于map,可以修改value,对于set,不能更改,防止破坏红黑树的有序性。
  • 红黑树提供两种插入操作,一种是insert_unique()另一种是insert_equal()。前者表示节点的key在整棵树中是独一无二的,后者允许节点的key重复,且相同key一定是相邻的。
// Key是每个节点的一部分,Value是每个节点的全部容
//KeyOfValue是每个节点如何从Value中获取Key,Compare是节点之间比较排序的方式
template<class Key, class Value, class KeyOfValue, class Compare, class Alloc = alloc>
class rb_tree{
protected:
	typedef __rb_tree_node<Value> rb_tree_node;
	...
public:
	typedef rb_tree_node* link_type;
	...
protected:
	//红黑树有三个数据,大小为12个字节
	size_type node_count;//节点数量
	link_type header;//指向红黑树根节点的指针,是为了实现方便设计的节点,实际上该节点并不储存数据
	Compare ker_compare;//key的大小比较准则,是一个函数对象
	...
}
  • 红黑树直接使用示例(2.9版),新版本有一些函数和类的名称变了
//Key是int,Value也是int表示Value与Key是相同的,类似set
//identity表示相等,less<int>表示小于
rb_tree<int, int, identity<int>, less<int>, alloc> myTree;

//第三个模板参数,identity是GUN独有
template <class Arg, class Result>
struct unary_function{
	typedef Arg argument_type;
	typedef Result result_type;
};//为什么要继承它,与可适配的有关
template<class T>
struct identity:public unary_function<T, T>{
	const T& operator()(const T& x) const {return x;}
};

//第四个参数,less<int>是标准库都有的
template<class Arg1, class Arg2, class Result>
struct binary_function{
	typedef Arg1 first_argument_type;
	typedef Arg2 second_argument_type;
	typedef Result reault_type;
};
template<class T>
struct less: public binary_function<T, T, bool>{
	bool operator()(const T& x, const T& y) const
	{ return x < y; }
};
---------------------测试程序---------------------------
rb_tree<int, int, identity<int>, less<int>> itree;
cout<< itree.empty() << endl; //1
cout<< itree.size() << endl; //0

itree.insert_unique(3);
itree.insert_unique(8);
itree.insert_unique(5);
itree.insert_unique(9);
itree.insert_unique(13);
itree.insert_unique(5); //no effect, since using insert_unique()
cout<< itree.empty() <<endl; //0
cout<< itree.size() <<endl; //5
cout<<itree.count(5) << endl; //1

itree.insert_equal(5);
itree.insert_equal(5);
cout<< itree.size() <<endl;//7,since using insert_equal
cout<< itreecount(5) <<endl;//3
  • G4.9版
  • 符合Handle and Body法则,将定义和实现分离
  • 在4.9中红黑树是24个字节,三个指针和一个枚举类型
    在这里插入图片描述

set与multiset

  • set/multiset是以红黑树为底层结构,因此,元素有自动排序的特性。排序的依据是key,且value就是key
  • set/multiset提供遍历操作及iterators。按正常规则(++iterators),便能得到排序状态。
  • 无法使用set/multiset的iterator改变元素值(因为ke有其特殊的排列规则)set/multiset的iterator的底部红黑树是const_iterator,就是为了禁止用户对元素赋值
  • set的key必需独一无二,它的insert()用的是红黑树的insert_unique()
  • multiset的key可以重复,它的insert()用的是红黑树的insert_equal()
//三个模板参数
//第一个是key的类型,第二个是如何比大小,第三个是分配器
template<class Key, class Compare = less<Key>, class Alloc = alloc>
class set{
public:
	typedef Key key_type;
	typedef Key value_type;
	typedef Compare key_compare;
	typedef Compare value_compare;
private:
	typedef rb_tree<key_type, value_type, identity<value_type>, key_compare, Alloc> rep_type;//红黑树的五个模板参数
	rep_type t;//唯一的变量是红黑树
public:
	typedef typename rep_type::const_iterator iterator;//set不允许通过迭代器该内容,因为拿到的是const_iterator
...
//set的所有操作,都通过底层的红黑树t的操作,从这个角度来看,set实际上是一种容器适配器
};

map和multimap

  • map和multimap是以红黑树为底层结构,因此元素有自动排序特性,排序的依据是key
  • map/multimap提供遍历操作及iterators,按++ite的方式遍历,可得到顺序序列
  • 无法使用iterator改变元素的key,但是可以用它来改变元素的data。因此map/multimap内部自动将用户指定的key_type设置为const,实现禁止用户对元素key赋值。
template<class Key, class T, class Compare = less<Key>m class Alloc = alloc>
class map{
public: 
	typedef Key key_type;
	typedef T data_type;
	typedef T mapped_type;
	typedef pair<const Key, T> value_type;//key是不能被修改的
	typedef Compare key_compare;
private:
	typedef rb_tree<key_type, value_type, select1st<value_type>, key_compare, Alloc> rep_type;//红黑树
	//select1st从value中取出第一个就是key
	rep_type t;
public:
	typedef typename rep_type::iterator iterator;//map的迭代器就是红黑树的迭代器
...
};

//select1st的实现
template<class Arg, class Result>
struct unary_function{
	typedef Arg atgument_type;
	typedef Result result_type;
};

template <class Pair>
struct select1st:public unary_function<Pair, typename Pair::first_type>{
	const typename Pair::first_type& operator()(const Pair& x) const
	{ return x.first; }
};
  • map的[ ] 操作符
    • 返回key对应的value,如果key不存在,将这一对数据插入到map中
    • [ ]操作符先调用lower_bound,查找key,如果找到就返回对应的value,没找到就返回最适合的插入的位置,后调用insert
    • 如果像map中插入元素,insert的效率高于[ ]操作符
    • [ ]操作符只有map和unordered_map有,对于multimap,可能有多个value与相同的key关联
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值