STL容器之哈希的补充——unordered_map和unordered_set对哈希桶的封装

1.unordered_map和unordered_set对哈希桶的封装

1.1封装的准备

​ 1.节点存放的是data;2.对于key的比较要使用仿函数KeyOfT类型的对象;

1.2迭代器的实现

1.2.1迭代器类成员设计
//由于++需要找到下一个桶位置,所以需要存一个哈希表指针方便查找桶的位置
node *node_;
HashTable<K, T, KeyOfT>* htptr_;
1.2.2++运算符的重载

​ 1.如果当前位置的下一个不为空,node继续往下走;2.为空找下一个桶的位置,计算出当前key所映射的桶位置,从下一个桶开始,不断的往后++;3.如果桶不为空node指向此桶,为空向后++;4.如果最后表全部遍历完毕,没有找到就像红黑树一样,指向空;

1.2.3迭代器内部存放哈希表指针

​ 会存在相互依赖的问题,即哈希表里面使用迭代器,迭代器里面使用哈希表,此时就需要用前置声明解决,但是前置声明不可以给缺省值,注意声明友元类时,对于g++会出现阴影模板参数,不允许模板参数名相同,解决方法就是修改模板参数名即可;

1.2.4对于const迭代器

​ 注意要将哈希表指针改成const,因为unordered_set使用的都是const迭代器,需要传递this,但是*this不可以修改,所以要使用const接收指针;

1.2.5插入

​ 不同的迭代器对象需要使用构造来解决;为了支持普通迭代器构造const迭代器,或者普通迭代器构造普通迭代器。insert返回pair类型

1.2.6operator[]

​ 复用insert。

代码实现:

namespace HashBucket
{
    template <class K>
    struct Default // 仿函数强转为无符号整型
    {
        size_t operator()(const K &key)
        {
            return (size_t)key;
        }
    };
    template <>
    struct Default<std::string> // 模板的特化处理string字符串类型
    {
        size_t operator()(const std::string &key)
        {
            size_t i = 0;
            for (const auto &ch : key)
            {
                i *= 131;
                i += ch;
            }
            return i;
        }
    };
    template <class T>
    struct HashNode
    {
        HashNode(const T &data) : data_(data), next_(nullptr) {}
        T data_;
        HashNode<T> *next_;
    };
    template <class K, class T, class KeyOfT, class HashFunc = Default<K>>
    class HashTable;
    template <class K, class T, class Ptr, class Ref, class KeyOfT, class HashFunc>
    struct __HashTableIterator
    {
        typedef HashNode<T> node;
        typedef __HashTableIterator<K, T, Ptr, Ref, KeyOfT, HashFunc> Self;
        typedef __HashTableIterator<K, T, T *, T &, KeyOfT, HashFunc> iterator;
        __HashTableIterator(node *node, const HashTable<K, T, KeyOfT, HashFunc> *htptr) : node_(node), htptr_(htptr) {}
        __HashTableIterator(const iterator &iter) : node_(iter.node_), htptr_(iter.htptr_) {}
        Ref operator*()
        {
            return node_->data_;
        }
        Ptr operator->()
        {
            return &(node_->data_);
        }
        Self &operator++()
        {
            HashFunc func;
            KeyOfT kot;
            if (node_->next_)
            {
                node_ = node_->next_;
                return *this;
            }
            else
            {
                size_t hashi = func(kot(node_->data_)) % htptr_->table_.size();
                ++hashi;
                while (hashi < htptr_->table_.size())
                {
                    if (htptr_->table_[hashi])
                    {
                        node_ = htptr_->table_[hashi];
                        return *this;
                    }
                    else
                    {
                        ++hashi;
                    }
                }
                node_ = nullptr;
                return *this;
            }
        }
        bool operator!=(const Self &iterator) const
        {
            return node_ != iterator.node_;
        }
        bool operator==(const Self &iterator) const
        {
            return node_ == iterator.node_;
        }
        node *node_;
        const HashTable<K, T, KeyOfT, HashFunc> *htptr_;
    };
    template <class K, class T, class KeyOfT, class HashFunc>
    class HashTable
    {
        template <class K1, class T1, class Ptr1, class Ref1, class KeyOfT1, class HashFunc1>
        friend struct __HashTableIterator;
        typedef HashNode<T> node;

    public:
        typedef __HashTableIterator<K, T, T *, T &, KeyOfT, HashFunc> iterator;
        typedef __HashTableIterator<K, T, const T *, const T &, KeyOfT, HashFunc> const_iterator;

    public:
        // 迭代器的实现
        iterator begin()
        {
            for (size_t i = 0; i < table_.size(); ++i)
            {
                if (table_[i])
                {
                    return {table_[i], this};
                }
            }
            return {nullptr, this};
        }
        iterator end()
        {
            return {nullptr, this};
        }
        const_iterator begin() const
        {
            for (size_t i = 0; i < table_.size(); ++i)
            {
                if (table_[i])
                {
                    return {table_[i], this};
                }
            }
            return {nullptr, this};
        }
        const_iterator end() const
        {
            return {nullptr, this};
        }

    public:
        HashTable() : size_(0)
        {
            table_.resize(10, nullptr);
        }
        ~HashTable()
        {
            for (size_t i = 0; i < table_.size(); i++)
            {
                node *cur = table_[i];
                while (cur)
                {
                    node *next = cur->next_;
                    delete cur;
                    cur = next; //*cur被释放,cur->next就是野指针访问,所以需要记录next位置;
                }
                table_[i] = nullptr;
            }
        }
        std::pair<iterator, bool> insert(const T &data)
        {
            KeyOfT kot;
            HashFunc func;
            iterator cur = find(kot(data));
            if (cur != end())
            {
                return {cur, false};
            }
            // 扩容
            if (size_ == table_.size())
            {
                size_t newsize = table_.size() * 2;
                std::vector<node *> newtable;
                newtable.resize(newsize, nullptr);
                // 遍历旧表,讲节点挂到新表
                for (size_t i = 0; i < table_.size(); i++)
                {
                    node *cur = table_[i];
                    while (cur)
                    {
                        node *next = cur->next_;
                        size_t hashi = func(kot(cur->data_)) % newsize;
                        cur->next_ = newtable[hashi];
                        newtable[hashi] = cur;
                        cur = cur->next_;
                    }
                    table_[i] = nullptr;
                }
                table_.swap(newtable);
            }
            size_t hashi = func(kot(data)) % table_.size();
            // 头插 访问最新插入的元素较快
            node *newnode = new node(data);
            newnode->next_ = table_[hashi];
            table_[hashi] = newnode;
            ++size_;
            return {{newnode, this}, true};
        }
        iterator find(const K &key)
        {
            KeyOfT kot;
            HashFunc func;
            size_t hashi = func(key) % table_.size();
            node *cur = table_[hashi];
            while (cur)
            {
                if (kot(cur->data_) == key)
                {
                    return {cur, this};
                }
                cur = cur->next_;
            }
            return {nullptr, this};
        }
        void print()
        {
            for (size_t i = 0; i < table_.size(); ++i)
            {
                KeyOfT kot;
                printf("[%d] -> ", i);
                node *cur = table_[i];
                while (cur)
                {
                    std::cout << kot(cur->data_) << " -> ";
                    cur = cur->next_;
                }
                if (!cur)
                {
                    std::cout << "nullptr";
                }
                std::cout << std::endl;
            }
            std::cout << std::endl;
        }
        bool erase(const K &key)
        {
            KeyOfT kot;
            HashFunc func;
            if (!find(key))
            {
                return false;
            }
            size_t hashi = func(key) % table_.size();
            node *cur = table_[hashi];
            node *prev = cur;
            if (kot(cur->data_) == key)
            {
                table_[hashi] = cur->next_;
                delete cur;
                --size_;
                return true;
            }
            else
            {
                while (cur)
                {
                    if (kot(cur->data_) == key)
                    {
                        prev->next_ = cur->next_;
                        delete cur;
                        --size_;
                        return true;
                    }
                    prev = cur;
                    cur = cur->next_;
                }
                return false;
            }
        }

    private:
        std::vector<node *> table_;
        size_t size_; // 记录存储了多少有效数据
    };
}

namespace Unordered_map
{
    template <class K, class V>
    class unordered_map
    {
        struct MapKeyOfT
        {
            const K &operator()(const std::pair<K, V> &kv)
            {
                return kv.first;
            }
        };

    public:
        typedef typename HashBucket::HashTable<K, std::pair<const K, V>, MapKeyOfT>::iterator iterator;
        typedef typename HashBucket::HashTable<K, std::pair<const K, V>, MapKeyOfT>::const_iterator const_iterator;

        iterator begin()
        {
            return hashtable_.begin();
        }
        iterator end()
        {
            return hashtable_.end();
        }
        const_iterator begin() const
        {
            return hashtable_.begin();
        }
        const_iterator end() const
        {
            return hashtable_.end();
        }

    public:
        std::pair<iterator, bool> insert(const std::pair<const K, V> kv)
        {
            return hashtable_.insert(kv);
        }
        V &operator[](const K &key)
        {
            std::pair<iterator, bool> it = insert({key, V()});
            return it.first->second;
        }

    private:
        HashBucket::HashTable<K, std::pair<const K, V>, MapKeyOfT> hashtable_;
    };
}

namespace Unordered_set
{
    template <class K>
    class unordered_set
    {
        struct SetKeyOfT
        {
            const K &operator()(const K &key)
            {
                return key;
            }
        };

    public:
        typedef typename HashBucket::HashTable<K, K, SetKeyOfT>::const_iterator iterator;
        typedef typename HashBucket::HashTable<K, K, SetKeyOfT>::const_iterator const_iterator;
        iterator begin() const
        {
            return hashtable_.begin();
        }
        iterator end() const
        {
            return hashtable_.end();
        }

    public:
        std::pair<iterator, bool> insert(const K &key)
        {
            std::pair<iterator, bool> it = hashtable_.insert(key);
            return it;
        }

    private:
        HashBucket::HashTable<K, K, SetKeyOfT> hashtable_;
    };
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值