_cpp利用哈希封装实现unordered_map和unordered_set

文章目录

链接:c++哈希(哈希表开散列实现的哈希表)
上面那篇文章,我们了解了哈希表的底层结构并模拟实现哈希表数据插入和删除。

这篇文章我们利用哈希表装实现unordered_map和unordered_set。

1.1 哈希表节点的定义

  • 因为我们要利用一颗树封装实现unordered_map和unordered_set,所以我们不能写死。
  • 怎么做?那看下面代码。
    template<class T>
    struct HashNode
    {

        T _data;
        HashNode<T>* _next;

        HashNode(const T& data)
            :_data(data)
            ,_next(nullptr)
        {}
    };

  • 我们把模板template
  • 看到这里uu们就很疑惑,那怎么区别那?我们就要借助仿函数(KeyOfT )-> 支持取出T对象中key的值。

1.2 哈希表中的迭代器

  • 迭代器大致框架跟利用红黑树封装map和set相同;区别我们上一篇文章实现的哈希表每一个位置是一个桶(单链表);我们只用模拟实现后置加加操作即可。

1.2.1 模拟实现后置加加的方法

  • 思路:加加分为俩种
    1. 当前桶位置找下一个节点。
    2. 找下一个哈希桶起始位置。
        typedef __HashIterator<K, T, Hash, KeyOfT> Self;
        Self& operator++()
        {
            if (_node->_next)
            {

                _node = _node->_next;
            }
            else
            {

                Hash hash;
                KeyOfT kot;
                size_t i = hash(kot(_node->_data)) % _pht->_tables.size();
                ++i;

                for (; i < _pht->_tables.size(); ++i)
                {
                    if (_pht->_tables[i])
                    {
                        _node = _pht->_tables[i];
                        break;
                    }
                }

                if (i == _pht->_tables.size())
                {
                    _node = nullptr;
                }
            }

1.2.2 哈希表迭代器代码

  • 注意:我们实现迭代器还要访问原来哈希表类的成员(私有成员需要把迭代器变为哈希表的友元,后面代码会写)

    template<class K, class T, class Hash, class KeyOfT>
    class HashTable;

    template<class K, class T, class Hash, class KeyOfT>
    struct __HashIterator
    {
        typedef HashNode<T> Node;
        typedef HashTable<K, T, Hash, KeyOfT> HT;
        typedef __HashIterator<K, T, Hash, KeyOfT> Self;

        Node* _node;
        HT* _pht;
        __HashIterator(Node* node, HT* pht)
            :_node(node)
            , _pht(pht)
        {}

        T& operator*()
        {
            return _node->_data;
        }

        T* operator->()
        {
            return &_node->_data;
        }

        Self& operator++()
        {
            if (_node->_next)
            {

                _node = _node->_next;
            }
            else
            {

                Hash hash;
                KeyOfT kot;
                size_t i = hash(kot(_node->_data)) % _pht->_tables.size();
                ++i;

                for (; i < _pht->_tables.size(); ++i)
                {
                    if (_pht->_tables[i])
                    {
                        _node = _pht->_tables[i];
                        break;
                    }
                }

                if (i == _pht->_tables.size())
                {
                    _node = nullptr;
                }
            }

            return *this;
        }

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

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

    };

1.3 仿函数

  • 除了上章比较用的仿函数Hash = HashFunc;此章我们还需要一个区分unordered_map和unordered_set的仿函数。
  • 因为map是pair
        struct MapKeyOfT
        {
            const K& operator()(const pair<K, V>& kv)
            {
                return kv.first;
            }
        };
        struct MapKeyOfT
        {
            const K& operator()(const K& val)
            {
                return val;
            }
        };

实现过程就在上图代码里了。

1.4 哈希表整体改造完成后的代码

namespace HashBucket
{
    template<class T>
    struct HashNode
    {

        T _data;
        HashNode<T>* _next;

        HashNode(const T& data)
            :_data(data)
            ,_next(nullptr)
        {}
    };

    template<class K, class T, class Hash, class KeyOfT>
    class HashTable;

    template<class K, class T, class Hash, class KeyOfT>
    struct __HashIterator
    {
        typedef HashNode<T> Node;
        typedef HashTable<K, T, Hash, KeyOfT> HT;
        typedef __HashIterator<K, T, Hash, KeyOfT> Self;

        Node* _node;
        HT* _pht;
        __HashIterator(Node* node, HT* pht)
            :_node(node)
            , _pht(pht)
        {}

        T& operator*()
        {
            return _node->_data;
        }

        T* operator->()
        {
            return &_node->_data;
        }

        Self& operator++()
        {
            if (_node->_next)
            {

                _node = _node->_next;
            }
            else
            {

                Hash hash;
                KeyOfT kot;
                size_t i = hash(kot(_node->_data)) % _pht->_tables.size();
                ++i;

                for (; i < _pht->_tables.size(); ++i)
                {
                    if (_pht->_tables[i])
                    {
                        _node = _pht->_tables[i];
                        break;
                    }
                }

                if (i == _pht->_tables.size())
                {
                    _node = nullptr;
                }
            }

            return *this;
        }

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

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

    };

    template<class K, class T, class Hash, class KeyOfT>
    class HashTable
    {
        typedef HashNode<T> Node;
        template<class K, class T, class Hash, class KeyOfT>
        friend struct __HashIterator;
    public:
        typedef __HashIterator<K, T, Hash, KeyOfT> iterator;
        iterator begin()
        {
            for (size_t i = 0; i < _tables.size(); ++i)
            {
                if (_tables[i])
                {
                    return iterator(_tables[i], this);
                }
            }

            return end();
        }

        iterator end()
        {
            return iterator(nullptr, this);
        }

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

                    delete cur;
                    cur = next;
                }
                _tables[i] = nullptr;
            }
        }

        inline size_t __stl_next_prime(size_t n)
        {
            static const size_t __stl_num_primes = 28;
            static const size_t __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, 3221225473, 4294967291
            };

            for (size_t i = 0; i < __stl_num_primes; ++i)
            {
                if (__stl_prime_list[i] > n)
                {
                    return __stl_prime_list[i];
                }
            }

            return -1;
        }

        pair<iterator, bool> Insert(const T& data)
        {
            KeyOfT kot;
            Hash hash;

            iterator ret = Find(kot(data));
            if (ret != end())
            {
                return make_pair(ret, false);
            }

            if (_tables.size() == _size)
            {

                vector<Node*> newTables;

                    newTables.resize(__stl_next_prime(_tables.size()), nullptr);

                for (size_t i = 0; i < _tables.size(); i++)
                {
                    Node* cur = _tables[i];
                    while (cur)
                    {
                        Node* next = cur->_next;

                        size_t hashi = hash(kot(cur->_data)) % newTables.size();

                        cur->_next = newTables[hashi];
                        newTables[hashi] = cur;

                        cur = next;
                    }
                    _tables[i] = nullptr;
                }
                _tables.swap(newTables);
            }

            size_t hashi = hash(kot(data)) % _tables.size();

            Node * newNode = new Node(data);
            newNode->_next = _tables[hashi];
            _tables[hashi] = newNode;
            ++_size;

            return make_pair(iterator(newNode, this), false);
        }

        iterator Find(const K& key)
        {
            if (Empty())
            {
                return end();
            }

            KeyOfT kot;
            Hash hash;
            size_t hashi = hash(key) % _tables.size();
            Node* cur = _tables[hashi];
            while (cur)
            {
                if (kot(cur->_data) == key)
                {

                    return iterator(cur, this);
                }
                cur = cur->_next;
            }

            return end();
        }

        bool Empty() const
        {
            return _size == 0;
        }

        bool Erase(const K& key)
        {
            if (Empty())
            {
                return false;
            }
            Hash hash;
            int hashi = hash(key) % _tables.size();
            Node* cur = _tables[hashi];
            Node* prev = nullptr;
            while (cur)
            {

                if (key == kot(cur->_data))
                {
                    if (prev)
                    {
                        prev->_next = cur->_next;
                    }
                    else
                    {
                        _tables[hashi] = cur->_next;
                    }
                    delete cur;
                    --_size;
                    return true;
                }
                prev = cur;
                cur = cur->_next;
            }

            return false;
        }

        size_t Size()
        {
            return _size;
        }

        size_t TablesSize()
        {
            return _tables.size();
        }

        size_t BucketNum()
        {
            size_t num = 0;
            for (size_t i = 0; i < _tables.size(); ++i)
            {
                if (_tables[i])
                {
                    ++num;
                }
            }

            return num;
        }

        size_t MaxBucketLenth()
        {
            size_t maxLen = 0;
            for (size_t i = 0; i < _tables.size(); ++i)
            {
                size_t len = 0;
                Node* cur = _tables[i];
                while (cur)
                {
                    ++len;
                    cur = cur->_next;
                }

                if (len > maxLen)
                {
                    maxLen = len;
                }
            }

            return maxLen;
        }
    private:
        vector<Node*> _tables;
        size_t _size = 0;
    };

}

  1. 封装实现unordered_map

  2. 注意:typename的使用–我们要取取类里面的类型而不是变量(例如:类的静态变量)需要说明。

#pragma once
#include "HashTable.h"

namespace Ding
{
    template<class K, class V, class Hash = HashFunc<K>>
    class unordered_map
    {
        struct MapKeyOfT
        {
            const K& operator()(const pair<K, V>& kv)
            {
                return kv.first;
            }
        };
    public:
        typedef typename  HashBucket::HashTable<K, pair<K, V>, Hash, MapKeyOfT> ::iterator iterator;

        iterator begin()
        {
            return _ht.begin();
        }

        iterator end()
        {
            return _ht.end();
        }

        pair<iterator, bool> insert(const pair<K, V>& kv)
        {
            return _ht.Insert(kv);
        }

        V& operator[](const K& key)
        {
            pair<iterator, bool> ret = _ht.Insert(make_pair(key, V()));
            return ret.first->second;
        }
    private:
        HashBucket::HashTable<K, pair<K, V>, Hash, MapKeyOfT> _ht;
    };
  1. 封装实现unordered_set

  2. 注意:typename的使用–我们要取取类里面的类型而不是变量(例如:类的静态变量)需要说明。

#pragma once

#include "HashTable.h"

namespace Ding
{
    template<class K, class Hash = HashFunc<K>>
    class unordered_set
    {
        struct MapKeyOfT
        {
            const K& operator()(const K& val)
            {
                return val;
            }
        };
    public:
        typedef typename  HashBucket::HashTable<K, K, Hash, MapKeyOfT> ::iterator iterator;

        iterator begin()
        {
            return _ht.begin();
        }

        iterator end()
        {
            return _ht.end();
        }

        pair<iterator, bool> insert(const K& val)
        {
            return _ht.Insert(val);
        }

    private:
        HashBucket::HashTable<K, K, Hash, MapKeyOfT> _ht;
    };

  1. 测试案例

/unordered_map/

    void test_map()
    {
        unordered_map<string, string> dict;
        dict.insert(make_pair("sort", "排序"));
        dict.insert(make_pair("right", "右边"));
        dict.insert(make_pair("left", "左边"));

        unordered_map<string, string>::iterator it = dict.begin();
        while (it != dict.end())
        {
            cout << it->first << ":" << it->second << endl;
            ++it;
        }
        cout << endl;

        unordered_map<string, int> countMap;
        string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
        for (auto e : arr)
        {
            countMap[e]++;
        }

        for (auto& kv : countMap)
        {
            cout << kv.first << ":" << kv.second << endl;
        }
    }
}

/unordered_set/

    void test_set()
    {
        unordered_set<int> s;
        s.insert(2);
        s.insert(3);
        s.insert(1);
        s.insert(2);
        s.insert(5);

        unordered_set<int>::iterator it = s.begin();

        while (it != s.end())
        {
            cout << *it << " ";
            ++it;
        }
        cout << endl;
    }
}

  1. 测试结果

_cpp利用哈希封装实现unordered_map和unordered_set

Original: https://blog.csdn.net/Dingyuan0/article/details/127816725
Author: 潜水少年请求出战
Title: _cpp利用哈希封装实现unordered_map和unordered_set

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/654764/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球