哈希
1.unordered系列关联式容器
1.1unordered_set
int main()
{
unordered_set<int> s;
//插入操作
s.insert(1);
s.insert(4);
s.insert(2);
s.insert(5);
//删除值为1的元素
s.erase(1);
//有效元素个数
s.size();
//查找值为4的元素
unordered_set<int>::iterator ret = s.find(4);
cout << *ret << endl;
//清空集合
s.clear();
//判空操作
s.empty();
unordered_set<int> s1{
1,2,3,4,5,6 };
//正向迭代器
unordered_set<int>::iterator it = s1.begin();
while (it != s1.end())
{
cout << *it << endl;
it++;
}
return 0;
}
1.2unordered_map
int main()
{
unordered_map<int, int> m;
//自己显示定义pair插入
m.insert(pair<int, int>(1, 12));
m.insert(pair<int, int>(2, 12));
//使用make_pair函数插入
m.insert(make_pair(3, 15));
m.insert(make_pair(4, 102));
//删除key值为1的元素
m.erase(1);
//有效元素个数
m.size();
//查找key值为4的元素
unordered_map<int, int>::iterator ret = m.find(4);
cout << ret->first << ":" << ret->second << endl;
//清空集合
m.clear();
//判空操作
m.empty();
unordered_map<int, int> m1;
m1.insert(make_pair(1, 12));
m1.insert(make_pair(2, 12));
m1.insert(make_pair(3, 15));
m1.insert(make_pair(4, 102));
//正向迭代器
unordered_map<int, int>::iterator it = m1.begin();
while (it != m1.end())
{
cout << it->first << ":" << it->second << endl;
it++;
}
cout << endl;
return 0;
}
2.底层结构
unordered系列的关联式容器之所以效率比较高,是因为其底层使用了哈希结构。
2.1哈希概念
可以不经过任何比较,一次直接从表中得到要搜索的元素。构造出一个结构,通过某种函数(hash func)使元素的储存位置与它的关键码直接能够建立映射的关系,那么在查找时通过该函数可以快速的找到。
插入元素
根据带插入元素的关键字,以此函数计算出该元素的存储位置并按此位置进行存放。
搜索元素
对元素的关键字进行同样的计算,在结构中按此位置取出元素比较,关键码相同则搜索成功。
2.2哈希冲突
对于两个数据元素的关键字k1和k2(k1!=k2),但是有Hash(k1)==Hash(k2)。即不同关键字通过相同哈希函数计算出相同的哈希地址,这种现象被称为哈希冲突。
2.3哈希函数
引起哈希冲突的一个原因可能是哈希函数设计不够合理,哈希函数的设计原则:
a.哈希函数的定义域必须包括需要存储的全部关键码,而如果散列表允许有m个地址时,其值域必须在0到m-1之间。
b.哈希函数计算出来的地址能均匀分布在整个空间中。
c.哈希函数应该比较简单。
常见的哈希函数
1.直接定制法
取关键字的某个线性函数为散列地址:hash(key)=A*key+B。
2.除留余数法
设散列表中允许的地址数为m,取一个不大于m但是接近或者等于m的质数n作为除数,按照哈希函数:hash(key)=key%n。
3.平方取中法 4.折叠法。 5.随机数法。 6.数学分析法。
哈希函数设计的越精妙,产生哈希冲突的可能性越低,但是无法避免哈希冲突。
2.4哈希冲突解决
解决哈希冲突常见的两种方法是:闭散列和开散列。
2.4.1闭散列
闭散列也叫开放定址法,当发生哈希冲突时,如果哈希表未被装满,说明哈希表中还有空位置,那么可以把key存放到冲突位置中的下一个位置中去。找寻下一个位置的方法有:
1.线性探测
从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止。
插入:通过哈希函数获取等待插入元素在哈希表中的位置。如果该位置没有元素则直接插入,有使用线性探测找到下一个位置插入新元素。
删除:采用闭散列处理哈希冲突时,不能随便物理删除哈希表中已有的元素,若直接删除元素会影响其他元素的搜索,比如删除9会影响2的查找,因此线性探测采用标记的伪删除法来删除元素。
//EMPTY此位为空,EXITS此位已有元素,DELETE此位元素已删除