zoukankan      html  css  js  c++  java
  • stl_hashtable.h

    stl_hashtable.h
    // Filename:    stl_hashtable.h
    
    // Comment By:  凝霜
    // E-mail:      mdl2009@vip.qq.com
    // Blog:        http://blog.csdn.net/mdl13412
    
    ////////////////////////////////////////////////////////////////////////////////
    // 本实作的hashtable采用的是开链法, 其内存布局如下
    ////////////////////////////////////////////////////////////////////////////////
    // 对于产生哈希冲突的结点, 我们采取在其位置维护一个链表才处理之
    //
    //  ------------------------------------------------------------------------
    //  |      |      |      |      |      | ..... |      |      |      |      |
    //  ------------------------------------------------------------------------
    //      |             |                                   |
    //      ↓             ↓                                   ↓
    //  --------       --------  --------  --------        --------
    //  | next |->0    | next |->| next |->| next |->0     | next |->0
    //  --------       --------  --------  --------        --------
    //  | data |       | data |  | data |  | data |        | data |
    //  --------       --------  --------  --------        --------
    ////////////////////////////////////////////////////////////////////////////////
    
    /*
     * Copyright (c) 1996,1997
     * Silicon Graphics Computer Systems, Inc.
     *
     * Permission to use, copy, modify, distribute and sell this software
     * and its documentation for any purpose is hereby granted without fee,
     * provided that the above copyright notice appear in all copies and
     * that both that copyright notice and this permission notice appear
     * in supporting documentation.  Silicon Graphics makes no
     * representations about the suitability of this software for any
     * purpose.  It is provided "as is" without express or implied warranty.
     *
     *
     * Copyright (c) 1994
     * Hewlett-Packard Company
     *
     * Permission to use, copy, modify, distribute and sell this software
     * and its documentation for any purpose is hereby granted without fee,
     * provided that the above copyright notice appear in all copies and
     * that both that copyright notice and this permission notice appear
     * in supporting documentation.  Hewlett-Packard Company makes no
     * representations about the suitability of this software for any
     * purpose.  It is provided "as is" without express or implied warranty.
     *
     */
    
    /* NOTE: This is an internal header file, included by other STL headers.
     *   You should not attempt to use it directly.
     */
    
    #ifndef __SGI_STL_INTERNAL_HASHTABLE_H
    #define __SGI_STL_INTERNAL_HASHTABLE_H
    
    // hashtable类用于实现哈希关联容器hash_st, hash_map, hash_multiset和hash_multimap
    
    #include <stl_algobase.h>
    #include <stl_alloc.h>
    #include <stl_construct.h>
    #include <stl_tempbuf.h>
    #include <stl_algo.h>
    #include <stl_uninitialized.h>
    #include <stl_function.h>
    #include <stl_vector.h>
    #include <stl_hash_fun.h>
    
    __STL_BEGIN_NAMESPACE
    
    // 这个是哈希表中维护的链表结点
    template <class Value>
    struct __hashtable_node
    {
      __hashtable_node* next;
      Value val;
    };
    
    // 这里使用前置声明, 否则后面的交叉引用会导致编译错误
    template <class Value, class Key, class HashFcn,
              class ExtractKey, class EqualKey, class Alloc = alloc>
    class hashtable;
    
    template <class Value, class Key, class HashFcn,
              class ExtractKey, class EqualKey, class Alloc>
    struct __hashtable_iterator;
    
    template <class Value, class Key, class HashFcn,
              class ExtractKey, class EqualKey, class Alloc>
    struct __hashtable_const_iterator;
    
    template <class Value, class Key, class HashFcn,
              class ExtractKey, class EqualKey, class Alloc>
    struct __hashtable_iterator
    {
      // 注意: hashtable不提供reverse iterator, 也不提供operator --
      typedef hashtable<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>
              hashtable;
      typedef __hashtable_iterator<Value, Key, HashFcn,
                                   ExtractKey, EqualKey, Alloc>
              iterator;
      typedef __hashtable_const_iterator<Value, Key, HashFcn,
                                         ExtractKey, EqualKey, Alloc>
              const_iterator;
      typedef __hashtable_node<Value> node;
    
      typedef forward_iterator_tag iterator_category;
      typedef Value value_type;
      typedef ptrdiff_t difference_type;
      typedef size_t size_type;
      typedef Value& reference;
      typedef Value* pointer;
    
      // 本实作中hasntable是由一个线性表作为hash表, 而表内的每一个被映射的
      // 哈希结点内部维护这一个链表, 用于处理哈希冲突, 此即开链法
      node* cur;            // 当前的位置, 是线性表中的链表结点
      hashtable* ht;        // 线性表中的位置
    
      __hashtable_iterator(node* n, hashtable* tab) : cur(n), ht(tab) {}
      __hashtable_iterator() {}
    
      reference operator*() const { return cur->val; }
    
    #ifndef __SGI_STL_NO_ARROW_OPERATOR
      // 如果编译器支持'->'则重载, 详细见我在<stl_list.h>中的剖析
      pointer operator->() const { return &(operator*()); }
    #endif /* __SGI_STL_NO_ARROW_OPERATOR */
    
      // 详细解析见实现部分
      iterator& operator++();
      iterator operator++(int);
    
      bool operator==(const iterator& it) const { return cur == it.cur; }
      bool operator!=(const iterator& it) const { return cur != it.cur; }
    };
    
    // const情况基本和上面一致
    template <class Value, class Key, class HashFcn,
              class ExtractKey, class EqualKey, class Alloc>
    struct __hashtable_const_iterator
    {
      typedef hashtable<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>
              hashtable;
      typedef __hashtable_iterator<Value, Key, HashFcn,
                                   ExtractKey, EqualKey, Alloc>
              iterator;
      typedef __hashtable_const_iterator<Value, Key, HashFcn,
                                         ExtractKey, EqualKey, Alloc>
              const_iterator;
      typedef __hashtable_node<Value> node;
    
      typedef forward_iterator_tag iterator_category;
      typedef Value value_type;
      typedef ptrdiff_t difference_type;
      typedef size_t size_type;
      typedef const Value& reference;
      typedef const Value* pointer;
    
      const node* cur;
      const hashtable* ht;
    
      __hashtable_const_iterator(const node* n, const hashtable* tab)
        : cur(n), ht(tab) {}
      __hashtable_const_iterator() {}
      __hashtable_const_iterator(const iterator& it) : cur(it.cur), ht(it.ht) {}
      reference operator*() const { return cur->val; }
    #ifndef __SGI_STL_NO_ARROW_OPERATOR
      pointer operator->() const { return &(operator*()); }
    #endif /* __SGI_STL_NO_ARROW_OPERATOR */
      const_iterator& operator++();
      const_iterator operator++(int);
      bool operator==(const const_iterator& it) const { return cur == it.cur; }
      bool operator!=(const const_iterator& it) const { return cur != it.cur; }
    };
    
    // 假设long至少为32-bits, 否则根据情况自己修改
    static const int __stl_num_primes = 28;
    static const unsigned long __stl_prime_list[__stl_num_primes] =
    {
      53,         97,           193,         389,       769,
      1543,       3079,         6151,        12289,     24593,
      49157,      98317,        196613,      393241,    786433,
      1572869,    3145739,      6291469,     12582917,  25165843,
      50331653,   100663319,    201326611,   402653189, 805306457,
      1610612741, 3221225473ul, 4294967291ul
    };
    
    // 返回大于n的最小素数
    inline unsigned long __stl_next_prime(unsigned long n)
    {
      const unsigned long* first = __stl_prime_list;
      const unsigned long* last = __stl_prime_list + __stl_num_primes;
      const unsigned long* pos = lower_bound(first, last, n);
      return pos == last ? *(last - 1) : *pos;
    }
    
    // Value:       结点的valule类型
    // Key:         结点的key类型
    // HashFcn:     hash function
    // ExtractKey:  从结点中取出键值的方法
    // EqualKey:    判断键值是否相同的方法
    // Alloc:       allocator, 默认alloc
    template <class Value, class Key, class HashFcn,
              class ExtractKey, class EqualKey,
              class Alloc>
    class hashtable
    {
    public:
      typedef Key key_type;
      typedef Value value_type;
      typedef HashFcn hasher;
      typedef EqualKey key_equal;
    
      typedef size_t            size_type;
      typedef ptrdiff_t         difference_type;
      typedef value_type*       pointer;
      typedef const value_type* const_pointer;
      typedef value_type&       reference;
      typedef const value_type& const_reference;
    
      // 获取hash相关的函数
      hasher hash_funct() const { return hash; }
      key_equal key_eq() const { return equals; }
    
    private:
      // 详细剖析参考<stl_fun_fun.h>
      hasher hash;
      key_equal equals;
      ExtractKey get_key;
    
      typedef __hashtable_node<Value> node;
      typedef simple_alloc<node, Alloc> node_allocator;
    
      vector<node*,Alloc> buckets;  // 线性表以vector实作
      size_type num_elements;
    
    public:
      typedef __hashtable_iterator<Value, Key, HashFcn, ExtractKey, EqualKey,
                                   Alloc>
      iterator;
    
      typedef __hashtable_const_iterator<Value, Key, HashFcn, ExtractKey, EqualKey,
                                         Alloc>
      const_iterator;
    
      friend struct
      __hashtable_iterator<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>;
      friend struct
      __hashtable_const_iterator<Value, Key, HashFcn, ExtractKey, EqualKey, Alloc>;
    
    public:
      // 下面这些函数STL容器的表现基本一致,
      // 不做说明, 可以参看<stl_vector.h>, <stl_list.h>中的解析
      hashtable(size_type n,
                const HashFcn&    hf,
                const EqualKey&   eql,
                const ExtractKey& ext)
        : hash(hf), equals(eql), get_key(ext), num_elements(0)
      {
        initialize_buckets(n);
      }
    
      hashtable(size_type n,
                const HashFcn&    hf,
                const EqualKey&   eql)
        : hash(hf), equals(eql), get_key(ExtractKey()), num_elements(0)
      {
        initialize_buckets(n);
      }
    
      hashtable(const hashtable& ht)
        : hash(ht.hash), equals(ht.equals), get_key(ht.get_key), num_elements(0)
      {
        copy_from(ht);
      }
    
      hashtable& operator= (const hashtable& ht)
      {
        if (&ht != this) {
          clear();
          hash = ht.hash;
          equals = ht.equals;
          get_key = ht.get_key;
          copy_from(ht);
        }
        return *this;
      }
    
      ~hashtable() { clear(); }
    
      size_type size() const { return num_elements; }
      size_type max_size() const { return size_type(-1); }
      bool empty() const { return size() == 0; }
    
      void swap(hashtable& ht)
      {
        __STD::swap(hash, ht.hash);
        __STD::swap(equals, ht.equals);
        __STD::swap(get_key, ht.get_key);
        buckets.swap(ht.buckets);
        __STD::swap(num_elements, ht.num_elements);
      }
    
      iterator begin()
      {
        for (size_type n = 0; n < buckets.size(); ++n)
          if (buckets[n])
            return iterator(buckets[n], this);
        return end();
      }
    
      iterator end() { return iterator(0, this); }
    
      const_iterator begin() const
      {
        for (size_type n = 0; n < buckets.size(); ++n)
          if (buckets[n])
            return const_iterator(buckets[n], this);
        return end();
      }
    
      const_iterator end() const { return const_iterator(0, this); }
    
      friend bool
      operator== __STL_NULL_TMPL_ARGS (const hashtable&, const hashtable&);
    
    public:
      // 线性表中的结点数
      size_type bucket_count() const { return buckets.size(); }
    
      // 线性表最多能分配的结点数
      size_type max_bucket_count() const
        { return __stl_prime_list[__stl_num_primes - 1]; }
    
      // 返回指定key映射了多少value
      size_type elems_in_bucket(size_type bucket) const
      {
        size_type result = 0;
        for (node* cur = buckets[bucket]; cur; cur = cur->next)
          result += 1;
        return result;
      }
    
      // 插入操作, 不允许重复
      pair<iterator, bool> insert_unique(const value_type& obj)
      {
        // 首先判断容量是否够用, 否则就重新配置
        resize(num_elements + 1);
        return insert_unique_noresize(obj);
      }
    
      // 插入操作, 允许重复
      iterator insert_equal(const value_type& obj)
      {
        resize(num_elements + 1);
        return insert_equal_noresize(obj);
      }
    
      pair<iterator, bool> insert_unique_noresize(const value_type& obj);
      iterator insert_equal_noresize(const value_type& obj);
    
    #ifdef __STL_MEMBER_TEMPLATES
      template <class InputIterator>
      void insert_unique(InputIterator f, InputIterator l)
      {
        insert_unique(f, l, iterator_category(f));
      }
    
      template <class InputIterator>
      void insert_equal(InputIterator f, InputIterator l)
      {
        insert_equal(f, l, iterator_category(f));
      }
    
      template <class InputIterator>
      void insert_unique(InputIterator f, InputIterator l,
                         input_iterator_tag)
      {
        for ( ; f != l; ++f)
          insert_unique(*f);
      }
    
      template <class InputIterator>
      void insert_equal(InputIterator f, InputIterator l,
                        input_iterator_tag)
      {
        for ( ; f != l; ++f)
          insert_equal(*f);
      }
    
      template <class ForwardIterator>
      void insert_unique(ForwardIterator f, ForwardIterator l,
                         forward_iterator_tag)
      {
        size_type n = 0;
        distance(f, l, n);
        resize(num_elements + n);
        for ( ; n > 0; --n, ++f)
          insert_unique_noresize(*f);
      }
    
      template <class ForwardIterator>
      void insert_equal(ForwardIterator f, ForwardIterator l,
                        forward_iterator_tag)
      {
        size_type n = 0;
        distance(f, l, n);
        resize(num_elements + n);
        for ( ; n > 0; --n, ++f)
          insert_equal_noresize(*f);
      }
    
    #else /* __STL_MEMBER_TEMPLATES */
      void insert_unique(const value_type* f, const value_type* l)
      {
        size_type n = l - f;
        resize(num_elements + n);
        for ( ; n > 0; --n, ++f)
          insert_unique_noresize(*f);
      }
    
      void insert_equal(const value_type* f, const value_type* l)
      {
        size_type n = l - f;
        resize(num_elements + n);
        for ( ; n > 0; --n, ++f)
          insert_equal_noresize(*f);
      }
    
      void insert_unique(const_iterator f, const_iterator l)
      {
        size_type n = 0;
        distance(f, l, n);
        resize(num_elements + n);
        for ( ; n > 0; --n, ++f)
          insert_unique_noresize(*f);
      }
    
      void insert_equal(const_iterator f, const_iterator l)
      {
        size_type n = 0;
        distance(f, l, n);
        resize(num_elements + n);
        for ( ; n > 0; --n, ++f)
          insert_equal_noresize(*f);
      }
    #endif /*__STL_MEMBER_TEMPLATES */
    
      reference find_or_insert(const value_type& obj);
    
      // 查找指定key
      iterator find(const key_type& key)
      {
        size_type n = bkt_num_key(key);
        node* first;
        for ( first = buckets[n];
              first && !equals(get_key(first->val), key);
              first = first->next)
          {}
        return iterator(first, this);
      }
    
      const_iterator find(const key_type& key) const
      {
        size_type n = bkt_num_key(key);
        const node* first;
        for ( first = buckets[n];
              first && !equals(get_key(first->val), key);
              first = first->next)
          {}
        return const_iterator(first, this);
      }
    
      // 返回key元素的个数
      size_type count(const key_type& key) const
      {
        const size_type n = bkt_num_key(key);
        size_type result = 0;
    
        for (const node* cur = buckets[n]; cur; cur = cur->next)
          if (equals(get_key(cur->val), key))
            ++result;
        return result;
      }
    
      pair<iterator, iterator> equal_range(const key_type& key);
      pair<const_iterator, const_iterator> equal_range(const key_type& key) const;
    
      // 擦除元素
      size_type erase(const key_type& key);
      void erase(const iterator& it);
      void erase(iterator first, iterator last);
    
      void erase(const const_iterator& it);
      void erase(const_iterator first, const_iterator last);
    
      void resize(size_type num_elements_hint);
      void clear();
    
    private:
      size_type next_size(size_type n) const { return __stl_next_prime(n); }
    
      // 预留空间, 并进行初始化
      void initialize_buckets(size_type n)
      {
        const size_type n_buckets = next_size(n);
        buckets.reserve(n_buckets);
        buckets.insert(buckets.end(), n_buckets, (node*) 0);
        num_elements = 0;
      }
    
      size_type bkt_num_key(const key_type& key) const
      {
        return bkt_num_key(key, buckets.size());
      }
    
      // 获取obj映射位置, 要经过一个mod过程
      size_type bkt_num(const value_type& obj) const
      {
        return bkt_num_key(get_key(obj));
      }
    
      size_type bkt_num_key(const key_type& key, size_t n) const
      {
        return hash(key) % n;
      }
    
      size_type bkt_num(const value_type& obj, size_t n) const
      {
        return bkt_num_key(get_key(obj), n);
      }
    
      // 分配空间并进行构造
      node* new_node(const value_type& obj)
      {
        node* n = node_allocator::allocate();
        n->next = 0;
        __STL_TRY {
          construct(&n->val, obj);
          return n;
        }
        __STL_UNWIND(node_allocator::deallocate(n));
      }
    
      // 析构并释放空间
      void delete_node(node* n)
      {
        destroy(&n->val);
        node_allocator::deallocate(n);
      }
    
      // 解析见实现部分
      void erase_bucket(const size_type n, node* first, node* last);
      void erase_bucket(const size_type n, node* last);
    
      void copy_from(const hashtable& ht);
    };
    
    
    template <class V, class K, class HF, class ExK, class EqK, class A>
    __hashtable_iterator<V, K, HF, ExK, EqK, A>&
    __hashtable_iterator<V, K, HF, ExK, EqK, A>::operator++()
    {
      const node* old = cur;
      cur = cur->next;              // 当前链表结点的下一个结点, 如果不为0
                                    // 那么它就是我们要的
    
      // 链表结点恰好是最后一个结点, 我们要在线性表的下一个表格的链表中查找
      if (!cur)
      {
        size_type bucket = ht->bkt_num(old->val);
        while (!cur && ++bucket < ht->buckets.size())
          cur = ht->buckets[bucket];
      }
    
      return *this;
    }
    
    template <class V, class K, class HF, class ExK, class EqK, class A>
    inline __hashtable_iterator<V, K, HF, ExK, EqK, A>
    __hashtable_iterator<V, K, HF, ExK, EqK, A>::operator++(int)
    {
      iterator tmp = *this;
      ++*this;      // 触发operator ++()
      return tmp;
    }
    
    // const情况同上
    template <class V, class K, class HF, class ExK, class EqK, class A>
    __hashtable_const_iterator<V, K, HF, ExK, EqK, A>&
    __hashtable_const_iterator<V, K, HF, ExK, EqK, A>::operator++()
    {
      const node* old = cur;
      cur = cur->next;
      if (!cur) {
        size_type bucket = ht->bkt_num(old->val);
        while (!cur && ++bucket < ht->buckets.size())
          cur = ht->buckets[bucket];
      }
      return *this;
    }
    
    template <class V, class K, class HF, class ExK, class EqK, class A>
    inline __hashtable_const_iterator<V, K, HF, ExK, EqK, A>
    __hashtable_const_iterator<V, K, HF, ExK, EqK, A>::operator++(int)
    {
      const_iterator tmp = *this;
      ++*this;
      return tmp;
    }
    
    // 对于不支持偏特化的编译器提供traits支持
    #ifndef __STL_CLASS_PARTIAL_SPECIALIZATION
    
    template <class V, class K, class HF, class ExK, class EqK, class All>
    inline forward_iterator_tag
    iterator_category(const __hashtable_iterator<V, K, HF, ExK, EqK, All>&)
    {
      return forward_iterator_tag();
    }
    
    template <class V, class K, class HF, class ExK, class EqK, class All>
    inline V* value_type(const __hashtable_iterator<V, K, HF, ExK, EqK, All>&)
    {
      return (V*) 0;
    }
    
    template <class V, class K, class HF, class ExK, class EqK, class All>
    inline hashtable<V, K, HF, ExK, EqK, All>::difference_type*
    distance_type(const __hashtable_iterator<V, K, HF, ExK, EqK, All>&)
    {
      return (hashtable<V, K, HF, ExK, EqK, All>::difference_type*) 0;
    }
    
    template <class V, class K, class HF, class ExK, class EqK, class All>
    inline forward_iterator_tag
    iterator_category(const __hashtable_const_iterator<V, K, HF, ExK, EqK, All>&)
    {
      return forward_iterator_tag();
    }
    
    template <class V, class K, class HF, class ExK, class EqK, class All>
    inline V*
    value_type(const __hashtable_const_iterator<V, K, HF, ExK, EqK, All>&)
    {
      return (V*) 0;
    }
    
    template <class V, class K, class HF, class ExK, class EqK, class All>
    inline hashtable<V, K, HF, ExK, EqK, All>::difference_type*
    distance_type(const __hashtable_const_iterator<V, K, HF, ExK, EqK, All>&)
    {
      return (hashtable<V, K, HF, ExK, EqK, All>::difference_type*) 0;
    }
    
    #endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */
    
    template <class V, class K, class HF, class Ex, class Eq, class A>
    bool operator==(const hashtable<V, K, HF, Ex, Eq, A>& ht1,
                    const hashtable<V, K, HF, Ex, Eq, A>& ht2)
    {
      typedef typename hashtable<V, K, HF, Ex, Eq, A>::node node;
      if (ht1.buckets.size() != ht2.buckets.size())
        return false;
      for (int n = 0; n < ht1.buckets.size(); ++n) {
        node* cur1 = ht1.buckets[n];
        node* cur2 = ht2.buckets[n];
        for ( ; cur1 && cur2 && cur1->val == cur2->val;
              cur1 = cur1->next, cur2 = cur2->next)
          {}
        if (cur1 || cur2)
          return false;
      }
      return true;
    }
    
    // 如果编译器支持模板函数特化优先级
    // 那么将全局的swap实现为使用hashtable私有的swap以提高效率
    #ifdef __STL_FUNCTION_TMPL_PARTIAL_ORDER
    
    template <class Val, class Key, class HF, class Extract, class EqKey, class A>
    inline void swap(hashtable<Val, Key, HF, Extract, EqKey, A>& ht1,
                     hashtable<Val, Key, HF, Extract, EqKey, A>& ht2) {
      ht1.swap(ht2);
    }
    
    #endif /* __STL_FUNCTION_TMPL_PARTIAL_ORDER */
    
    
    // 在不需要重新调整容量的情况下插入元素, key不可以重复
    template <class V, class K, class HF, class Ex, class Eq, class A>
    pair<typename hashtable<V, K, HF, Ex, Eq, A>::iterator, bool>
    hashtable<V, K, HF, Ex, Eq, A>::insert_unique_noresize(const value_type& obj)
    {
      // 获取待插入元素在hashtable中的索引
      const size_type n = bkt_num(obj);
    
      node* first = buckets[n];
    
      for (node* cur = first; cur; cur = cur->next)
        // 如果keu重复, 在不进行插入, 并告知用户插入失败
        if (equals(get_key(cur->val), get_key(obj)))
          return pair<iterator, bool>(iterator(cur, this), false);
    
      // 插入结点
      node* tmp = new_node(obj);
      tmp->next = first;
      buckets[n] = tmp;
      ++num_elements;
      return pair<iterator, bool>(iterator(tmp, this), true);
    }
    
    // 在不需要重新调整容量的情况下插入元素, key可以重复
    template <class V, class K, class HF, class Ex, class Eq, class A>
    typename hashtable<V, K, HF, Ex, Eq, A>::iterator
    hashtable<V, K, HF, Ex, Eq, A>::insert_equal_noresize(const value_type& obj)
    {
      const size_type n = bkt_num(obj);
      node* first = buckets[n];
    
      for (node* cur = first; cur; cur = cur->next)
        if (equals(get_key(cur->val), get_key(obj))) {
          node* tmp = new_node(obj);
          tmp->next = cur->next;
          cur->next = tmp;
          ++num_elements;
          return iterator(tmp, this);
        }
    
      node* tmp = new_node(obj);
      tmp->next = first;
      buckets[n] = tmp;
      ++num_elements;
      return iterator(tmp, this);
    }
    
    // 这个用于支持hash_map操作
    template <class V, class K, class HF, class Ex, class Eq, class A>
    typename hashtable<V, K, HF, Ex, Eq, A>::reference
    hashtable<V, K, HF, Ex, Eq, A>::find_or_insert(const value_type& obj)
    {
      resize(num_elements + 1);
    
      size_type n = bkt_num(obj);
      node* first = buckets[n];
    
      for (node* cur = first; cur; cur = cur->next)
        if (equals(get_key(cur->val), get_key(obj)))
          return cur->val;
    
      node* tmp = new_node(obj);
      tmp->next = first;
      buckets[n] = tmp;
      ++num_elements;
      return tmp->val;
    }
    
    // 查找满足key的区间
    template <class V, class K, class HF, class Ex, class Eq, class A>
    pair<typename hashtable<V, K, HF, Ex, Eq, A>::iterator,
         typename hashtabfind_or_insertle<V, K, HF, Ex, Eq, A>::iterator>
    hashtable<V, K, HF, Ex, Eq, A>::equal_range(const key_type& key)
    {
      typedef pair<iterator, iterator> pii;
      const size_type n = bkt_num_key(key);
    
      for (node* first = buckets[n]; first; first = first->next) {
        if (equals(get_key(first->val), key)) {
          for (node* cur = first->next; cur; cur = cur->next)
            if (!equals(get_key(cur->val), key))
              return pii(iterator(first, this), iterator(cur, this));
          for (size_type m = n + 1; m < buckets.size(); ++m)
            if (buckets[m])
              return pii(iterator(first, this),
                         iterator(buckets[m], this));
          return pii(iterator(first, this), end());
        }
      }
      return pii(end(), end());
    }
    
    template <class V, class K, class HF, class Ex, class Eq, class A>
    pair<typename hashtable<V, K, HF, Ex, Eq, A>::const_iterator,
         typename hashtable<V, K, HF, Ex, Eq, A>::const_iterator>
    hashtable<V, K, HF, Ex, Eq, A>::equal_range(const key_type& key) const
    {
      typedef pair<const_iterator, const_iterator> pii;
      const size_type n = bkt_num_key(key);
    
      for (const node* first = buckets[n] ; first; first = first->next) {
        if (equals(get_key(first->val), key)) {
          for (const node* cur = first->next; cur; cur = cur->next)
            if (!equals(get_key(cur->val), key))
              return pii(const_iterator(first, this),
                         const_iterator(cur, this));
          for (size_type m = n + 1; m < buckets.size(); ++m)
            if (buckets[m])
              return pii(const_iterator(first, this),
                         const_iterator(buckets[m], this));
          return pii(const_iterator(first, this), end());
        }
      }
      return pii(end(), end());
    }
    
    // 擦除指定元素
    template <class V, class K, class HF, class Ex, class Eq, class A>
    typename hashtable<V, K, HF, Ex, Eq, A>::size_type
    hashtable<V, K, HF, Ex, Eq, A>::erase(const key_type& key)
    {
      // 计算映射位置
      const size_type n = bkt_num_key(key);
      node* first = buckets[n];
      size_type erased = 0;
    
      // 开始查找并删除
      if (first) {
        node* cur = first;
        node* next = cur->next;
        while (next) {
          if (equals(get_key(next->val), key)) {
            cur->next = next->next;
            delete_node(next);
            next = cur->next;
            ++erased;
            --num_elements;
          }
          else {
            cur = next;
            next = cur->next;
          }
        }
        if (equals(get_key(first->val), key)) {
          buckets[n] = first->next;
          delete_node(first);
          ++erased;
          --num_elements;
        }
      }
      return erased;
    }
    
    template <class V, class K, class HF, class Ex, class Eq, class A>
    void hashtable<V, K, HF, Ex, Eq, A>::erase(const iterator& it)
    {
      if (node* const p = it.cur) {
        const size_type n = bkt_num(p->val);
        node* cur = buckets[n];
    
        if (cur == p) {
          buckets[n] = cur->next;
          delete_node(cur);
          --num_elements;
        }
        else {
          node* next = cur->next;
          while (next) {
            if (next == p) {
              cur->next = next->next;
              delete_node(next);
              --num_elements;
              break;
            }
            else {
              cur = next;
              next = cur->next;
            }
          }
        }
      }
    }
    
    // 擦除指定区间的元素
    template <class V, class K, class HF, class Ex, class Eq, class A>
    void hashtable<V, K, HF, Ex, Eq, A>::erase(iterator first, iterator last)
    {
      size_type f_bucket = first.cur ? bkt_num(first.cur->val) : buckets.size();
      size_type l_bucket = last.cur ? bkt_num(last.cur->val) : buckets.size();
    
      if (first.cur == last.cur)
        return;
      else if (f_bucket == l_bucket)
        erase_bucket(f_bucket, first.cur, last.cur);
      else {
        erase_bucket(f_bucket, first.cur, 0);
        for (size_type n = f_bucket + 1; n < l_bucket; ++n)
          erase_bucket(n, 0);
        if (l_bucket != buckets.size())
          erase_bucket(l_bucket, last.cur);
      }
    }
    
    template <class V, class K, class HF, class Ex, class Eq, class A>
    inline void
    hashtable<V, K, HF, Ex, Eq, A>::erase(const_iterator first,
                                          const_iterator last)
    {
      erase(iterator(const_cast<node*>(first.cur),
                     const_cast<hashtable*>(first.ht)),
            iterator(const_cast<node*>(last.cur),
                     const_cast<hashtable*>(last.ht)));
    }
    
    template <class V, class K, class HF, class Ex, class Eq, class A>
    inline void
    hashtable<V, K, HF, Ex, Eq, A>::erase(const const_iterator& it)
    {
      erase(iterator(const_cast<node*>(it.cur),
                     const_cast<hashtable*>(it.ht)));
    }
    
    // 调整hashtable的容量
    template <class V, class K, class HF, class Ex, class Eq, class A>
    void hashtable<V, K, HF, Ex, Eq, A>::resize(size_type num_elements_hint)
    {
      const size_type old_n = buckets.size();
    
      // 如果新调整的大小小于当前大小, 不进行更改
      if (num_elements_hint > old_n) {
        const size_type n = next_size(num_elements_hint);
    
        // 如果已经到达hashtable的容量的极限, 那么也不进行更改
        if (n > old_n) {
          // 建立新的线性表来扩充容量
          vector<node*, A> tmp(n, (node*) 0);
          __STL_TRY {
            // 先面开始copy
            for (size_type bucket = 0; bucket < old_n; ++bucket) {
              node* first = buckets[bucket];
              while (first) {
                size_type new_bucket = bkt_num(first->val, n);
                buckets[bucket] = first->next;
                first->next = tmp[new_bucket];
                tmp[new_bucket] = first;
                first = buckets[bucket];
              }
            }
            buckets.swap(tmp);
          }
    #         ifdef __STL_USE_EXCEPTIONS
          catch(...) {
            for (size_type bucket = 0; bucket < tmp.size(); ++bucket) {
              while (tmp[bucket]) {
                node* next = tmp[bucket]->next;
                delete_node(tmp[bucket]);
                tmp[bucket] = next;
              }
            }
            throw;
          }
    #         endif /* __STL_USE_EXCEPTIONS */
        }
      }
    }
    
    // 擦除指定映射位置的所有元素
    template <class V, class K, class HF, class Ex, class Eq, class A>
    void hashtable<V, K, HF, Ex, Eq, A>::erase_bucket(const size_type n,
                                                      node* first, node* last)
    {
      node* cur = buckets[n];
      if (cur == first)
        erase_bucket(n, last);
      else {
        node* next;
        for (next = cur->next; next != first; cur = next, next = cur->next)
          ;
        while (next) {
          cur->next = next->next;
          delete_node(next);
          next = cur->next;
          --num_elements;
        }
      }
    }
    
    template <class V, class K, class HF, class Ex, class Eq, class A>
    void
    hashtable<V, K, HF, Ex, Eq, A>::erase_bucket(const size_type n, node* last)
    {
      node* cur = buckets[n];
      while (cur != last) {
        node* next = cur->next;
        delete_node(cur);
        cur = next;
        buckets[n] = cur;
        --num_elements;
      }
    }
    
    // 清空hashtable, 但是不释放vector的内存
    template <class V, class K, class HF, class Ex, class Eq, class A>
    void hashtable<V, K, HF, Ex, Eq, A>::clear()
    {
      for (size_type i = 0; i < buckets.size(); ++i) {
        node* cur = buckets[i];
        while (cur != 0) {
          node* next = cur->next;
          delete_node(cur);
          cur = next;
        }
        buckets[i] = 0;
      }
      num_elements = 0;
    }
    
    // 复制另一个hashtable给当前hashtable
    template <class V, class K, class HF, class Ex, class Eq, class A>
    void hashtable<V, K, HF, Ex, Eq, A>::copy_from(const hashtable& ht)
    {
      // 首先清空当前hashtable
      buckets.clear();
      // 预留足够容量
      buckets.reserve(ht.buckets.size());
      // 完成初始化操作, 这是hashtable的先验条件
      buckets.insert(buckets.end(), ht.buckets.size(), (node*) 0);
      __STL_TRY {
        // 开始copy操作
        for (size_type i = 0; i < ht.buckets.size(); ++i) {
          if (const node* cur = ht.buckets[i]) {
            node* copy = new_node(cur->val);
            buckets[i] = copy;
    
            for (node* next = cur->next; next; cur = next, next = cur->next) {
              copy->next = new_node(next->val);
              copy = copy->next;
            }
          }
        }
        num_elements = ht.num_elements;
      }
      __STL_UNWIND(clear());
    }
    
    __STL_END_NAMESPACE
    
    #endif /* __SGI_STL_INTERNAL_HASHTABLE_H */
    
    // Local Variables:
    // mode:C++
    // End:
  • 相关阅读:
    uva 11997
    【USACO 3.1.1】最短网络
    【USACO 2.4.5】分数化小数
    【USACO 2.4.4】回家
    【USACO 2.4.3】牛的旅行
    【USACO 2.4.2】穿越栅栏
    【USACO 2.4.1】两只塔姆沃斯牛
    【USACO 2.3.5】控制公司
    【USACO 2.3.4】货币系统
    【USACO 2.3.3】零数列
  • 原文地址:https://www.cnblogs.com/zendu/p/4987795.html
Copyright © 2011-2022 走看看