|
函数声明
|
功能介绍
|
|
unordered_map
|
构造不同格式的unordered_map对象
|
|
函数声明
|
功能介绍
|
|
bool empty() const
|
检测unordered_map是否为空
|
|
size_t size() const
|
获取unordered_map的有效元素个数
|
|
函数声明
|
功能介绍
|
|
begin
|
返回unordered_map第一个元素的迭代器
|
|
end
|
返回unordered_map最后一个元素下一个位置的迭代器
|
|
cbegin
|
返回unordered_map第一个元素的const迭代器
|
|
cend
|
返回unordered_map最后一个元素下一个位置的const迭代器
|
|
函数声明
|
功能介绍
|
|
operator[]
|
返回与key对应的value,没有一个默认值
|
|
函数声明
|
功能介绍
|
|
iterator fifind(const K& key)
|
返回key在哈希桶中的位置
|
|
size_t count(const K& key)
|
返回哈希桶中关键码为key的键值对的个数
|
|
函数声明
|
功能介绍
|
|
insert
|
向容器中插入键值对
|
|
erase
|
删除容器中的键值对
|
|
void clear()
|
清空容器中有效元素个数
|
|
void swap(unordered_map&)
|
交换两个容器中的元素
|
|
函数声明
|
功能介绍
|
|
size_t bucket_count()const
|
返回哈希桶中桶的总个数
|
|
size_t bucket_size(size_t n)const
|
返回n号桶中有效元素的总个数
|
|
size_t bucket(const K& key)
|
返回元素key所在的桶号
|
1.重复n次的元素
- class Solution {
- public:
- int repeatedNTimes(vector<int>& A) {
- size_t N = A.size()/2;
- // 用unordered_map统计每个元素出现的次数
- unordered_map<int, int> m;
- for(auto e : A)
- m[e]++;
-
- // 找出出现次数为N的元素
- for(auto& e : m)
- {
- if(e.second == N)
- return e.first;
- }
- }
- };
- class Solution
- {
- public:
- vector<int> intersection(vector<int>& nums1, vector<int>& nums2)
- {
-
- // 用unordered_set对nums1中的元素去重
- unordered_set<int> s1;
- for (auto e : nums1)
- s1.insert(e);
- // 用unordered_set对nums2中的元素去重
- unordered_set<int> s2;
- for (auto e : nums2)
- s2.insert(e);
- // 遍历s1,如果s1中某个元素在s2中出现过,即为交集
- vector<int> vRet;
- for (auto e : s1)
- {
- if (s2.find(e) != s2.end())
- vRet.push_back(e);
- }
- return vRet;
- }
- };
根据待插入元素的关键码,以此函数计算出该元素的存储位置并按此位置进行存放
用该方法进行搜索不必进行多次关键码的比较,因此搜索的速度比较快。
哈希函数设计原则:


- // 哈希表每个空间给个标记
- // EMPTY此位置空, EXIST此位置已经有元素, DELETE元素已经删除
- enum State{EMPTY, EXIST, DELETE};
- // 注意:假如实现的哈希表中元素唯一,即key相同的元素不再进行插入
- // 为了实现简单,此哈希表中我们将比较直接与元素绑定在一起
- template<class K, class V>
- class HashTable
- {
- struct Elem
- {
- pair
_val; - State _state;
- };
-
- public:
- HashTable(size_t capacity = 3)
- : _ht(capacity), _size(0)
- {
- for (size_t i = 0; i < capacity; ++i)
- _ht[i]._state = EMPTY;
- }
-
- bool Insert(const pair
& val) - {
- // 检测哈希表底层空间是否充足
- // _CheckCapacity();
- size_t hashAddr = HashFunc(key);
- // size_t startAddr = hashAddr;
- while (_ht[hashAddr]._state != EMPTY)
- {
- if (_ht[hashAddr]._state == EXIST && _ht[hashAddr]._val.first
- == key)
- return false;
-
- hashAddr++;
- if (hashAddr == _ht.capacity())
- hashAddr = 0;
- /*
- // 转一圈也没有找到,注意:动态哈希表,该种情况可以不用考虑,哈希表中元
- 素个数到达一定的数量,哈希冲突概率会增大,需要扩容来降低哈希冲突,因此哈希表中元素是
- 不会存满的
- if(hashAddr == startAddr)
- return false;
- */
- }
-
- // 插入元素
- _ht[hashAddr]._state = EXIST;
- _ht[hashAddr]._val = val;
- _size++;
- return true;
- }
- int Find(const K& key)
- {
- size_t hashAddr = HashFunc(key);
- while (_ht[hashAddr]._state != EMPTY)
- {
- if (_ht[hashAddr]._state == EXIST && _ht[hashAddr]._val.first
- == key)
- return hashAddr;
-
- hashAddr++;
- }
- return hashAddr;
- }
- bool Erase(const K & key)
- {
- int index = Find(key);
- if (-1 != index)
- {
- _ht[index]._state = DELETE;
- _size++;
- return true;
- }
- return false;
- }
- size_t Size()const;
- bool Empty() const;
- void Swap(HashTable
&ht) ; - private:
- size_t HashFunc(const K & key)
- {
- return key % _ht.capacity();
- }
- private:
- vector
_ht; - size_t _size;
- };
- void CheckCapacity()
- {
- if (_size * 10 / _ht.capacity() >= 7)
- {
- HashTable
newHt(GetNextPrime(ht.capacity)) ; - for (size_t i = 0; i < _ht.capacity(); ++i)
- {
- if (_ht[i]._state == EXIST)
- newHt.Insert(_ht[i]._val);
- }
-
- Swap(newHt);
- }
- }
1. 开散列概念


从上图可以看出,开散列中每个桶中放的都是发生哈希冲突的元素。
2. 开散列实现
- template<class V>
- struct HashBucketNode
- {
- HashBucketNode(const V& data)
- : _pNext(nullptr), _data(data)
- {}
- HashBucketNode
* _pNext; - V _data;
- };
- // 所实现的哈希桶中key是唯一的
- template<class V>
- class HashBucket
- {
- typedef HashBucketNode
Node; - typedef Node* PNode;
- public:
- HashBucket(size_t capacity = 3) : _size(0)
- {
- _ht.resize(GetNextPrime(capacity), nullptr);
- }
-
- // 哈希桶中的元素不能重复
- PNode* Insert(const V& data)
- {
- // 确认是否需要扩容。。。
- // _CheckCapacity();
-
- // 1. 计算元素所在的桶号
- size_t bucketNo = HashFunc(data);
-
- // 2. 检测该元素是否在桶中
- PNode pCur = _ht[bucketNo];
- while (pCur)
- {
- if (pCur->_data == data)
- return pCur;
-
- pCur = pCur->_pNext;
- }
-
- // 3. 插入新元素
- pCur = new Node(data);
- pCur->_pNext = _ht[bucketNo];
- _ht[bucketNo] = pCur;
- _size++;
- return pCur;
- }
-
- // 删除哈希桶中为data的元素(data不会重复),返回删除元素的下一个节点
- PNode* Erase(const V& data)
- {
- size_t bucketNo = HashFunc(data);
- PNode pCur = _ht[bucketNo];
- PNode pPrev = nullptr, pRet = nullptr;
-
- while (pCur)
- {
- if (pCur->_data == data)
- {
- if (pCur == _ht[bucketNo])
- _ht[bucketNo] = pCur->_pNext;
- else
- pPrev->_pNext = pCur->_pNext;
-
- pRet = pCur->_pNext;
- delete pCur;
- _size--;
- return pRet;
- }
- }
-
- return nullptr;
- }
-
- PNode* Find(const V& data);
- size_t Size()const;
- bool Empty()const;
- void Clear();
- bool BucketCount()const;
- void Swap(HashBucket
& ht; - ~HashBucket();
- private:
- size_t HashFunc(const V& data)
- {
- return data % _ht.capacity();
- }
- private:
- vector
_ht; - size_t _size; // 哈希表中有效元素的个数
- };
- void _CheckCapacity()
- {
- size_t bucketCount = BucketCount();
- if (_size == bucketCount)
- {
- HashBucket
newHt(bucketCount) ; - for (size_t bucketIdx = 0; bucketIdx < bucketCount; ++bucketIdx)
- {
- PNode pCur = _ht[bucketIdx];
- while (pCur)
- {
- // 将该节点从原哈希表中拆出来
- _ht[bucketIdx] = pCur->_pNext;
-
- // 将该节点插入到新哈希表中
- size_t bucketNo = newHt.HashFunc(pCur->_data);
- pCur->_pNext = newHt._ht[bucketNo];
- newHt._ht[bucketNo] = pCur;
- pCur = _ht[bucketIdx];
- }
- }
-
- newHt._size = _size;
- this->Swap(newHt);
- }
- }
- // 哈希函数采用处理余数法,被模的key必须要为整形才可以处理,此处提供将key转化为整形的方法
- // 整形数据不需要转化
- template<class T>
- class DefHashF
- {
- public:
- size_t operator()(const T& val)
- {
- return val;
- }
- };
- // key为字符串类型,需要将其转化为整形
- class Str2Int
- {
- public:
- size_t operator()(const string& s)
- {
- const char* str = s.c_str();
- unsigned int seed = 131; // 31 131 1313 13131 131313
- unsigned int hash = 0;
- while (*str)
- {
- hash = hash * seed + (*str++);
- }
-
- return (hash & 0x7FFFFFFF);
- }
- };
- // 为了实现简单,此哈希表中我们将比较直接与元素绑定在一起
- template<class V, class HF>
- class HashBucket
- {
- // ……
- private:
- size_t HashFunc(const V& data)
- {
- return HF()(data.first) % _ht.capacity();
- }
- };
- size_t GetNextPrime(size_t prime)
- {
- 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];
- }
- // K:关键码类型
- // V: 不同容器V的类型不同,如果是unordered_map,V代表一个键值对,如果是unordered_set, V 为 K
- // HF: 哈希函数仿函数对象类型,哈希函数使用除留余数法,需要将Key转换为整形数字才能取模
- template<class K, class V, class KeyOfValue, class HF = DefHashF
> - class HashBucket;
- // 为了实现简单,在哈希桶的迭代器类中需要用到hashBucket本身,
- template<class K, class V, class KeyOfValue, class HF>
- class HashBucket;
- // 注意:因为哈希桶在底层是单链表结构,所以哈希桶的迭代器不需要--操作
- template <class K, class V, class KeyOfValue, class HF>
- struct HBIterator
- {
- typedef HashBucket
HashBucket; - typedef HashBucketNode
* PNode; - typedef HBIterator
Self; - HBIterator(PNode pNode = nullptr, HashBucket* pHt = nullptr);
- Self& operator++()
- {
- // 当前迭代器所指节点后还有节点时直接取其下一个节点
- if (_pNode->_pNext)
- _pNode = _pNode->_pNext;
- else
- {
- // 找下一个不空的桶,返回该桶中第一个节点
- size_t bucketNo = _pHt->HashFunc(KeyOfValue()(_pNode -> _data)) + 1;
- for (; bucketNo < _pHt->BucketCount(); ++bucketNo)
- {
- if (_pNode = _pHt->_ht[bucketNo])
- break;
- }
- }
- return *this;
- }
- Self operator++(int);
- V& operator*();
- V* operator->();
- bool operator==(const Self& it) const;
- bool operator!=(const Self& it) const;
- PNode _pNode; // 当前迭代器关联的节点
- HashBucket* _pHt; // 哈希桶--主要是为了找下一个空桶时候方便
- };
- template<class K, class V, class KeyOfValue, class HF = DefHashF
> - class HashBucket
- {
- friend HBIterator
; - // ......
- public:
- typedef HBIterator
Iterator; - //
- // ...
- // 迭代器
- Iterator Begin()
- {
- size_t bucketNo = 0;
- for (; bucketNo < _ht.capacity(); ++bucketNo)
- {
- if (_ht[bucketNo])
- break;
- }
- if (bucketNo < _ht.capacity())
- return Iterator(_ht[bucketNo], this);
- else
- return Iterator(nullptr, this);
- }
- Iterator End()
- {
- return Iterator(nullptr, this);
- }
- Iterator Find(const K& key);
- Iterator Insert(const V& data);
- Iterator Erase(const K& key);
-
- // 为key的元素在桶中的个数
- size_t Count(const K& key)
- {
- if (Find(key) != End())
- return 1;
-
- return 0;
- }
-
- size_t BucketCount()const
- {
- return _ht.capacity();
- }
- size_t BucketSize(size_t bucketNo)
- {
- size_t count = 0;
- PNode pCur = _ht[bucketNo];
- while (pCur)
- {
- count++;
- pCur = pCur->_pNext;
- }
-
- return count;
- }
-
- // ......
- };
- // unordered_map中存储的是pair
的键值对,K为key的类型,V为value的类型,HF哈希函数类型 - // unordered_map在实现时,只需将hashbucket中的接口重新封装即可
- template<class K, class V, class HF = DefHashF
> - class unordered_map
- {
- typedef pair
ValueType; - typedef HashBucket
HT; - // 通过key获取value的操作
- struct KeyOfValue
- {
- const K& operator()(const ValueType& data)
- {
- return data.first;
- }
- };
- public:
- typename typedef HT::Iterator iterator;
- public:
- unordered_map() : _ht()
- {}
-
- iterator begin()
- {
- return _ht.Begin();
- }
- iterator end()
- {
- return _ht.End();
- }
-
- // capacity
- size_t size()const
- {
- return _ht.Size();
- }
- bool empty()const
- {
- return _ht.Empty();
- }
- ///
- // Acess
- V& operator[](const K& key)
- {
- return (*(_ht.InsertUnique(ValueType(key, V())).first)).second;
- }
- const V& operator[](const K& key)const;
- //
- // lookup
- iterator find(const K& key)
- {
- return _ht.Find(key);
- }
- size_t count(const K& key)
- {
- return _ht.Count(key);
- }
- /
- // modify
- pair
bool > insert(const ValueType& valye) - {
- return _ht.Insert(valye);
- }
- iterator erase(iterator position)
- {
- return _ht.Erase(position);
- }
-
- // bucket
- size_t bucket_count()
- {
- return _ht.BucketCount();
- }
- size_t bucket_size(const K& key)
- {
- return _ht.BucketSize(key);
- }
- private:
- HT _ht;
- };
- class bitset
- {
- public:
- bitset(size_t bitCount)
- : _bit((bitCount >> 5) + 1), _bitCount(bitCount)
- {}
- // 将which比特位置1
- void set(size_t which)
- {
- if (which > _bitCount)
- return;
- size_t index = (which >> 5);
- size_t pos = which % 32;
- _bit[index] |= (1 << pos);
- }
- // 将which比特位置0
- void reset(size_t which)
- {
- if (which > _bitCount)
- return;
- size_t index = (which >> 5);
- size_t pos = which % 32;
- _bit[index] &= ~(1 << pos);
- }
- // 检测位图中which是否为1
- bool test(size_t which)
- {
- if (which > _bitCount)
- return false;
- size_t index = (which >> 5);
- size_t pos = which % 32;
- return _bit[index] & (1 << pos);
- }
- // 获取位图中比特位的总个数
- size_t size()const { return _bitCount; }
- // 位图中比特为1的个数
- size_t Count()const
- {
- int bitCnttable[256] = {
- 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2,
- 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3,
- 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3,
- 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4,
- 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5,
- 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4,
- 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5,
- 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5,
- 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3,
- 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6,
- 6, 7, 6, 7, 7, 8 };
-
- size_t size = _bit.size();
- size_t count = 0;
- for (size_t i = 0; i < size; ++i)
- {
- int value = _bit[i];
- int j = 0;
- while (j < sizeof(_bit[0]))
- {
- unsigned char c = value;
- count += bitCntTable[c];
- ++j;
- value >>= 8;
- }
- }
- return count;
- }
- private:
- vector<int> _bit;
- size_t _bitCount;
- };


向布隆过滤器中插入:"baidu"


- struct BKDRHash
- {
- size_t operator()(const string& s)
- {
- // BKDR
- size_t value = 0;
- for (auto ch : s)
- {
- value *= 31;
- value += ch;
- }
- return value;
- }
- };
-
-
- struct APHash
- {
- size_t operator()(const string& s)
- {
- size_t hash = 0;
- for (long i = 0; i < s.size(); i++)
- {
- if ((i & 1) == 0)
- {
- hash ^= ((hash << 7) ^ s[i] ^ (hash >> 3));
- }
- else
- {
- hash ^= (~((hash << 11) ^ s[i] ^ (hash >> 5)));
- }
- }
- return hash;
- }
- };
-
-
- struct DJBHash
- {
- size_t operator()(const string& s)
- {
- size_t hash = 5381;
- for (auto ch : s)
- {
- hash += (hash << 5) + ch;
- }
- return hash;
- }
- };
-
-
- template<size_t N,
- size_t X = 5,
- class K = string,
- class HashFunc1 = BKDRHash,
- class HashFunc2 = APHash,
- class HashFunc3 = DJBHash>
- class BloomFilter
- {
- public:
- void Set(const K& key)
- {
- size_t len = X * N;
- size_t index1 = HashFunc1()(key) % len;
- size_t index2 = HashFunc2()(key) % len;
- size_t index3 = HashFunc3()(key) % len;
- /* cout << index1 << endl;
- cout << index2 << endl;
- cout << index3 << endl<
-
- _bs.set(index1);
- _bs.set(index2);
- _bs.set(index3);
- }
-
- bool Test(const K& key)
- {
- size_t len = X * N;
- size_t index1 = HashFunc1()(key) % len;
- if (_bs.test(index1) == false)
- return false;
-
- size_t index2 = HashFunc2()(key) % len;
- if (_bs.test(index2) == false)
- return false;
-
- size_t index3 = HashFunc3()(key) % len;
- if (_bs.test(index3) == false)
- return false;
- return true; // 存在误判的
- }
-
- // 不支持删除,删除可能会影响其他值。
- void Reset(const K& key);
- private:
- bitset
_bs; - };