字符串哈希算法
c++字符串哈希计算

在C++中,计算字符串的哈希值通常涉及到使用某种哈希函数。
哈希函数将输入(在这种情况下是字符串)转换为固定大小的输出,通常是整数。
这个输出被称为哈希值或哈希码。
在C++标准库中,没有内置的字符串哈希函数,但你可以使用第三方库,如Boost,或者自己实现一个简单的哈希函数。
另外,C++11引入了std::hash模板类,它可以用于获取标准类型的哈希值,包括std::string。
下面是一个使用std::hash来计算字符串哈希值的例子:cpp#include <iostream>#include <string>#include <functional>int main() {std::string str = "Hello, World!";std::hash<std::string> hasher;size_t hash = hasher(str);std::cout << "Hash value of \"" << str << "\" is: " << hash << std::endl; return 0;}在这个例子中,我们使用了std::hash<std::string>来创建一个字符串哈希函数对象。
然后,我们通过调用这个函数对象并传入我们的字符串来计算哈希值。
最后,我们打印出计算得到的哈希值。
请注意,不同的编译器和平台可能会产生不同的哈希值,因为C++标准并没有规定std::hash 的具体实现。
因此,如果你需要跨平台的一致性,你可能需要使用一个特定的哈希算法,如MD5、SHA-1或SHA-256,这些都可以通过第三方库(如OpenSSL或Crypto++)来实现。
然而,这些算法通常用于密码学和数据完整性检查,而不是普通的哈希表查找。
计算哈希值的方法

计算哈希值的方法哈希值是一种通过数据内容计算出来的固定长度的字符串。
它具有以下特点:1.固定长度:哈希值的长度是固定的,无论输入数据的长度如何,哈希值的长度始终不变。
通常情况下,哈希值的长度由算法决定。
2.确定性:对于相同的输入数据,总是可以得到相同的哈希值。
3.不可逆性:从哈希值无法恢复出原始数据,即无法通过哈希值反推出输入数据的内容。
这是哈希算法的一种安全特性。
计算哈希值的方法有多种,这里我们主要介绍以下几种常见的哈希算法。
1. MD5 (Message Digest Algorithm 5)MD5是最早广泛应用的哈希算法之一,它将任意长度的数据作为输入,并输出一个128位的哈希值。
MD5算法已被证明不具备足够的安全性,容易受到碰撞攻击。
2. SHA (Secure Hash Algorithm)算法系列SHA算法系列是继MD5之后被广泛采用的哈希算法。
SHA系列包括SHA-1、SHA-224、SHA-256、SHA-384和SHA-512等不同长度的哈希算法。
SHA-1已经不再被推荐使用,因为它的哈希值长度为160位,安全性相对较低,而且存在碰撞攻击的问题。
SHA-256是目前广泛使用的SHA算法,其哈希值长度为256位。
3. CRC32 (Cyclic Redundancy Check)CRC32是一种经典的哈希算法,广泛应用于数据校验中。
它将任意长度的数据作为输入,并输出一个32位的哈希值。
CRC32主要用于检测数据在传输过程中是否发生了错误。
4. HMAC (Hash-based Message Authentication Code)HMAC是一种基于哈希算法的消息验证码,常用于网络通信中的数据完整性校验和身份认证。
HMAC通过在哈希过程中引入额外的密钥,增加了安全性。
5. BcryptBcrypt是一种用于密码存储的哈希算法。
与其他哈希算法不同的是,Bcrypt在计算哈希值时会引入随机盐,增加了密码的安全性。
字符串哈希算法转数字

字符串哈希算法转数字字符串哈希算法是将字符串转换成数字的一种算法。
常用的字符串哈希算法有哈希函数(Hash function),其主要思想是通过某种算法将字符串映射到一个数字上。
主要有两种方法将字符串转换成数字:1.加法哈希:将每个字符的ASCII 码相加得到的数字作为哈希值。
2.乘法哈希:将每个字符的ASCII 码相乘得到的数字作为哈希值。
常用的字符串哈希算法有:●MD5:128位的哈希值,经过改进的MD5算法●SHA:Secure Hash Algorithm,安全哈希算法,包括SHA-1,SHA-2,SHA-3等●MurmurHash:高性能哈希算法,常用于哈希表●FNV:Fowler-Noll-Vo哈希算法Java中加法哈希的实现方法如下:public int addHash(String str) {int hash = 0;for (int i = 0; i < str.length(); i++) {hash += str.charAt(i);}return hash;}//例子String s = "hello";int hash = addHash(s);这个函数接受一个字符串作为输入,遍历每个字符,将它们的ASCII 码值相加,最后返回哈希值。
这里的哈希值就是"h" 的ASCII 码值104 加上"e" 的ASCII 码值101 加上"l" 的ASCII 码值108 加上"l" 的ASCII 码值108 加上"o" 的ASCII 码值111,即:104 + 101 + 108 + 108 + 111 = 432。
哈希表之bkdrhash算法解析及扩展

哈希表之bkdrhash算法解析及扩展BKDRHASH是⼀种字符哈希算法,像BKDRHash,APHash。
DJBHash,JSHash,RSHash。
SDBMHash。
PJWHash。
ELFHash 等等,这些都是⽐較经典的,通过(字符串哈希函数)这篇⽂章,我们可知道,BKDRHash是⽐較好的⼀个获取哈希值的⽅法。
以下就解说这个BKDRHash函数是怎样推导实现的。
当我看到BKDRHash的代码时。
不禁就疑惑了。
这⾥⾯有个常数Seed,取值为31、131等,为什么要这么取。
我取其它的值不⾏吗?还有为什么要将每⼀个字符相加。
并乘以这个Seed?这些究竟是什么含义?最后想了⽼半天都是不得其解,最后绕进素数⾥⾯出不来了……最后在⼀位⽜⼈的指点下。
才茅塞顿开。
以下把我的想法和推导过程记录例如以下。
BKDRHash计算公式的推导由⼀个字符串(⽐⽅:ad)得到其哈希值。
为了降低碰撞,应该使该字符串中每⼀个字符都參与哈希值计算。
使其符合雪崩效应,也就是说即使改变字符串中的⼀个字节,也会对终于的哈希值造成较⼤的影响。
我们直接想到的办法就是让字符串中的每⼀个字符相加。
得到其和SUM,让SUM作为哈希值,如SUM(ad)= a+d;但是依据ascii码表得知a(97)+d(100)=b(98)+c(99)。
那么发⽣了碰撞,我们发现直接求和的话会⾮常easy发⽣碰撞,那么怎么办哪?我们能够对字符间的差距进⾏放⼤,乘以⼀个系数:SUM(ad) =系数1 * a + 系数2 * dSUM(bc)= 系数1 * b + 系数2 * c系数1不等于系数2。
这样SUM(ad)等于SUM(bc)的概率就会⼤⼤减⼩。
但是我们的字符串不可能仅仅有两位或者三位,我们也不可能为每⼀个系数去⼈为的赋值。
但是字符串中有位数的顺序。
⽐⽅在”ab”中,b是第0位,a是第1位,那么我们能够⽤系数的n次⽅作为每⼀个字符的系数,但这个系数不能为1:SUM(ad) =系数^1 * a + 系数^0 * dSUM(bc)= 系数^1 * b + 系数^0 * c这样我们就⼤⼤减少了碰撞的发⽣,以下我们如果有个字符数组p,有n个元素,那么即:以下就是这个“系数”取值的问题。
哈希匹配算法

哈希匹配算法哈希匹配算法是一种常用的字符串匹配算法,它通过将字符串映射为一个固定长度的哈希值来进行匹配。
在实际应用中,哈希匹配算法被广泛用于字符串匹配、模式匹配、数据索引等领域。
一、哈希匹配算法的基本原理哈希匹配算法的基本原理是将字符串通过一个哈希函数转换为一个唯一的哈希值,然后将这个哈希值与其他字符串进行比较,从而实现字符串匹配的功能。
哈希函数的设计非常重要,它应该具备以下特点:1. 输入相同的字符串,哈希函数应该返回相同的哈希值;2. 输入不同的字符串,哈希函数应该返回不同的哈希值。
1. 字符串匹配:在文本处理、搜索引擎等领域,哈希匹配算法常被用于字符串匹配。
通过将待匹配的字符串和已有的字符串进行哈希映射,可以快速地找到匹配的结果。
2. 模式匹配:在字符串处理、编译原理等领域,哈希匹配算法被用于模式匹配。
通过将模式串和待匹配的字符串进行哈希映射,可以高效地找到模式串在待匹配字符串中的位置。
3. 数据索引:在数据库、搜索引擎等领域,哈希匹配算法被用于数据索引。
通过将数据的关键字进行哈希映射,可以快速地找到对应的数据项。
三、哈希匹配算法的优缺点1. 优点:(1)高效性:哈希匹配算法通过哈希映射的方式进行匹配,能够快速定位到待匹配字符串的位置,从而提高匹配效率。
(2)灵活性:哈希匹配算法可以根据实际需求设计不同的哈希函数,适应不同的应用场景。
(3)可扩展性:哈希匹配算法可以通过调整哈希函数的参数来适应不同规模的数据集。
2. 缺点:(1)冲突问题:由于哈希函数的映射是将一个无限的输入域映射到一个有限的输出域,所以在实际应用中,哈希函数可能会出现冲突,导致多个不同的字符串映射到同一个哈希值上。
(2)哈希函数设计困难:设计一个好的哈希函数是非常困难的,需要考虑多个因素,并且需要保证输入相同的字符串一定能够得到相同的哈希值,输入不同的字符串一定能够得到不同的哈希值。
四、哈希匹配算法的改进方法1. 拉链法:当哈希函数出现冲突时,可以使用拉链法来解决。
几种字符串哈希HASH算法的性能比较

几种字符串哈希HASH算法的性能比较2011年01月26日星期三 19:40这不就是要找hash table的hash function吗?1 概述链表查找的时间效率为O(N),二分法为log2N,B+ Tree为log2N,但Hash链表查找的时间效率为O(1)。
设计高效算法往往需要使用Hash链表,常数级的查找速度是任何别的算法无法比拟的,Hash 链表的构造和冲突的不同实现方法对效率当然有一定的影响,然而Hash函数是Hash链表最核心的部分,本文尝试分析一些经典软件中使用到的字符串 Hash函数在执行效率、离散性、空间利用率等方面的性能问题。
2 经典字符串Hash函数介绍作者阅读过大量经典软件原代码,下面分别介绍几个经典软件中出现的字符串Hash函数。
2.1 PHP中出现的字符串Hash函数static unsigned long hashpjw(char *arKey, unsigned int nKeyLength) {unsigned long h = 0, g;char *arEnd=arKey+nKeyLength;while (arKey < arEnd) {h = (h << 4) + *arKey++;if ((g = (h & 0xF0000000))) {h = h ^ (g >> 24);h = h ^ g;}}return h;}2.2 OpenSSL中出现的字符串Hash函数unsigned long lh_strhash(char *str){int i,l;unsigned long ret=0;unsigned short *s;if (str == NULL) return(0);l=(strlen(str)+1)/2;s=(unsigned short *)str;for (i=0; iret^=(s[i]<<(i&0x0f));return(ret);} *//* The following hash seems to work very well on normal text strings * no collisions on /usr/dict/words and it distributes on %2^n quite * well, not as good as MD5, but still good.*/unsigned long lh_strhash(const char *c){unsigned long ret=0;long n;unsigned long v;int r;if ((c == NULL) || (*c == '\0'))return(ret);/*unsigned char b[16];MD5(c,strlen(c),b);return(b[0]|(b[1]<<8)|(b[2]<<16)|(b[3]<<24));*/n=0x100;while (*c){v=n|(*c);n+=0x100;r= (int)((v>>2)^v)&0x0f;ret=(ret<>(32-r));ret&=0xFFFFFFFFL;ret^=v*v;c++;}return((ret>>16)^ret);}在下面的测量过程中我们分别将上面的两个函数标记为OpenSSL_Hash1和OpenSSL_Hash2,至于上面的实现中使用MD5算法的实现函数我们不作测试。
RabinKarp算法利用哈希函数解决字符串匹配问题

RabinKarp算法利用哈希函数解决字符串匹配问题RabinKarp算法是一种用于解决字符串匹配问题的算法,它利用了哈希函数的特性来进行匹配。
在本文中,将详细介绍RabinKarp算法的原理和实现,并对其优缺点进行探讨。
一、RabinKarp算法的原理RabinKarp算法是一种基于哈希函数的字符串匹配算法。
它的基本思想是通过对字符串进行哈希计算,将字符串的每个字符映射为一个数值,然后利用滑动窗口的方式在目标字符串中进行匹配。
具体而言,RabinKarp算法可以分为以下几个步骤:1. 计算模式串的哈希值,并记录下来。
2. 计算目标字符串中第一个与模式串长度相等的子串的哈希值。
3. 比较当前的哈希值与模式串的哈希值是否相等,如果相等,则进一步比较两个字符串是否完全一致。
4. 如果两个字符串不完全一致,则通过滑动窗口的方式,将目标字符串中的子串的哈希值更新为下一个字符的哈希值,并继续进行比较。
5. 重复步骤3和步骤4,直到找到匹配的子串或者目标字符串遍历完成。
通过利用哈希函数的计算,RabinKarp算法能够在平均情况下以线性时间复杂度O(n+m)完成匹配,其中n和m分别为目标字符串和模式串的长度。
二、RabinKarp算法的实现下面给出RabinKarp算法的具体实现代码:```pythondef rabin_karp(pattern, text):n = len(text)m = len(pattern)pattern_hash = hash(pattern)for i in range(n-m+1):window = text[i:i+m]window_hash = hash(window)if window_hash == pattern_hash and window == pattern:return ireturn -1```在上述代码中,我们可以看到,通过调用`hash()`函数计算字符串的哈希值,从而实现了RabinKarp算法的匹配过程。
哈希算法实现字符串匹配

哈希算法实现字符串匹配对于匹配字符串m和⽬标字符串n,最朴素的思想就是对于每个起始位置都o(m)地直接⽐较字符是否相同,最后时间复杂度为O(m*n)这样的时间复杂度在⼤多数时候都很不乐观,因此需要⼀些技巧降低时间复杂度。
哈希算法:我们可以将⼀段字符串映射为数值然后⽐较数值⼤⼩,若相等则匹配成功。
这是理想情况下的,要达到这样的效果需要哈希算法具备⼀定的抗碰撞性(即不同的字符串不会映射到同⼀数值)。
在这个前提下,要是计算每个长度为m的字符串的哈希值,最终复杂度必然还是O(m*n),这⾥可以⽤滚动哈希的⽅法优化。
对于匹配字符串 s=C₁C₂C₃.....C 哈希值H=C₁*B^(m-1)+C₂*B^(m-2)+C₃*B^(m-3)+...+C 其中B取⼀个⾮常⼤素数如(1e9+7),B^(m-1)表⽰B的m-1次⽅对于⽬标字符串ss=A₁A₂A₃....A 已知A₁开始长度为m的字符串的哈希值为h ,要得到A₂开始长度为m的字符串的哈希值只需h′ = h*B-A₁*B^m+D 其中D为第(m+1)位字符,就可以在O(n)的时间复杂度内实现字符串匹配先上代码:1 #include<iostream>2 #include<algorithm>3 #include<string>4 #include<set>5 #include<vector>6 #include<queue>7 #include<stack>8 #include<map>9 #include<cmath>10 #include<string>11using namespace std;12 typedef unsigned long long ull;13char s[1010][1010];14char pat[110][55][1010];15 ull hash_[1010][1010], temp[1010][1010];16const ull B = 1e9 + 7, A = 9973;17int N, M, P, Q, T;18void comput_hash(char a[][1010], int n, int m)19 {20int i, j, k;21 ull e = 0, t1 = 1, t2 = 1;22for (i = 1; i <= Q; i++)23 t1 *= A;24for (i = 1; i <= n; i++)25 {26 e = 0;27for (j = 1; j <= Q; j++)28 e = e * A + a[i][j];29for (j = 1; j + Q - 1 <= m; j++)30 {31 temp[i][j] = e;32if (j + Q <= m)33 e = e * A - a[i][j] * t1 + a[i][j + Q];34 }35 }3637 e = 0;38for (i = 1; i <= P; i++)39 t2 *= B;40for (j = 1; j + Q - 1 <= m; j++)41 {42 e = 0;43for (i = 1; i <= P; i++)44 e = e * B + temp[i][j];45for (i = 1; i + P - 1 <= n; i++)46 {47 hash_[i][j] = e;48if (i + P <= n)49 e = e * B - temp[i][j] * t2 + temp[i + P][j];50 }51 }52 }53int main()54 {55int i, j, k;56int cnt = 0, ans;57while (~scanf("%d%d%d%d%d", &N, &M, &T, &P, &Q))58 {59if (N == 0 && M == 0 && P == 0 && Q == 0 && T == 0)60break;61for (i = 1; i <= N; i++)62 scanf("%s", s[i] + 1);63for (k = 1; k <= T; k++)64for (i = 1; i <= P; i++)65 scanf("%s", pat[k][i] + 1);6667 multiset<ull>ml;68for (i = 1; i <= T; i++)69 {70 comput_hash(pat[i], P, Q);71 ml.insert(hash_[1][1]);72 }7374 comput_hash(s, N, M);75for (i = 1; i + P - 1 <= N; i++)76for (j = 1; j + Q - 1 <= M; j++)77 ml.erase(hash_[i][j]);7879 ans = T - ml.size();80 printf("Case %d: %d\n", ++cnt, ans);81 }82return0;83 }对于这道题,我们可以先只看⼀个维度,对于⼀个维度的匹配就是简单的板⼦题,就像之前所说进⾏匹配即可,在拓展到⼆维时,应该考虑⾏列均相同。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
经典字符串Hash函数工作中经常需要用大hash这个强有力的工具,hash表最核心的部分则在于怎么设计一个好的hash函数,以使数据更均匀地分布在若干个桶上。
下面来介绍一下我现在用到的一个hash函数,我们来看代码:unsigned chostcachehash::get_host_key(const string& host){int result = 1;unsigned i = 0;for (i = 0; i <host.size(); i++)result = 31 * result + host[i];return abs(result);}inline unsigned getkey(unsigned key){return (key % m_capacity);}m_capacity为hash桶的个数对于一个字符串,我们首先调用get_host_key()来得到一个key,然后再用这个key调用getkey来得到他在hash桶里的位置。
这个是我们在工作一直使用的hash函数,效果也还可以。
今天忽然心血来潮,在网上搜了一下看还有没有更好的hash函数,被我发现了这篇文章,于是转过来看看。
php中出现的字符串hash函数static unsigned long hashpjw(char *arkey,unsigned intnkeylength){unsigned long h = 0,g;char *arend=arkey+nkeylength;while (arkey<arend) {h = (h << 4) + *arkey++;if ((g = (h & 0xf0000000))) {h = h ^ (g >> 24);h = h ^ g;}}return h;}openssl中出现的字符串hash函数unsigned long lh_strhash(char *str){int i,l;unsigned long ret=0;unsigned short *s;if (str == null) return(0);l=(strlen(str)+1)/2;s=(unsigned short *)str;for (i=0; i %有点看不懂ret^=(s[i]<<(i&0x0f));return(ret);} *//* the following hash seems to work very well on normal text strings * no collisions on /usr/dict/words and it distributes on %2^n quite* well,not as good as md5,but still good.*/unsigned long lh_strhash(const char *c){unsigned long ret=0;long n;unsigned long v;int r;if ((c == null) || (*c == "{post.abstract}"))return(ret);/*unsigned char b[16];md5(c,strlen(c),b);return(b[0]|(b[1]<<8)|(b[2]<<16)|(b[3]<<24));*/n=0x100;while (*c){v=n|(*c);n+=0x100;r= (int)((v>>2)^v)&0x0f;ret=(ret<>(32-r));ret&=0xffffffffl;ret^=v*v;c++;}return((ret>>16)^ret);}mysql中出现的字符串hash函数#ifndefnew_hash_function/* calchashvalue for a key */static uintcalc_hashnr(const byte *key,uint length){register uint nr=1,nr2=4;while (length--){nr^= (((nr & 63)+nr2)*((uint) (uchar) *key++))+ (nr << 8);nr2+=3;}return((uint) nr);}/* calchashvalue for a key,case indepenently */static uintcalc_hashnr_caseup(const byte *key,uint length){register uint nr=1,nr2=4;while (length--){nr^= (((nr & 63)+nr2)*((uint) (uchar) toupper(*key++)))+ (nr << 8);nr2+=3;}return((uint) nr);}#else/** fowler/noll/vo hash** the basis of the hash algorithm was taken from an idea sent by email to the * ieeeposix p1003.2 mailing list from phongvo (kpv@) and * glenn fowler (gsf@). landon curt noll (chongo@) * later improved on their algorithm.** the magic is in the interesting relationship between the special prime* 16777619 (2^24 + 403) and 2^32 and 2^8.** this hash produces the fewest collisions of any function that we"ve seen so * far,and works well on both numbers and strings.*/uintcalc_hashnr(const byte *key,uintlen){const byte *end=key+len;uint hash;for (hash = 0; key < end; key++){hash *= 16777619;hash ^= (uint) *(uchar*) key;}return (hash);}uintcalc_hashnr_caseup(const byte *key,uintlen) {const byte *end=key+len;uint hash;for (hash = 0; key < end; key++){hash *= 16777619;hash ^= (uint) (uchar) toupper(*key);}return (hash);}#endif从上表可以看出,这些经典软件虽然构造字符串Hash函数的方法不同,但是它们的效率都是不错的,相互之间差距很小,读者可以参考实际情况从其中借鉴使用。
暴雪公司有个经典的字符串的hash公式先提一个简单的问题,假如有一个庞大的字符串数组,然后给你一个单独的字符串,让你从这个数组中查找是否有这个字符串并找到它,你会怎么做?有一个方法最简单,老老实实从头查到尾,一个一个比较,直到找到为止,我想只要学过程序设计的人都能把这样一个程序作出来,但要是有程序员把这样的程序交给用户,我只能用无语来评价,或许它真的能工作,但...也只能如此了。
最合适的算法自然是使用HashTable(哈希表),先介绍介绍其中的基本知识,所谓Hash,一般是一个整数,通过某种算法,可以把一个字符串"压缩" 成一个整数,这个数称为Hash,当然,无论如何,一个32位整数是无法对应回一个字符串的,但在程序中,两个字符串计算出的Hash值相等的可能非常小,下面看看在MPQ中的Hash算法unsigned long HashString(char *lpszFileName, unsigned long dwHashType){unsigned char *key = (unsigned char *)lpszFileName;unsigned long seed1 = 0x7FED7FED, seed2 = 0xEEEEEEEE;intch;while(*key != 0){ch = toupper(*key );seed1 = cryptTable[(dwHashType<< 8) ch] ^ (seed1 seed2);seed2 = ch seed1 seed2 (seed2 << 5) 3;}return seed1;}Blizzard的这个算法是非常高效的,被称为"One-Way Hash",举个例子,字符串"unitneutralacritter.grp"通过这个算法得到的结果是0xA26067F3。
是不是把第一个算法改进一下,改成逐个比较字符串的Hash值就可以了呢,答案是,远远不够,要想得到最快的算法,就不能进行逐个的比较,通常是构造一个哈希表(Hash Table)来解决问题,哈希表是一个大数组,这个数组的容量根据程序的要求来定义,例如1024,每一个Hash值通过取模运算(mod)对应到数组中的一个位置,这样,只要比较这个字符串的哈希值对应的位置又没有被占用,就可以得到最后的结果了,想想这是什么速度?是的,是最快的O(1),现在仔细看看这个算法吧intGetHashTablePos(char *lpszString, SOMESTRUCTURE *lpTable, intnTableSize){intnHash = HashString(lpszString), nHashPos = nHash % nTableSize;if (lpTable[nHashPos].bExists&& !strcmp(lpTable[nHashPos].pString, lpszString)) returnnHashPos;elsereturn -1; //Error value}看到此,我想大家都在想一个很严重的问题:"假如两个字符串在哈希表中对应的位置相同怎么办?",究竟一个数组容量是有限的,这种可能性很大。