20.哈希
一.unordered系列关联式容器
unordered_set 和 unordered_map 中序遍历都是无序的
二.unordered_set的介绍
cplusplius文档链接如下:
https://legacy.cplusplus.com/reference/unordered_set/unordered_set/
平时使用不用管
1.接口介绍
只能说,set和unordered_set的使用都是差不多的(90%),但是由于底层的差别(set(红黑树),unordered_set(哈希表)),有一些差别,如下:
从unordered_set没提供的rbegin()和rend()可以知道
2.代码测试
1.接口测试
#include<unordered_set>
#include<unordered_map>
#include<set>
#include<iostream>
#include <time.h>
#include <vector>
using namespace std;void test_set1()
{unordered_set<int> s = { 3,1,6,7,8,2 };unordered_set<int>::iterator it = s.begin();while (it != s.end()){cout << *it << " ";++it;}cout << endl;for (auto e : s){cout << e << " ";}cout << endl;
}
这里验证了,我们的unordered_set插入数据是无序的
2.性能测试
int test_set2()
{const size_t N = 10000000;unordered_set<int> us;set<int> s;vector<int> v;v.reserve(N);srand(time(0));for (size_t i = 0; i < N; ++i){//v.push_back(rand()); // N比较大时,重复值比较多//v.push_back(rand()+i); // 重复值相对少v.push_back(i); // 没有重复,有序}size_t begin1 = clock();for (auto e : v){s.insert(e);}size_t end1 = clock();cout << "set insert:" << end1 - begin1 << endl;size_t begin2 = clock();for (auto e : v){us.insert(e);}size_t end2 = clock();cout << "unordered_set insert:" << end2 - begin2 << endl;int m1 = 0;size_t begin3 = clock();for (auto e : v){auto ret = s.find(e);if (ret != s.end()){++m1;}}size_t end3 = clock();cout << "set find:" << end3 - begin3 << "->" << m1 << endl;int m2 = 0;size_t begin4 = clock();for (auto e : v){auto ret = us.find(e);if (ret != us.end()){++m2;}}size_t end4 = clock();cout << "unorered_set find:" << end4 - begin4 << "->" << m2 << endl;cout << "插入数据个数:" << s.size() << endl;cout << "插入数据个数:" << us.size() << endl << endl;size_t begin5 = clock();for (auto e : v){s.erase(e);}size_t end5 = clock();cout << "set erase:" << end5 - begin5 << endl;size_t begin6 = clock();for (auto e : v){us.erase(e);}size_t end6 = clock();cout << "unordered_set erase:" << end6 - begin6 << endl << endl;return 0;
}
unordered_set有序性能低,set有序性能高
三.unordered_map的介绍
1.接口介绍
2.代码测试
void test_map1()
{unordered_map<string, string> dict;dict.insert({ "left", "左边" });dict["sort"];dict["sort"] = "排序";
}
和map的基础功能是一样的
四.题目
1.
https://leetcode.cn/problems/n-repeated-element-in-size-2n-array/description/
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;}}
};
2.
https://leetcode.cn/problems/intersection-of-two-arrays/description/
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;}
};
3.
https://leetcode.cn/problems/first-unique-character-in-a-string/description/
class Solution {
public:int firstUniqChar(string s) {int count[26]={0};for(auto ch:s){count[ch-'a']++;}for(int i=0;i<s.size();i++){ if(count[s[i]-'a']==1){return i;}}return -1;}
};
五.哈希的概念的讲解
1.闭散列
找位置又有两种方式:
a.线性探测
有没有可能找不到位置(位置被占满了),不会,后面我们会提出负载因子的概念
b.二次探测
c.其他规则
这里不展开讨论
2.开散列
六.哈希的大概实现
#pragma once
#include <vector>enum State
{EXIST,EMPTY,DELETE
};template<class K, class V>
struct HashData
{pair<K, V> _kv;State _state = EMPTY;
};template<class K, class V>
class HashTable
{
private:vector<HashData<K, V>> _tables;
};