1.容器rb_tree
- 按正常规则++it遍历,便能得到排序状态
- 不能使用rb_tree的iterators改变元素值
- 两种插入操作:insert_unique()和insert_equal()
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:
size_type node_count;
link_type header; // 指向红黑树节点的指针
Compare key_compare; // key值比较方法
};
rb_tree<int, int, identity<int>, less<int>, alloc> itree;
2.容器set,multiset
- 元素按照key值自动排序
- set/multiset提供遍历操作,不能使用迭代器来改变元素的Key(Key就是data)
- set的所有操作,都在呼叫底层rb_tree的操作
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_value, value_type, identity<value_type>, key_compare, Alloc> rep_type;
rep_type t;
public:
typedef typename rep_type::**const_iterator** iterator; // 为了禁止user对元素赋值
3.容器map,multimap
- 元素按照key值自动排序
- 提供遍历操作,不能使用迭代器来改变元素的Key。但可以用它来改变元素的data
template <class Key, class T, class Compare = less<Key>, 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;
typedef Compare key_compare;
private:
typedef rb_tree<key_type, value_type, select1st<value_type>, key_compare, Alloc> rep_type;
rep_type t;
public:
typedef typename rep_type::iterator iterator;
template<class Arg, class Result>
struct unary_function{
typedef Arg argument_type;
typedef Result result_type;
}
template<class Pair>
struct select1st:public unary_function<Pair, typename Pair::first_type>
{
const typename Pair::first_type& operaor()(const Pair&x) const
{return x.first};
}
set
的元素既是key也是value,修改任何一个元素都会破坏集合的有序性和唯一性,因此不允许修改。map
的元素是键值对,键必须保持不变以保证有序性,但值的修改不会影响有序性,因此允许修改值。
4.容器hashtable
- rehashing:当我们需要安插的元素数目大于篮子的数目,就需要将原本的篮子数目扩充近一倍
template <class Value, class Key, class HashFun, class ExtractKey, class EqualKey, class Alloc=alloc>
class hashtable {
public:
typedef HashFun hasher; // 散射函数
typedef EqualKey key_equal; // 比较key值是否相等
typedef size_t size_type;
private:
// size = 1+1+1+12+4 = 19 -> 20
hasher hash; // 空函数对象:1
key_equal equals; // 空函数对象:1
ExtractKey get_key; // 空函数对象:1
typedef _hashtable_node<Value> node;
vector<node*, Alloc> buckets; // vector中有三个指针:12
size_type num_elements; // 4
public:
size_type bucket_count() const {return buckets.size();}
template <class Value>
struct __hashtable_node{
__hashtable_node* next; // 4
Value val; // 4
}
实际调用:
hashtable<const char*, const char*, hash<const char*>, identity<const char*>, eqstr, alloc>
ht(50, hash<const chat*>(), eqstr()); // 50代表的是哈希表的初始桶(bucket)数量
ht.insert_unique("kiwi");
// 比较两个C语言风格的字符串是否相等,可以用strcmp()
// 但它返回的是-1,0,1,不是bool类型,因此需要加一层外套
// const char*表示指向字符串的指针,通过指针可以访问整个字符串
struct eqstr{
bool operator()(const char* s1, const char* s2) const
{return strcmp(s1,s2) == 0;}
};
- C语言中的字符串是以
'\\0'
(空字符)结尾的字符数组。使用const char*
表示指向字符数组的指针,而不是单个字符。如果你使用的是const char
,那只表示一个字符,而不是一个字符串。 - 比较两个字符串需要用指针遍历每个字符,因此要使用
const char*
。
template<>
struct hash<const char*>
{
size_type operator()(const char* s) const
{
size_type hash = 0;
while(*s) // 遍历字符串中的每一个字符
{
hash = hash * 101 + *s++; // 计算当前字符的ASCII值
}
return hash;
}
};
5.unordered_set容器
unordered_set<string> c;
// 第i号篮子里有多少个元素
for(unsigned i=0; i<20; i++){
cout << "bucket #" << i << c.bucket_size(i) << " elements.\\n";
}