文章目录
unordered_map与unordered_set
功能:
功能基本一样
1 2 3
| 1. unorder_xxx遍历不按照key进行排序 ,命名体现了 2. unorder_xxx只有单向迭代器,没有提供反向迭代器 3. unorder_xxx综合效率略胜map和set
|
unordered对于无序的数据效率很高
set底层使用对于顺序插入的数据效率就会很高
demo.cc
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
| void test_set() {
unordered_set<int> us; us.insert(1); us.insert(3); us.insert(4); us.insert(1); us.insert(7); us.insert(6); us.insert(2); auto it=us.begin(); while(it!=us.end()) { cout<<*it<<" "; it++; } cout<<endl;
unordered_multiset<int> s; s.insert(12); s.insert(12); s.insert(12); auto dt=us.begin();
while(dt!=s.end()) { cout<<*dt<<" "; dt++; }
}
|
哈希
哈希本质
哈希/散列
本质上就是映射,找到一个值进行映射,把数据映射到对应的地方
使用示例
计数排序:
1.统计每个数字出现次数,范围很集中,可以使用,但是对于随机的一堆整数,就按照范围来开空间,很分散,最好不要这样,
哈希函数
除留余数法
10 122 31 400
%10把对应的数放到它余数对应的位置
开10个空间,分配到不同的地方
哈希冲突:
不同的数用哈希放到了同一个地方,不能保证每个值都开辟一个空间
但是我想要映射到一个相对固定的地方去
我们最常用的方法就是将
如何解决哈希冲突
- 闭散列
闭散列:开放定址法,当发生hash冲突的时候,如果哈希表未被装满,说明在哈希表中必然还有空的位置,那么就把key存放到下一个“空位置”中去
* 线性探测
从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止
1 2
| * 二次探测 >我们下一次探测到其平方的位置上,这样就不会让数据太集中
|
- 开散列/哈希桶/拉链法
6 26 36 46,
把尾数为6的都挂起来,放到同一个桶里面,这样就不会出现争抢位置,现在我们出现的争抢就内部解决,不会互相影响了,从根源上更好的去管理这个东西
表长度100
控制负载因子,能够极大的控制住效率–负载因子到了就扩容,
但一个桶的长度超过一定的值之后,就把他转化成一个红黑树,这样效率就很高了
1 2 3 4 5 6 7 8 9
| struct Date { forward_list<T> _list; set<T> _list; size_t len }; len 大于一定值的时候,就把forward_list 里面的数据插入到set里面,再把单链表里面的数据给删除掉
|
极端场景
- 存50个值,40个值冲突,挂在同一个桶上
- 存储了10000个值,平均每个桶的长度100,阶段场景山有些桶可能有上千个值
哈希函数
- 除留余数法:我们将每个数和其对应vector长度进行取余,当达到负载因子就要进行重新扩容,重新映射
- 平方取中法
假如关键字1234,就把它平方=1522356,取中间3位,223,
如果它不够3位,就继续对他进行平方,直到取出3位位置,也存在哈希冲突
不常用
闭散列
使用线性探测;冲突的时候,就往后进行探测,直到到达空位置,
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
| enum Status { EXISTS, EMPTY, DELETE };
template <class K, class V>
struct HashData { pair<K, V> _kv; Status _status = EMPTY; };
template <class K> struct Hash { size_t operator()(const K &key) { return key; } };
template <>
struct Hash<string> { size_t operator()(const string &s) { size_t val = 0; for (auto e : s) { val *= 131; val += e; } return val; } };
template <class K, class V, class HashFunc = Hash<K>>
class HashTable { private: vector<HashData<K, V>> _table; size_t _n = 0; public:
HashData<K, V> *Find(const K &key) { if (_table.size() == 0) { return nullptr; } HashFunc hc; size_t start = hc(key) % _table.size(); size_t i = 0; size_t index = start;
while (_table[index]._status != EMPTY) { if (_table[index]._kv.first == key && _table[index]._status == EXISTS) { return &_table[index]; } i++; index = start + i * i; index %= _table.size(); }
return nullptr; }
bool Erase(const K &key) { HashData<K, V> *ret = Find(key); if (ret == nullptr) { return false; } else { ret->_status = DELETE; _n--; return true; } }
bool Insert(const pair<K, V>& kv) {
HashData<K, V> *ret = Find(kv.first); if (ret != nullptr) { return false; }
if (_table.size() == 0 || _n * 10 / _table.size() >= 7) { size_t newsize = _table.size() == 0 ? 10 : _table.size() * 2;
HashTable<K, V, HashFunc> newHT; newHT._table.resize(newsize); for (size_t i = 0; i < _table.size(); i++) { if (_table[i]._status == EXISTS) { newHT.Insert(_table[i]._kv); } } _table.swap(newHT._table); } HashFunc hc; size_t start = hc(kv.first) % _table.size(); size_t i = 0; size_t index = start;
while (_table[index]._status == EXISTS) { i++; index = start + i * i; index %= _table.size(); } _table[index]._kv = kv; _table[index]._status = EXISTS; _n++;
return true; } };
|
散列表(哈希桶)
将vector里面的数据结构换成单链表
把冲突的数据都串在一起
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
| template <class K, class V>
struct HashNode { pair<K, V> _kv; HashNode<K, V> *_next; HashNode(const pair<K, V> &kv) : _kv(kv), _next(nullptr) { } };
template <class K> struct Hash { size_t operator()(const K &key) { return key; } };
template <class K, class V, class HashFunc = Hash<K>> class HashTable { typedef HashNode<K, V> Node;
private: vector<Node *> _table; size_t _n = 0; public: Node *Find(const K &key) { if (_table.empty()) { return nullptr; } HashFunc hc; size_t index = hc(key) % _table.size(); if (_table[index] == nullptr) { return nullptr; } else { Node *cur = _table[index]; while (cur) { if (cur->_kv.first == key) return cur; cur = cur->_next; } return nullptr; } } bool Erase(const K &key) { if (_table.empty()) { return false; } HashFunc hc; size_t index = hc(key) % _table.size(); Node *cur = _table[index]; Node *prev = nullptr; while (cur) { if (cur->_kv.first == 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; } bool Insert(const pair<K, V> &kv) {
Node *ret = Find(kv.first); if (ret) { return false; }
HashFunc hc;
if (_n == _table.size()) { size_t newcp = _table.size() == 0 ? 10 : _table.size() * 2; vector<Node *> newTable; newTable.resize(newcp); for (size_t i = 0; i < _table.size(); i++) { if (_table[i]) { Node *cur = _table[i]; while (cur) { Node *next = cur->_next; size_t index = hc(cur->_kv.first) % newTable.size(); cur->_next = newTable[index]; newTable[index] = cur; cur = next; } } _table[i] = nullptr; } _table.swap(newTable); } size_t index = hc(kv.first) % _table.size(); Node *newnode = new Node(kv); newnode->_next = _table[index]; _table[index] = newnode;
_table[index] = newnode; _n++; return true; } };
|