SGISTL源码阅读二十四 hash_set 关联式容器

SGISTL源码阅读二十四 hash_set 关联式容器

前言

前面我们已经分析了sethashtableset的底层容器是红黑树,而接下来我们要分析的hash_set,是底层为hashtable的集合。


深入源码

hash_set的定义部分
#ifndef __STL_LIMITED_DEFAULT_TEMPLATES
template <class Value, class HashFcn = hash<Value>,
          class EqualKey = equal_to<Value>,
          class Alloc = alloc>
#else
template <class Value, class HashFcn, class EqualKey, class Alloc = alloc>
#endif
class hash_set
{
private:
  //定义别名
  typedef hashtable<Value, Value, HashFcn, identity<Value>,
                    EqualKey, Alloc> ht;
  //定义一个hashtable类型的成员变量rep
  ht rep;

public:
  //声明相应型别
  //hashtable有一些无法处理的型别
  //除非用户为那些型别撰写 hash function
  typedef typename ht::key_type key_type;
  typedef typename ht::value_type value_type;
  typedef typename ht::hasher hasher;
  typedef typename ht::key_equal key_equal;

  typedef typename ht::size_type size_type;
  typedef typename ht::difference_type difference_type;
  typedef typename ht::const_pointer pointer;
  typedef typename ht::const_pointer const_pointer;
  typedef typename ht::const_reference reference;
  typedef typename ht::const_reference const_reference;
  //直接使用了底层hashtable的迭代器
  typedef typename ht::const_iterator iterator;
  typedef typename ht::const_iterator const_iterator;
hash_set的构造函数

它的构造函数版本非常地多,但是实现却非常简单,直接简单地调用了底层hashtable提供的方法

public:
  //默认构造,默认大小为100个buckets(hashtable内部会将100转换为一个合适的质数)
  hash_set() : rep(100, hasher(), key_equal()) {}
  //指定大小创建,防止隐式转换
  explicit hash_set(size_type n) : rep(n, hasher(), key_equal()) {}
  //指定大小n以及哈希函数,其余取默认值
  hash_set(size_type n, const hasher& hf) : rep(n, hf, key_equal()) {}
  //指定大小n及哈希函数和比较key的大小的函数
  hash_set(size_type n, const hasher& hf, const key_equal& eql)
    : rep(n, hf, eql) {}

#ifdef __STL_MEMBER_TEMPLATES
   //我们需要注意到下面所有的插入都是调用的insert_unique
   //保证了set中元素的唯一性
  template <class InputIterator>
  hash_set(InputIterator f, InputIterator l)
    : rep(100, hasher(), key_equal()) { rep.insert_unique(f, l); }
  template <class InputIterator>
  hash_set(InputIterator f, InputIterator l, size_type n)
    : rep(n, hasher(), key_equal()) { rep.insert_unique(f, l); }
  template <class InputIterator>
  hash_set(InputIterator f, InputIterator l, size_type n,
           const hasher& hf)
    : rep(n, hf, key_equal()) { rep.insert_unique(f, l); }
  template <class InputIterator>
  hash_set(InputIterator f, InputIterator l, size_type n,
           const hasher& hf, const key_equal& eql)
    : rep(n, hf, eql) { rep.insert_unique(f, l); }
#else
  //以下为const版本
  hash_set(const value_type* f, const value_type* l)
    : rep(100, hasher(), key_equal()) { rep.insert_unique(f, l); }
  hash_set(const value_type* f, const value_type* l, size_type n)
    : rep(n, hasher(), key_equal()) { rep.insert_unique(f, l); }
  hash_set(const value_type* f, const value_type* l, size_type n,
           const hasher& hf)
    : rep(n, hf, key_equal()) { rep.insert_unique(f, l); }
  hash_set(const value_type* f, const value_type* l, size_type n,
           const hasher& hf, const key_equal& eql)
    : rep(n, hf, eql) { rep.insert_unique(f, l); }
  hash_set(const_iterator f, const_iterator l)
    : rep(100, hasher(), key_equal()) { rep.insert_unique(f, l); }
  hash_set(const_iterator f, const_iterator l, size_type n)
    : rep(n, hasher(), key_equal()) { rep.insert_unique(f, l); }
  hash_set(const_iterator f, const_iterator l, size_type n,
           const hasher& hf)
    : rep(n, hf, key_equal()) { rep.insert_unique(f, l); }
  hash_set(const_iterator f, const_iterator l, size_type n,
           const hasher& hf, const key_equal& eql)
    : rep(n, hf, eql) { rep.insert_unique(f, l); }
#endif /*__STL_MEMBER_TEMPLATES */
hashset的相关操作

这些操作也是一样,直接调用了底层hashtable所实现的方法。

基本操作
public:
  //返回大小
  size_type size() const { return rep.size(); }
  size_type max_size() const { return rep.max_size(); }
  //判断是否为空
  bool empty() const { return rep.empty(); }
  //交换两个hashset
  void swap(hash_set& hs) { rep.swap(hs.rep); }
  friend bool operator== __STL_NULL_TMPL_ARGS (const hash_set&,
                                               const hash_set&);
  //返回头部的迭代器
  iterator begin() const { return rep.begin(); }
  //返回尾部的迭代器
  iterator end() const { return rep.end(); }
  //...
  //查找值为key的节点,返回一个迭代器
  iterator find(const key_type& key) const { return rep.find(key); }
  //计算值为key的节点个数
  size_type count(const key_type& key) const { return rep.count(key); }

  pair<iterator, iterator> equal_range(const key_type& key) const
    { return rep.equal_range(key); }
  //...
  public:
  //重建(如果hint小于当前hashset大小,则不会重建)
  void resize(size_type hint) { rep.resize(hint); }
  //返回桶的数量
  size_type bucket_count() const { return rep.bucket_count(); }
  size_type max_bucket_count() const { return rep.max_bucket_count(); }
  //返回节点数
  size_type elems_in_bucket(size_type n) const
    { return rep.elems_in_bucket(n); }
插入操作
public:
  pair<iterator, bool> insert(const value_type& obj)
    {
      //确保set中元素的唯一性,调用insert_unique()
      pair<typename ht::iterator, bool> p = rep.insert_unique(obj);
      //pair的第一个值为迭代器,如果插入失败,则返回指向hashset中值为obj的迭代器,插入成功则指向插入成功的位置
      //第二个值为布尔类型,插入成功则返回true,插入失败则返回false
      return pair<iterator, bool>(p.first, p.second);
    }
#ifdef __STL_MEMBER_TEMPLATES
  //迭代器指定范围插入
  template <class InputIterator>
  void insert(InputIterator f, InputIterator l) { rep.insert_unique(f,l); }
#else
  void insert(const value_type* f, const value_type* l) {
    rep.insert_unique(f,l);
  }
  //const版本
  void insert(const_iterator f, const_iterator l) {rep.insert_unique(f, l); }
#endif /*__STL_MEMBER_TEMPLATES */
  //noresize版本
  pair<iterator, bool> insert_noresize(const value_type& obj)
  {
    pair<typename ht::iterator, bool> p = rep.insert_unique_noresize(obj);
    return pair<iterator, bool>(p.first, p.second);
  }

删除操作
  //删除值为key的节点,并返回删除了的个数
  size_type erase(const key_type& key) {return rep.erase(key); }
  //删除指定位置的节点
  void erase(iterator it) { rep.erase(it); }
  //删除指定范围的节点
  void erase(iterator f, iterator l) { rep.erase(f, l); }
  //将hashset清空
  void clear() { rep.clear(); }
操作符重载
//重载==
//直接调用hashtable所实现的
template <class Value, class HashFcn, class EqualKey, class Alloc>
inline bool operator==(const hash_set<Value, HashFcn, EqualKey, Alloc>& hs1,
                       const hash_set<Value, HashFcn, EqualKey, Alloc>& hs2)
{
  return hs1.rep == hs2.rep;
}

关于hash_multiset

hash_multisethash_set的区别等同于multisetset的区别。
也是由于调用inset的函数不同而造成的。

深入源码

下面只贴出了部分代码

//调用了rep.insert_equal
#ifdef __STL_MEMBER_TEMPLATES
  template <class InputIterator>
  hash_multiset(InputIterator f, InputIterator l)
    : rep(100, hasher(), key_equal()) { rep.insert_equal(f, l); }
  template <class InputIterator>
  hash_multiset(InputIterator f, InputIterator l, size_type n)
    : rep(n, hasher(), key_equal()) { rep.insert_equal(f, l); }
  template <class InputIterator>
  hash_multiset(InputIterator f, InputIterator l, size_type n,
                const hasher& hf)
    : rep(n, hf, key_equal()) { rep.insert_equal(f, l); }
  template <class InputIterator>
  hash_multiset(InputIterator f, InputIterator l, size_type n,
                const hasher& hf, const key_equal& eql)
    : rep(n, hf, eql) { rep.insert_equal(f, l); }
#else
//...
public:
  iterator insert(const value_type& obj) { return rep.insert_equal(obj); }
#ifdef __STL_MEMBER_TEMPLATES
  template <class InputIterator>
  void insert(InputIterator f, InputIterator l) { rep.insert_equal(f,l); }
#else
  void insert(const value_type* f, const value_type* l) {
    rep.insert_equal(f,l);
  }
  void insert(const_iterator f, const_iterator l) { rep.insert_equal(f, l); }

总结

本次我们分析了hash_set以及hash_multiset,可以看到它们底层是由hashtable实现的,他们大量地调用了hashtable所实现的方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值