数据结构 哈希表(3)——UnorderedMap实现

unordered_map


无序映射表(Unordered Map)容器是一个存储以键值对组合而成的元素的关联容器(Associative container),容器中的元素无特别的次序关系。该容器允许基于主键地快速检索各个元素

// <unordered_map>
template < class Key,       
    class T,
    class Hash = hash<Key>,
    class Pred = equal_to<Key>,
    class Alloc = allocator< pair<const Key,T> >
> class unordered_map;

模板参数:

  • Key:主键的类型
  • T:被映射的值的类型
  • Hash:一元谓词,以一个 Key 类型的对象为参数,返回一个基于该对象的 size_t 类型的唯一值
  • Pred:二元谓词,以两个 Key 类型的对象为参数,返回一个 bool 值,如果第一个参数等价于第二个参数,该 bool 值为 true,否则为 false
  • Alloc:容器内部用来管理内存分配及释放的内存分配器的类型

在一个 unordered_map 容器中,主键通常被用来唯一标志(Uniquely identify)一个元素,而被映射的值保存了与该主键关联的内容。主键与被映射值的类型可以不同,在模板内部,这两种类型合并绑定成成员类型 value_type。由上述描述可知,value_type 是一个双元组类型(Pair type),具体定义如下:

typedef pair<const Key, T> value_type;

在 unordered_map 内部,元素不会按任何顺序排序,而是通过主键的 hash 值将元素分组放置到各个槽(Bucket,也可译成“桶”)中,这样就能通过主键快速地访问各个对应的元素(平均耗时为一个常量,即时间复杂度为 O(1))

在访问容器中的某个元素时,unordered_map 容器比 map 容器高效,而在迭代容器元素的某个子集时,前者比后者稍微低效了一点

unordered_map 实现了直接访问操作符(operator[]),使得可以通过主键(Key value)直接访问被映射的值(Mapped value)

unordered_map 容器支持正向迭代

unordered_map封装实现


通过上面对unordered_map的介绍,unordered_map容器底层使用哈希表的拉链法实现的,前面我们已经实现过处理哈希冲突的拉链法,下面我们自己封装实现一下unordered_map容器

哈希函数的构造:

template <class K>
struct HashFunc
{
    size_t operator()(const K& key)
    {
        return key;
    }
};

template <>
struct HashFunc<string> //特化string类型的仿函数
{
    static size_t BKDRHash(const char * str)
    {
        unsigned int seed = 131; 
        unsigned int hash = 0;
        while (*str)
        {
            hash = hash * seed + (*str++);
        }
        return (hash & 0x7FFFFFFF);
    }

    size_t operator()(const string& key)
    {
        return BKDRHash(key.c_str());
    }
};

HashNode结构定义:

template <class K,class V>
struct HashNode
{
    pair<const K, V> _kv;//存一个pair结构   
    HashNode<K, V>* _next;

    HashNode(const pair<K, V>& kv)
        :_kv(kv)
        ,_next(NULL)
    {}
};

实现迭代器:

template <class K, class V, class HashFunc = _HashFunc<K>>
class HashTable;

template <class K,class V,class Ref,class Ptr>
struct HashIterator
{
    typedef struct HashNode<K, V> Node;
    typedef HashIterator<K, V, Ref, Ptr> Self;

    Node* _node;
    HashTable<K, V,HashFunc<K>>* _hashTable;

    HashIterator(Node* node, HashTable<K, V, HashFunc<K>>* ht)
        :_node(node)
        , _hashTable(ht)
    {}

    Node* _Next()
    {
        if (_node->_next)
        {
            return _node->_next;
        }//_node->_next==NULL,则需找到哈希表的下一个位置

        size_t index = _hashTable->_HashFunc((_node->_kv).first);
        for (size_t i = index + 1; i < _hashTable->_table.size(); ++i)
        {
            if (_hashTable->_table[i])
                return _hashTable->_table[i];
        }
        return NULL;
    }

    Node* _Prev()
    {
        //若_node并非当前链表的头结点,则只需找到其所在链表的前一个位置
        //若_node为当前链表的头结点,则需要找到哈希表的前一个非空位置链表的最后一个节点
        size_t index = _hashTable->_HashFunc((_node->_kv).first);
        if (_hashTable->_table[index]!=_node)
        {
            Node* prev = _hashTable->_table[index];
            Node* cur = prev->_next;
            while (cur)
            {
                if (cur == _node)
                    return prev;
                prev = prev->_next;
                cur = cur->_next;
            }
        }
        for (size_t i = index - 1; index > 0; --index)
        {
            if (_hashTable->_table[i])
            {
                Node* cur = _hashTable->_table[i];
                Node* next = cur->_next;
                while (next)
                {
                    cur = cur->_next;
                    next = cur->_next;
                }
                return cur;
            }
        }
        return NULL;
    }

    //前置++,返回值为++之后的值
    Self& operator++()
    {
        _node = _Next();
        return *this;
    }

    //后置++,返回值为++之前的值
    Self operator++(int)
    {
        Node* cur = _node;
        _node = _Next;
        return cur;
    }

    Self& operator--()
    {
        _node = _Prev();
        return *this;
    }

    Self operator--(int)
    {
        Node* cur = _node;
        _node = _Prev();
        return cur;
    }

    Ptr operator->()
    {
        return  &_node->_kv;
    }

    Ref & operator*()
    {
        return  _node->_kv;
    }

    bool operator==(const Self& tmp)
    {
        return (_node == tmp._node);
    }

    bool operator!=(const Self& tmp)
    {
        return _node != tmp._node;
    }
};

实现HashTable:

template <class K, class V, class HashFunc = _HashFunc<K>>
class HashTable
{
    typedef struct HashNode<K, V> Node;
public:
    typedef HashIterator<K, V, pair<K, V>&, pair<K, V>*> Iterator;
    typedef HashIterator<K, V, const pair<K, V>&, const pair<K, V>*> const_Iterator;
    friend struct Iterator;
    friend struct const_Iterator;
public:
    HashTable()
        :_size(0)
    {
        _table.resize(_GetNextPrime(0));
    }

    ~HashTable()
    {
        for (size_t i = 0; i < _table.size(); ++i)
        {
            Node* cur = _table[i];
            while (cur)
            {
                Node* next = cur->_next;
                delete cur;
                cur = next;
            }
            _table[i] = NULL;
        }
    }

    //插入函数  
    pair<Iterator, bool> Insert(const pair<K, V>& kv)
    {
        //检查容量  
        _CheckCapacity();
        //先查找   
        Node * cur = Find(kv.first)._node;
        if (cur)//找到返回失败  
        {
            return make_pair(Iterator(cur, this), false);//返回该节点的迭代器,,并且插入失败   
        }
        Node * node = new Node(kv);//新建节点   
        size_t index = _HashFunc(kv.first);
        cur = _table[index];
        if (cur)
        {
            node->_next = cur;
        }
        _table[index] = node;
        ++_size;
        return  make_pair(Iterator(node, this), true);//返回新增的节点的迭代器,,,插入成功  
    }
    //查找函数  
    Iterator Find(const K& key)
    {
        size_t index = _HashFunc(key);//找到对应的哈希地址   
        Node* cur = _table[index];
        while (cur)
        {
            if (cur->_kv.first == key)//找到的话  
                return Iterator(cur, this);//返回该位置的迭代器  
            cur = cur->_next;
        }
        return Iterator(NULL, this);//没找到的话,,返回一个为NULL的迭代器  

    }
    bool Erase(const K& key)
    {
        Node* cur = Find(key)._node;
        if (cur)
        {
            size_t index = _HashFunc(key);
            if (_table[index] == cur)
            {

                delete cur;
                _table[index] = NULL;
            }
            else
            {
                Node* prev = _table[index];
                while (prev->_next != cur)
                {
                    prev = prev->_next;
                }//prev->_next==cur;
                delete cur;
                prev->_next = NULL;
            }
            --_size;
            return true;
        }
        return false;
    }
    Iterator  Begin()
    {
        for (size_t i = 0; i< _table.size(); ++i)
        {
            Node* cur = _table[i];
            if (cur)
            {
                return  Iterator(cur, this);
            }
        }
        return  Iterator(NULL, this);
    }
    const_Iterator  Begin()const
    {
        for (size_t i = 0; i< _tables.size(); ++i)
        {
            Node* cur = _tables[i];
            if (cur)
            {
                return  Iterator(cur, this);
            }
        }
        return  Iterator(NULL, this);
    }
    const_Iterator End()const
    {
        return  Iterator(NULL, this);
    }
    Iterator End()
    {
        return  Iterator(NULL, this);
    }

    //使用迭代器输出哈希表内的数据   
    void  Print()
    {
        Iterator it = Begin();
        while (it != End())
        {
            cout << "("<< it->first << " ," << it->second << ")" << endl;
            ++it;
        }
        cout << endl;
    }
protected:
    void _Swap(HashTable<K, V,HashFunc>& tmp)
    {
        _table.swap(tmp._table);
        swap(_size, tmp._size);
    }
    void _CheckCapacity()
    {
        //若哈希表的负载因子>=0.7(也可以是>=1)或者哈希表的长度为0,则进行重构哈希表
        if (_size * 10 / _table.size() >= 7 || _table.size() == 0)
        {
            size_t newSize = _GetNextPrime(_table.size());
            //哈希表扩容后进行重构
            HashTable<K, V, HashFunc> newTable;
            newTable._table.resize(newSize);

            //将原哈希表中的元素插入到扩容后的哈希表中
            for (size_t i = 0; i < _table.size(); ++i)  
            {
                Node* cur = _table[i];
                while (cur)
                {
                    newTable.Insert(cur->_kv);
                    cur = cur->_next;
                }
            }
            _Swap(newTable);
        }
    }

    size_t _GetNextPrime(const size_t size)
    {
        const int _PrimeSize = 28;//编译器为我们提供的素数表的长度  
        //素数表  
        static const unsigned long _PrimeList[_PrimeSize] =
        {
            53ul, 97ul, 193ul, 389ul, 769ul,
            1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
            49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
            1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
            50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
            1610612741ul, 3221225473ul, 4294967291ul
        };
        for (size_t i = 0; i < _PrimeSize; ++i)
        {
            if (_PrimeList[i] > size)//找到下一个素数  
            {
                return  _PrimeList[i];
            }
        }
        return _PrimeList[_PrimeSize - 1];//如果要是已经是最大了,,就直接返回最后的值  
    }

    size_t _HashFunc(const K& key)
    {
        return HashFunc()(key) % _table.size();
    }
private:
    vector<Node*> _table;
    size_t _size;
};

实现UnorderedMap:

template<class K, class V, class HashFunc = _HashFunc<K>>
class UnorderedMap
{
    typedef HashTable<K, V, HashFunc> HashTable;
public:
    typedef   typename HashTable::Iterator  Iterator;
    typedef   typename HashTable::const_Iterator  const_Iterator;

    UnorderedMap()
    {}


    //插入函数   
    pair<Iterator, bool> Insert(const pair<K, V> & kv)
    {
        return _hashTable.Insert(kv);//直接调用 hash表的函数  
    }
    bool Erase(const K& key)
    {
        return  _hashTable.Erase(key);//调用 删除函数   
    }
    Iterator  Find(const  K& key)
    {
        return _hashTable.Find(key);//调用   查找函数   
    }
    Iterator Begin()
    {
        return  _hashTable.Begin();//直接调用    
    }
    const_Iterator Begin()const
    {
        return  _hashTable.Begin();
    }
    Iterator End()
    {
        return _hashTable.End();
    }
    const_Iterator End()const
    {
        return _hashTable.End();
    }
    void Print()
    {
        _hashTable.Print();
    }
protected:
    HashTable _hashTable;
};

猜你喜欢

转载自blog.csdn.net/Aurora_pole/article/details/80497717
今日推荐