当前位置:   article > 正文

【C++】STL之unordered_map和unordered_set的模拟实现

【C++】STL之unordered_map和unordered_set的模拟实现

哈希表的改造

哈希表的开散列方式拥有更高的空间利用率,所以unordered_map和unordered_set的底层使用开散列方式实现

以前实现的哈希表只能实现单一数据类型的插入操作,但是要用一个哈希表同时封装出unordered_map和unordered_set,就得对哈希表进行改造,让它更加通用

模板参数改造

unordered_mapKV结构的,而unordered_setK结构的,模板参数传入的值有可能是pair<K, V>, 也有可能是一个key,所以在进行对key的比较或者运算时,我们并不知道这个类型是pair还是key,所以我们需要把这个取值交给用户自己完成,添加一个模板参数KeyOfT,就可以在传参时传入key的取值规则,在运算时,不管传入的时哪种类型的数据,都可以取出key值进行比较运算,这个设计在map和set的模拟实现中就使用过

【C++】STL之map和set的模拟实现

template <class K, class T, class KeyOfT, class HashFunc = Hash<K>>
  • 1

添加默认成员函数

拷贝构造函数

拷贝构造采用深拷贝实现

  • 将哈希表的大小调整成要拷贝表的大小
  • 将要拷贝表中的结点一个一个的考到哈希表
  • 更改哈希表的有效个数
HashTable(const HashTable& ht) {
    _n = ht._n;
    _table.resize(ht._table.size());

    for (size_t i = 0; i < ht._table.size(); i++) {
        Node* cur = ht._table[i];
        while (cur) {
            Node* copy = new Node(cur->_data);
            copy->_next = _table[i];
            _table[i] = copy;
            cur = cur->_next;
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

赋值运算符重载

现代写法

HashTable& operator=(HashTable ht) {
    _table.swap(ht._table);
    swap(_n, ht._n);

    return *this;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

析构函数
~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] = nullptr;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

增加迭代器

由于哈希桶的性质,哈希表只能支持正向迭代器

结构
template <class K, class T, class KeyOfT, class HashFunc = Hash<K>>
struct __HTIterator {
    typedef HashNode<T> Node;
    typedef __HTIterator<K, T, KeyOfT, HashFunc> Self;
    typedef HashTable< K, T, KeyOfT, HashFunc> HT;
    Node* _node;
    HT* _pht;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

要实现**++操作**,需要在遍历完桶时找到下一个桶的头节点地址,所以迭代器结点中需要传入哈希表的地址

//构造函数
__HTIterator(Node* node, HT* pht)
	:_node(node) //结点指针
	, _pht(pht) //哈希表地址
{}
  • 1
  • 2
  • 3
  • 4
  • 5
++ 操作

++操作就算找当前结点的下一个结点

  • 如果当前结点不是这个桶的最后一个结点,++走到**当前结点下一个结点**
  • 如果当前结点是桶的最后一个结点,++走到**下一个非空桶第一个结点**
Self& operator++() {
    //当前桶中还有数据,走到当前桶结点的下一个
    if (_node->_next){
        _node = _node->_next;
    }
    //当前桶中没有数据了,走到下一个桶
    else {
        HashFunc hf;
        KeyOfT kot;

        //size_t index = HashFunc()(KeyOfT()(_node->_data)) % _pht->_table.size();
        size_t index = hf(kot(_node->_data)) % _pht->_table.size();

        ++index;
        while (index < _pht->_table.size()) {
            if (_pht->_table[index]) {
                _node = _pht->_table[index];
                return *this;
            }
            else {
                ++index;
            }
        }
        _node = nullptr;  
    }
    return *this;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

迭代器完整实现
template <class K, class T, class KeyOfT, class HashFunc = Hash<K>>
struct __HTIterator {
    typedef HashNode<T> Node;
    typedef __HTIterator<K, T, KeyOfT, HashFunc> Self;
    typedef HashTable< K, T, KeyOfT, HashFunc> HT;
    Node* _node;
    HT* _pht;

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


    Self& operator++() {
        //当前桶中还有数据,走到当前桶结点的下一个
        if (_node->_next) {
            _node = _node->_next;
        }
        //当前桶中没有数据了,走到下一个桶
        else {
            HashFunc hf;
            KeyOfT kot;

            //size_t index = HashFunc()(KeyOfT()(_node->_data)) % _pht->_table.size();
            size_t index = hf(kot(_node->_data)) % _pht->_table.size();

            ++index;
            while (index < _pht->_table.size()) {
                if (_pht->_table[index]) {
                    _node = _pht->_table[index];
                    return *this;
                }
                else {
                    ++index;
                }
            }
            _node = nullptr;
        }
        return *this;
    }

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

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

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

    bool operator ==(const Self& s) const {
        return _node == s._node;
    }
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

begin()函数

begin()函数就是返回哈希表中第一个非空桶的第一个结点的迭代器

iterator begin() {
    size_t i = 0;
    while (i < _table.size()) {
        if (_table[i]) {
            return iterator(_table[i], this);
        }
        ++i;
    }
    return end();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

end()函数

end()函数返回的是一个空迭代器

iterator end() {
    return iterator(nullptr, this);
}
  • 1
  • 2
  • 3

哈希表改造完整代码

#pragma once
#include<iostream>
#include<vector>
using namespace std;
namespace OpenHash {
    template<class T>
    struct HashNode {
        HashNode(const T& data)
            :_data(data)
            ,_next(nullptr)
        {}
        HashNode<T>* _next;
        T _data;
    };

    template<class K>
    struct Hash
    {
        size_t operator()(const K& key) //返回键值key
        {
            return key;
        }
    };

    //string类型的特化
    template<>
    struct Hash<string> {
        //BKDRHash算法
        size_t operator()(const string& s) {
            size_t value = 0;
            for (auto ch : s) {
                value += ch;
                value *= 131;
            }
            return value;
        }
    };

    //前置声明
    template <class K, class T, class KeyOfT, class HashFunc>
    class HashTable;

    template <class K, class T, class KeyOfT, class HashFunc = Hash<K>>
    struct __HTIterator {
        typedef HashNode<T> Node;
        typedef __HTIterator<K, T, KeyOfT, HashFunc> Self;
        typedef HashTable< K, T, KeyOfT, HashFunc> HT;
        Node* _node;
        HT* _pht;

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


        Self& operator++() {
            //当前桶中还有数据,走到当前桶结点的下一个
            if (_node->_next){
                _node = _node->_next;
            }
            //当前桶中没有数据了,走到下一个桶
            else {
                HashFunc hf;
                KeyOfT kot;

                //size_t index = HashFunc()(KeyOfT()(_node->_data)) % _pht->_table.size();
                size_t index = hf(kot(_node->_data)) % _pht->_table.size();

                ++index;
                while (index < _pht->_table.size()) {
                    if (_pht->_table[index]) {
                        _node = _pht->_table[index];
                        return *this;
                    }
                    else {
                        ++index;
                    }
                }
                _node = nullptr;  
            }
            return *this;
        }

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

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

        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 KeyOfT, class HashFunc = Hash<K>>
    class HashTable {
        typedef HashNode<T> Node;
        friend struct __HTIterator<K, T, KeyOfT, HashFunc>;
    public:
        typedef __HTIterator<K, T, KeyOfT, HashFunc> iterator;
        
        HashTable() = default; //显示生成默认构造函数

        HashTable(const HashTable& ht) {
            _n = ht._n;
            _table.resize(ht._table.size());

            for (size_t i = 0; i < ht._table.size(); i++) {
                Node* cur = ht._table[i];
                while (cur) {
                    Node* copy = new Node(cur->_data);
                    copy->_next = _table[i];
                    _table[i] = copy;
                    cur = cur->_next;
                }
            }
        }

        HashTable& operator=(HashTable ht) {
            _table.swap(ht._table);
            swap(_n, ht._n);

            return *this;
        }

        ~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] = nullptr;
            }
        }

        iterator begin() {
            size_t i = 0;
            while (i < _table.size()) {
                if (_table[i]) {
                    return iterator(_table[i], this);
                }
                ++i;
            }
            return end();
        }

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

        size_t GetNextPrime(size_t prime){
            static const int PRIMECOUNT = 28;
            static const size_t primeList[PRIMECOUNT] = {
                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
            };
            size_t i = 0;
            for (; i < PRIMECOUNT; ++i){
                if (primeList[i] > prime)
                    return primeList[i];
            }
            return primeList[i];
        }

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

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

            //负载因子到1时增容
            if (_n == _table.size()) {
                vector<Node*> newtable;

                /*size_t newSize = _table.size() == 0 ? 10 : _table.size() * 2;
                newtable.resize(newSize, nullptr);*/

                newtable.resize(GetNextPrime(_table.size()));

                //遍历取旧表中结点,重新计算映射位置,挂到新表中
                for (size_t i = 0; i < _table.size(); ++i) {
                    if (_table[i]) {
                        Node* cur = _table[i];
                        while (cur) {
                            //计算key在新表中的映射位置
                            Node* next = cur->_next;
                            size_t index = hf(kot(cur->_data)) % newtable.size();
                            //头插
                            cur->_next = newtable[index];
                            newtable[index] = cur;
                            cur = next;
                        }
                        _table[i] = nullptr;
                    }
                }
                _table.swap(newtable);
            }

            //计算key映射位置
            size_t index = hf(kot(data)) % _table.size();
            Node* newnode = new Node(data);

            //头插
            newnode->_next = _table[index];
            _table[index] = newnode;

            ++_n;

            return make_pair(iterator(newnode, this), true);
        }

        iterator Find(const K& key) {
            KeyOfT kot;
            HashFunc hf;
            if (_table.size() == 0) {
                return end();
            }

            size_t index = hf(key) % _table.size();
            Node* cur = _table[index];

            while (cur) {
                if (kot(cur->_data) == key) {
                    return iterator(cur, this);
                }
                else {
                    cur = cur->_next;
                }
            }
            return end();
        }


        bool Erase(const K& key) {
            HashFunc hf;
            size_t index = hf(key) % _table.size();

            Node* cur = _table[index];
            Node* prev = nullptr;

            while (cur) {
                if (kot(cur->_data) == key) {
                    if (prev == nullptr) {
                        //头删
                        _table[index] = cur->_next;                       
                    }
                    else {
                        prev->_next = cur->_next;
                    }
                    delete cur;
                    --_n;
                    return true;
                }
                else {
                    prev = cur;
                    cur = cur->_next;
                }
            }
            return false;
        }

    private:
        vector<Node*> _table;
        size_t _n;
    };
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283

unordered_map模拟实现

#pragma once
#include"HastTable.h"
namespace ns_unordered_map_set{
	template<class K, class V>
	class unordered_map {
	public:
		struct MapKeyOfT {
			const K& operator()(const pair<K, V>& kv) {
				return kv.first;
			}
		};

		typedef typename OpenHash::HashTable<K, pair<K, V>, 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);
		}

		void erase(const K& key)
		{
			_ht.Erase(key);
		}

		iterator find(const K& key)
		{
			return _ht.Find(key);
		}

		V& operator[](const K& key) {
			pair<iterator, bool> ret = _ht.Insert(make_pair(key, V()));
			return ret.first->second;
		}
	private:
		OpenHash::HashTable<K, pair<K, V>, MapKeyOfT> _ht;
	};
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

unordered_set模拟实现

#pragma once
#include"HastTable.h"
namespace ns_unordered_map_set {
	template<class K>
	class unordered_set {
	public:
		struct SetKeyOfT {
			const K& operator()(const K& key) {
				return key;
			}
		};

		typedef typename OpenHash::HashTable<K, K, SetKeyOfT>::iterator iterator;
		
		iterator begin() {
			return _ht.begin();
		}

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

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

		void erase(const K& key)
		{
			_ht.Erase(key);
		}

		iterator find(const K& key)
		{
			return _ht.Find(key);
		}

	private:
		OpenHash::HashTable<K, K, SetKeyOfT> _ht;
	};
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/人工智能uu/article/detail/941257
推荐阅读
相关标签
  

闽ICP备14008679号