• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
jacklee404
Never Stop!
博客园    首页    新随笔    联系   管理    订阅  订阅
哈希表学习

哈希表学习

存储结构

模拟散列表

开放寻址法

#include <iostream>
#include <cstring>

using i64 = long long;

const int N = 2000003, null = 0x3f3f3f3f;

int h[N];

int find(int x) {
	int k = (x % N + N) % N;

	while(h[k] != null && h[k] != x) {
		k ++;
		if(k == N) k = 0;
	}

	return k;
}

int main() {
	// for(int i = 2e6; ; i ++) {
	// 	bool ok = true;
	// 	for(int j = 2; j <= i / j; j ++) {
	// 		if(i % j == 0) {
	// 			ok = false;
	// 			break;
	// 		}
	// 	}
	// 	if(ok) {
	// 		std::cout << i << "\n";
	// 		break;
	// 	}
	// }

	memset(h, 0x3f, sizeof h);

	int n;

	std::cin >> n;


	while(n --) {
		std::string t;
		int x;

		std::cin >> t >> x;
		int k = find(x);

		if(t == "I") {
			h[k] = x;
		} else {
			std::cout << ((h[k] != null)?"Yes":"No") << "\n";
		}
	}
}

拉链法

​ 可以通过一个图来直观的理解。

#include <iostream>
#include <cstring>

using i64 = long long;

const int N = 1e5 + 10, M = 100003;

int mod;

int h[N], e[N], ne[N], idx;

void insert(int x) {
	int n = (x % M + M) % M;
	ne[idx] = h[n], h[n] = idx, e[idx ++] = x;
}

bool find(int x) {
	int n = (x % M + M) % M;
	for(int i = h[n]; ~i; i = ne[i]) {
		if(e[i] == x) return true;
	}
	return false;
}

int main() {
	memset(h, -1, sizeof h);
	
// 	for(int i = 1e5; ; i ++) {
// 	    bool ok = true;
// 	    for(int j = 2; j <= i / j; j ++) {
// 	        if(i % j == 0) {
// 	            ok = false;
// 	            break;
// 	        }
// 	    }
// 	    if(ok) {
// 	        std::cout << i << "\n";
// 	        break;
// 	    }
// 	}

	int n;

	std::cin >> n;


	while(n --) {
		std::string t;
		int x;

		std::cin >> t >> x;

		if(t == "I") {
			insert(x);
		} else {
			std::cout << (find(x)?"Yes":"No") << "\n";
		}
	}
}

字符串哈希方式

前缀哈希法

​ 思路:将字符串映射到\(p\)进制数(不能将某个字母映射到\(0\)), 另外一般在\(p = 131 或 13331, Q = 2^{64}\)时,能将冲

突更好的减少(\(99.99\% 不存在冲突\))。

\[A \space B \space C \space D \\ → (1 \space 2 \space 3 \space 4)_p \\ hash[ABCD] = (1 \times p^3 + 2 \times p^2 + 3 \times p^3 + 4 \times p^4) \bmod Q \\ hash[BC] = hash[ABC] - hash[A] \times p^2 \\ → hash[R] - hash[L] \times p^{R - L + 1} \]

​ 对于一个字符串的hash值,我们可以通过计算前缀的hash值,来计算区间的hash值。这里取模有一个技巧,如果我们对\(2^{64}\)取模,相当于unsigned long long的溢出,即可以用unsingned long long来代替取模。

861- 字符串哈希

#include <iostream>

using i64 = long long;
using ui64 = unsigned long long;

const int N = 1e5 + 10, P = 131;

int n, m;
char str[N];
ui64 h[N], p[N];

ui64 get(int l, int r) {
	return h[r] - h[l - 1] * p[r - l + 1];
}

int main() {
	std::cin >> n >> m >> (str + 1);

	p[0] = 1;

	for(int i = 1; i <= n; i ++) {
		p[i] = p[i - 1] * P;
		h[i] = h[i - 1] * P + str[i];
	}

	while(m --) {
		int l1, r1, l2, r2;

		std::cin >> l1 >> r1 >> l2 >> r2;

		std::cout << (get(l1, r1) == get(l2, r2)?"Yes":"No") << "\n";
	}
}
posted on 2023-03-18 11:02  Jack404  阅读(14)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3