6.2 哈希冲突 - Hello 算法 (hello-algo.com)
哈希表 hash_table
#include <unordered_map>
unordered_map<string,int> mp;
mp["111"] = 11;
mp["11"] = 14;
mp["1"] = 13;
mp["121"] = 12;
mp.erase("121");//delete
// 遍历哈希表
//智能指针
for(auto i:mp){
cout << mp.first<<" "<<mp.second<<endl;
}
//迭代器
for(auto i=mp.begin();i!=mp.end();i++){
cout << i->first<<' '<< mp->second << endl;
}
哈希表实现将一个较大的哈希函数映射到较小的数据空间 通过哈希函数将值存到相应的索引位置
一般简单的哈希函数可以为
index = hash(key) % capacity
查找删除键值时通过哈希函数直接访问目标值
使用数组简单 实现hash表
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
struct Pair
{
int key;
string val;
Pair(int key,string val){
this->key = key;
this->val = val;
}
};
/// 基于数组实现的hash表
class ArrayHashMap
{
private:
vector<Pair*> buckets; // 水桶
const int HashKey = 100;
public:
ArrayHashMap(/* args */);
~ArrayHashMap();
int hashFunc(int key);
string get(int key);
void put(int key,string val);
void erase(int key);
vector<int> getAllVal();
vector<string> getAllKey();
void printHashTable();
};
ArrayHashMap::ArrayHashMap(/* args */)
{
buckets = vector<Pair*>(100);
}
ArrayHashMap::~ArrayHashMap()
{
for(const auto &bucket:buckets){
delete bucket;
}
buckets.clear();
}
int ArrayHashMap::hashFunc(int key)
{
return key % HashKey;
}
string ArrayHashMap::get(int key)
{
Pair *par = buckets[hashFunc(key)];
if(par == nullptr)return "";
return par->val;
}
void ArrayHashMap::put(int key, string val)
{
Pair *pir = new Pair(key,val);
buckets[hashFunc(key)] = pir;
}
void ArrayHashMap::erase(int key)
{
int k = hashFunc(key);
delete buckets[k];
buckets[k] = nullptr;
}
vector<int> ArrayHashMap::getAllVal()
{
vector<int> res;
for(auto c:buckets){
if(c!=nullptr)
res.push_back(c->key);
}
return res;
}
vector<string> ArrayHashMap::getAllKey()
{
vector<string> res;
for(auto c:buckets){
if(c!=nullptr)
res.push_back(c->val);
}
return res;
}
void ArrayHashMap::printHashTable()
{
for(auto c:buckets){
cout << c->key << " " << c->val << endl;
}
}
int main(){
ArrayHashMap c;
c.put(123,"123");
c.put(12333,"12333");
c.put(123333,"123333");
c.put(123444,"123444");
// c.printHashTable();
cout << c.get(1233) << endl; // hash冲突
return 0;
}
冲突处理
存储哈希值的方法 开放寻址法 拉链法
开放寻址法//一个数组
当发生冲突时,通过一定的方法在哈希表中寻找下一个可用的位置来存储键值对
拉链法 // 链表
每个索引位置都是一个链表用于存储多个键值
当出现冲突时候会以链表的形式连接在一起
一般%的数一般为大于目标范围最大的质数
1.
列表中的每个数字都是质数
2.
每个数字的大小略小于前一个数字的两倍
3.
每个数字都尽可能远离
普通哈希
拉链
const int N = 1e5;
int h[N],e[N],ne[N],idx = 0; // 拉链 h[] = {-1}
// 向哈希表中
void insert(int x){
int k = (x%n+n)%n;
e[idx] = x;
ne[idx] = h[k];
h[k] = idx ++;
}
// 查找是否在hash表中
bool find(int x){
int k = (x%n+n)%n;
for(int i=h[k];~i;i = ){
int b = e[i];
if(e[i] == x)return true;
}
return false;
}
开放寻址法
int h[N*3];
// 有就返回x的下表
//没有返回插入hash的位置
int find(int x){
int h = (x%n+n)%n;
while(h[t]!=null&&h[t]!=x){ //null为自己设置的最大值
t ++;
if(t == n)t = 0;
}
return t;
}
//插入
h[find(x)] = x;
字符串hash
将字符串看作p进制数(p一般为131 / 13331)冲突概率低
直接使用unsigned long long 存储,溢出就是取模的结果
typedef unsigned long long ULL; // 定义无符号长长整型 ULL
ULL h[N], p[N]; // 哈希数组 h 和权值数组 p
p[0] = 1; // 初始权值为 1
// 计算哈希数组和权值数组
for (int i = 1; i <= n; i++) {
h[i] = h[i - 1] * P + str[i]; // 计算哈希数组
p[i] = p[i - 1] * P; // 计算权值数组,P 进制
}
// 计算子串 str[l ~ r] 的哈希值
ULL get(int l, int r) {
return h[r] - h[l - 1] * p[r - l + 1]; // 返回子串哈希值
}
矩阵hash
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 110;
char g[N][N];
pair<int,int> q[N*N];
double eqs = 1e-5; // 定义误差范围
int n,m;
int top;
double get_dist(pair<int,int> a, pair<int,int> b){
// 计算两点之间的欧氏距离
double dx = a.first - b.first;
double dy = a.second - b.second;
return sqrt(dx*dx + dy*dy);
}
double get_hash(){
// 计算哈希值
double sum = 0;
for (int i = 0; i < top; i++)
for (int j = i + 1; j < top; j++)
sum += get_dist(q[i], q[j]); // 累加两点之间的距离
return sum;
}
char get_id(double key){
// 获取哈希值对应的字符标识
static double hash[30]; // 哈希表,存储哈希值
static int id = 0; // 标识当前哈希表中的位置
for(int i = 0; i < id; i++){
if(fabs(hash[i] - key) < eqs){ // 如果当前哈希值与已有哈希值之差在误差范围内
return i + 'a'; // 返回对应的字符标识
}
}
hash[id++] = key; // 将当前哈希值加入哈希表
return id - 1 + 'a'; // 返回对应的字符标识
}
void dfs(int a, int b){
// 深度优先搜索,标记连通分量
q[top++] = {a, b}; // 将当前点加入队列
g[a][b] = '0'; // 标记当前点已访问
for(int x = a - 1; x <= a + 1; x++){
for(int y = b - 1; y <= b + 1; y++){
if(x == a && y == b) continue;
if(x >= 0 && x < n && y >= 0 && y < m && g[x][y] == '1'){
dfs(x, y); // 继续搜索相邻的未访问点
}
}
}
}
int main(){
cin >> m >> n;
for(int i = 0; i < n; i++){
cin >> g[i];
}
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(g[i][j] == '1'){
top = 0;
dfs(i, j); // 搜索连通分量
char c = get_id(get_hash()); // 获取哈希值对应的字符标识
for(int k = 0; k < top; k++){
g[q[k].first][q[k].second] = c; // 将连通分量内的所有点标记为同一字符
}
}
}
}
for(int i = 0; i < n; i++){
cout << g[i] << endl; // 输出标记后的地图
}
return 0;
}