首页 > 编程语言 >哈希表和字符串哈希算法

哈希表和字符串哈希算法

时间:2024-09-30 23:24:23浏览次数:3  
标签:std hash int 元素 算法 哈希 字符串 unordered

哈希

哈希表(Hash Table)是一种数据结构,它可以通过一个哈希函数将键(key)映射到存储位置,从而实现高效的数据查找、插入和删除操作。哈希表的特点是能够在常数时间(O(1))内完成查找和更新,前提是哈希冲突处理得当。

哈希表的基本结构

数组:哈希表的底层通常是一个数组,数组中的每个元素称为一个"桶"(bucket),用来存储键值对或单个值。

哈希函数:

哈希函数用于将输入的键(通常是字符串或整数)转换为数组中的索引。例如,hash(key) % array_size 这种简单的方式可以将键转换为数组的有效索引。

处理哈希冲突:

由于哈希函数可能会将不同的键映射到相同的数组位置,这种现象称为哈希冲突。常见的哈希冲突处理方法有两种:

1.链地址法(Separate Chaining):每个桶中存储一个链表,冲突的元素依次存储在链表中。
2.开放地址法(Open Addressing):当发生冲突时,通过一定的探测策略寻找下一个空闲的桶。常见的探测方法包括线性探测、二次探测和双重哈希。

C++标准库中提供了几种支持哈希操作的容器,最常用的就是std::unordered_map和std::unordered_set。它们分别实现了基于哈希表的映射和集合。

1. std::unordered_map

std::unordered_map是C++标准模板库(STL)中用于存储键值对的哈希表实现,它的特点是可以快速查找给定键对应的值。

基本用法:

#include <iostream>
#include <unordered_map>

int main() {
    std::unordered_map<std::string, int> hashMap;
    // 插入键值对
    hashMap["apple"] = 5;
    hashMap["banana"] = 3;
    // 查找元素
    if (hashMap.find("apple") != hashMap.end()) {
        std::cout <<hashMap["apple"] << std::endl;
    }
    // 遍历哈希表
    for (const auto& pair : hashMap) {
        std::cout << pair.first << " : " << pair.second << std::endl;
    }
    return 0;
}

主要方法:
insert(): 插入键值对。
find(): 查找指定键是否存在,返回一个迭代器。
operator[]: 通过键直接访问或插入元素。
erase(): 删除指定键值对。

2. std::unordered_set

std::unordered_set是一个只存储唯一元素的容器,内部使用哈希表进行实现。它不存储键值对,只存储元素本身,且每个元素唯一。

基本用法:

#include <iostream>
#include <unordered_set>

int main() {
    std::unordered_set<int> hashSet;

    // 插入元素
    hashSet.insert(10);
    hashSet.insert(20);

    // 查找元素
    if (hashSet.find(10) != hashSet.end()) {
        std::cout  << std::endl;
    }

    // 遍历集合
    for (const auto& elem : hashSet) {
        std::cout << elem << std::endl;
    }

    return 0;
}

主要方法:
insert(): 插入元素。
find(): 查找指定元素是否存在。
erase(): 删除元素。
count(): 检查元素是否存在,返回1表示存在,0表示不存在。

字符串哈希

我们来判断两个字符串是否相等的时候,如果使用一个一个遍历,时间是可呢会超时的,所以我们采用将字符串变成一个数字,数字之间的比较是非常容易的时间复杂度是O(1)。下面我们来看看如何操作,和字符串哈希的概念。
在这里插入图片描述
如果真的还是发生了冲突我们又该怎么解决呢?
在这里插入图片描述

计算hash_code代码如下:

#include<iostream>
using namespace std;
typedef unsigned long long ULL;

const int X = 13331;

int main()
{
	string s = "abcde";
	ULL hash_code = s[0];
	ULL flag = 1;
	for (int i = 1; i < s.size(); i++)
	{
		//在十进制中我们是1*100+2*10+3*1;所以这里我们一样
		hash_code = hash_code * X + s[i];
	}
	cout << hash_code;
	return 0;
}

字符串哈希代码实现

#include<iostream>
#include<vector>
using namespace std;
typedef unsigned long long ULL;
const int X = 13331;
vector<ULL>h, x;
void BKDR_hash(string s)
{
	h[0] = s[0];
	x[0] = 1;
	for (int i = 1; i < s.size(); i++)
	{
		h[i] = h[i - 1] * X + s[i];
//假如现在是1234,我们要怎样得到他的字串234呢 我们可以使用前缀和
//   1     12     123     1234
//  h[1]  h[2]    h[3]    h[3]
//234 = h[3]-h[0]*10^3
//34  = h[3]-h[2]*10^2
		x[i] = x[i - 1] * X;
	}
}

ULL get_hash(int left, int right)
{
	if (!left)
	{
		return h[right];
	}
	else
	{
		return h[right] - h[left - 1] * x[right - left + 1];
	}
}

int main()
{
	string s1;
	cin >> s1;
	h.resize(s1.size());
	x.resize(s1.size());
	BKDR_hash(s1);
	string s2;
	cin >> s2;
	ULL hash2 = 0;
	for (int i = 0; i < s2.size(); i++)
	{
		hash2 = hash2 * X + s2[i];
	}
	for (int i = 0; i < s1.size(); i++)
	{
		cout << get_hash(i, min(s1.size() - 1, i + s2.size() - 1)) << " ";
	}
	cout << endl;
	cout << hash2;
	return 0;
}
//运行
//abcde
//cd
//1293205 1306537 1319869 1333201 101
//1319869
//我们可以发现s2的cd和s1中的一个字串是相等的是不是可以把kmp算法也代替,这样就很简单

哈希表和字符串哈希源码

标签:std,hash,int,元素,算法,哈希,字符串,unordered
From: https://blog.csdn.net/buaichifanqie/article/details/142645122

相关文章

  • Java中的推荐系统算法:协同过滤与基于内容的比较
    Java中的推荐系统算法:协同过滤与基于内容的比较大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!今天我们来讨论Java中的推荐系统算法,特别是协同过滤与基于内容的推荐算法之间的比较。这两类推荐系统算法在实际应用中都非常常见,理解它们的工作原理和......
  • AWK进阶教程:精通match函数,让字符串搜索游刃有余!
    AWK中的match函数允许你在字符串中搜索模式。在本教程中,你将学习如何使用awkmatch函数,基于匹配结果执行条件处理,并遍历字符串中的多个匹配项。语法和用法awkmatch函数的基本语法是:awk'{if(match($0,pattern))print$0;}'filename这里,$0表示整行输入,pat......
  • 高级java每日一道面试题-2024年9月30日-算法篇-LRU是什么?如何实现?
    如果有遗漏,评论区告诉我进行补充面试官:LRU是什么?如何实现?我回答:LRU(LeastRecentlyUsed)是一种常用的缓存淘汰策略,用于在缓存满时决定哪些数据应该被移除。LRU算法的基本思想是:当缓存达到其容量上限时,最近最少使用的数据会被优先淘汰。这种策略假设最近使用的数据在......
  • KMP算法
    引言之前在打ACM竞赛时就学过一些字符串相关的算法,其中就包括KMP。但是面向竞赛的KMP算法和面向408的KMP算法在一些概念和实现细节上有细微差异,所以特意写了这篇文章对408中的KMP算法做出总结字符串的前缀、后缀和部分匹配指前缀指除了最后一个字符以外,字符串的所有头部子串;后......
  • 高精度算法-减法
    ​//高精度算法-减法#include<iostream>#include<string>#include<vector>#include<cmath>usingnamespacestd;intmain(){strings1,s2;//减法.getline(cin,s1);getline(cin,s2);//减法的2个必要数字.inta1[200]={0};inta2[200......
  • 代码随想录算法训练营第六天|Day6哈希表基础
    242.有效的字母异位词题目链接/文章讲解/视频讲解:https://programmercarl.com/0242.%E6%9C%89%E6%95%88%E7%9A%84%E5%AD%97%E6%AF%8D%E5%BC%82%E4%BD%8D%E8%AF%8D.html思路1.暴力的解法,两层为循环,很明显时间复杂度是O(n^2)。boolisAnagram(char*s,char*t){if(......
  • 3. 算法笔记-对数器
    对数器是一个非常重要的自我验证技巧,其实现步骤如下:(1)方法A(2)方法B(3)随机样本产生器(4)用相同的样本验证方法A和方法B,比对结果是否一致。(5)若出现样本,使得结果不一致,查找原因,进行改进。(6)否则,方法验证成功。#include<vector>#include<cstdio>#incl......
  • 全同态加密算法概览
    我们前面有谈到《Paillier半同态加密算法》,半同态加密算法除了支持密文加法运算的Paillier算法,还有支持密文乘法计算的RSA算法,早期的PSI(隐私求交)和PIR(匿踪查询)都有使用基于RSA盲签名技术来实现。今天我们来谈谈能够有效支持任意函数密文计算的全同态加密算法(fully......
  • 谨防火灾!电瓶车检测AI算法助力城市/小区/园区多场景安全管理精细化、智能化
    随着人工智能技术的快速发展,AI智能分析网关V4在电瓶车检测领域的应用日益广泛。这一技术通过深度学习、计算机视觉等先进算法,实现了对电瓶车及其相关行为的智能识别和分析,为电瓶车的管理和应用提供了强大的技术支持。一、电瓶车检测算法的工作原理电瓶车检测AI算法主要基于计算......
  • Drain算法-笔记
    简介论文链接:https://jiemingzhu.github.io/pub/pjhe_icws2017.pdf算法原理图:有几点注意:根节点和叶节点实际是一套规则,并不包含日志数据真正的日志数据在叶节点之下的LogGroup第一层节点,基于假设:具有相同日志事件的日志消息可能具有相同的日志消息长度第二层节点,基于......