赞
踩
目录
开散列法又叫链地址法(开链法),首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链接起来,各链表的头结点存储在哈希表中。
从上图可以看出,开散列中每个桶中放的都是发生哈希冲突的元素。
应用链地址法处理溢出,需要增设链接指针,似乎增加了存储开销。事实上: 由于开地址法必须保持大量的空闲空间以确保搜索效率,如二次探查法要求装载因子a <= 0.7,而表项所占空间又比指针大的多,所以使用链地址法反而比开地址法节省存储空间。
当数据类型不是整数时,我们需要通过哈希函数将其转换为一个size_t类型的无符号整形然后%上哈希表的容量得出一个映射值,所以需要针对不同的数据类型,来构造不同的Hashfunc来将其转换为size_t类型,这时就要用到模板特化来处理数据,尤其是字符串类型。
同时针对set和map的不同,我们需要将hash桶的模板可以满足两种不同类型的调用,所以在参数上也要设置两个参数,如果是set传参,就让两个参数都是K,如果是map传参,第一个参数是K,第二个参数则是pair<K,V>,而在构造哈希表的node时,不管是set还是map都只需要传第二个参数过去,而hashnode也只需要用一个template<class T>来进行接收就好,然后构造初始化出T _data和一个T* _next的指针来指向桶中下一个节点。
那为什么在传参时不直接只设置一个参数呢?因为在调用find时,需要传一个值进去查找,如果是set则直接查找,如果是map则需要取出hashnode中的first与之进行比较,所以必须设置两个模板参数。
桶的个数是一定的,随着元素的不断插入,每个桶中元素的个数不断增多,极端情况下,可能会导致一个桶中链表节点非常多,会影响的哈希表的性能,因此在一定条件下需要对哈希表进行增容,那该条件怎么确认呢?开散列最好的情况是:每个哈希桶中刚好挂一个节点,再继续插入元素时,每一次都会发生哈希冲突,因此,在元素个数刚好等于桶的个数时,可以给哈希表增容。
因为开散列每个位置都是一串单链表,所以在插入节点时,直接选择头插即可,头插的消耗和速度都是最小的。
- #pragma once
- #include<iostream>
- using namespace std;
- #include<vector>
- #include<string>
-
- template<class K>
- struct HashFunc
- {
- size_t operator()(const K& key)
- {
- return (size_t)key;
- }
- };
-
- // 特化
- template<>
- struct HashFunc<string>
- {
- size_t operator()(const string& s)
- {
- size_t hash = 0;
- for (auto e : s)
- {
- hash += e;
- hash *= 131;
- }
-
- return hash;
- }
- };
- namespace hash_bucket
- {
- //如果是unordered_set的话T=K
- //如果是unordered_map的话T=pair<K,V>
- template<class T>
- struct HashNode
- {
- HashNode<T>* _next;
- T _data;
- HashNode(const T& data)
- :_next(nullptr)
- ,_data(data)
- {}
- };
- // 前置声明,因为编译器编译时会向上进行查找,而iterator要去调用哈希表,所以需要提前进行前置声明
- template<class K, class T, class Keyoft, class Hash >
- class HashTable;
-
- //迭代器实现
- template<class K, class T, class Keyoft, class Hash >
- struct __HTIterator
- {
- typedef HashNode<T> Node;
- typedef HashTable<K, T, Keyoft, Hash> HT;
- typedef __HTIterator<K, T, Keyoft, Hash> Self;
-
- Node* _node;
- HT* _ht;
-
- __HTIterator(Node* node,HT* ht)
- :_node(node)
- ,_ht(ht)
- {}
-
- T& operator*()
- {
- return _node->_data;
- }
-
- Self& operator++()
- {
- //如果当前桶内还有节点
- if (_node->_next)
- {
- _node = _node->_next;
- }
- else
- {
- //当前桶找完,就去找下一个桶
- Keyoft kot;
- Hash hs;
- size_t hashi = hs(kot(_node->_data)) % _ht->_tables.size();
- hashi++;
- while (hashi < _ht->_tables.size())
- {
- if (_ht->_tables[hashi])
- {
- _node = _ht->_tables[hashi];
- break;
- }
- hashi++;
- }
-
- //如果后面没有桶
- if (hashi == _ht->_tables.size())
- {
- _node = nullptr;
- }
- }
-
- return *this;
- }
- bool operator!=(const Self& s)
- {
- return _node != s._node;
- }
- };
-
- //哈希桶搭建
- template<class K, class T,class Keyoft,class Hash>
- class HashTable
- {
- template<class K, class T, class KeyOfT, class Hash>
- friend struct __HTIterator;
-
- typedef HashNode<T> Node;
-
- public:
- typedef __HTIterator< K, T, Keyoft, Hash> iterator;
- HashTable()
- {
- _tables.resize(10, nullptr);
- _n = 0;
- }
- ~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;
- }
- }
- 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);
- }
- //插入节点
- bool insert(const T& data)
- {
- Keyoft kot;
- if (Find(kot(data)))
- return false;
-
- Hash hs;
- //负载因子到1就扩容
- if (_n == _tables.size())
- {
- vector<Node*> newtables(_tables.size() * 2,nullptr);
- for (size_t i = 0; i < _tables.size(); i++)
- {
- Node* cur = _tables[i];
- while (cur)
- {
- Node* next = cur->_next;
- //头插到新表
- size_t hashi = hs(kot(cur->_data)) % newtables.size();
- newtables[hashi] = cur;
- cur = next;
- }
- _tables[i] = nullptr;
- }
- _tables.swap(newtables);
- }
- size_t hashi = hs(kot(data)) % _tables.size();
- Node* newnode = new Node(data);
-
-
- //头插
- newnode->_next = _tables[hashi];
- _tables[hashi] = newnode;
- ++_n;
- return true;
- }
-
- //查找
- Node* Find(const K& key)
- {
- Hash hs;
- Keyoft kot;
- size_t hashi = hs(key) % _tables.size();
- Node* prev = nullptr;
- Node* cur = _tables[hashi];
- while (cur)
- {
- if (kot(cur->_data) == key)
- return cur;
- cur = cur->_next;
- }
- return nullptr;
- }
-
- Node* Erase(const K& key)
- {
- Hash hs;
- Keyoft kot;
- size_t hashi = hs(key) % _tables.size();
- Node* prev = nullptr;
- Node* cur = _tables[hashi];
- while (cur)
- {
- if (kot(cur->_data) == key)
- {
- if (prev == nullptr)
- {
- _tables[hashi] = cur->next;
- }
- else
- {
- prev->_next = cur->_next;
- }
-
- }
- prev = cur;
- cur = cur->_next;
- }
- return false;
- }
- private:
- vector<Node*> _tables;//指针数组
- size_t _n;
- };
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。