首页 > 其他分享 >字符串hash相关

字符串hash相关

时间:2023-11-23 15:44:06浏览次数:23  
标签:std hash int long collision str 字符串 相关

哈希

c++里常用的hash是map和unordered_map
前者是平衡树实现的, O(logn)的插入和搜索, 后者是O(1)的插入和搜索
但是前者有序, 后者无序
本文讲的是后者

关于实现

基本类型可以视所需空间大小选择不同的hash办法
而我着重讲一下字符串的hash

在字符串hash里

  1. DJB hash
  2. SDBM hash
  3. BKDR hash

这些都是常见的hash

关于空间

这里提一下, hash有"负载因子"一说

负载因子 衡量哈希表满的程度的指标, 当元素数量/桶数量 > 负载因子时, hash表会进行重新hash

用unordered_map的时候一开始就要reverse扩容到自己需要的空间, 不然随着元素增多, 他会rehash, 浪费性能

自己写hash表的时候, 我听说一般都是直接开4N的空间, 原理未知, 可能是性价比比较高吧, 在我看来, 肯定是空间允许的话, 开的越大越好

关于碰撞

碰撞我一般直接直接链起来, 来判断即可.
比较简单

hash算法碰撞测试

测一下两个简单的hash, djb和bkdr

#include <bits/stdc++.h>
#include <chrono>
using namespace std;

#define HASH_SIZE 100000
#define HASH_TABLE_SIZE (HASH_SIZE << 2)
#define MOD (HASH_TABLE_SIZE)
int m_count[HASH_TABLE_SIZE];

vector<string> generate_string(int num, int max_length)
{
    vector<string> strings;
    strings.reserve(num);
    random_device rd;
    mt19937 gen(rd());
    uniform_int_distribution<> length_dist(1, max_length);
    uniform_int_distribution<> char_dist(32, 126);
    for (int i = 0; i < num; i++)
    {
        int len = length_dist(gen);
        string str;
        str.reserve(len);
        for (int j = 0; j < len; j++)
        {
            str.push_back(static_cast<char>(char_dist(gen)));
        }
        strings.push_back(str);
    }
    return strings;
}

unsigned long long BKDRhash(char *c)
{
    unsigned long long seed = 131;
    unsigned long long hash = 0;
    while (*c)
    {
        hash *= seed;
        hash += (*c++);
    }
    return hash % MOD;
}

unsigned long long DJBhash(char *c)
{
    unsigned long long hash = 5381;
    while (*c)
    {
        hash += (hash << 5);
        hash += (*c++);
    }
    return hash % MOD;
}

void test(std::function<unsigned long long(char *c)> f, std::vector<string> &strings)
{
    memset(m_count, 0, sizeof(m_count));
    auto start = std::chrono::high_resolution_clock::now();
    for (auto &str : strings)
    {
        m_count[f(&str[0])]++;
    }
    int collision = 0;
    for (int i = 0; i < HASH_TABLE_SIZE; i++)
    {
        if (m_count[i] > 1)
        {
            collision++;
        }
    }
    auto end = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
    std::cout << "Time taken by function: " << duration.count() << " milliseconds" << std::endl;
    cout << "collision: " << collision << endl;
}

int main()
{
    vector<string> strs = generate_string(100000, 1000);
    test(BKDRhash, strs);
    test(DJBhash, strs);
    return 0;
}

上面代码跑出来结果是

Time taken by function: 144 milliseconds
collision: 10659
Time taken by function: 161 milliseconds
collision: 10696

然后我把哈希表又放大了4倍, 果然跟我想的一样, 碰撞少了

collision: 2934
collision: 3059

那其实没有什么空间要开多大的说法, 本来就是允许的话越大越好.
而且bkdr的hash性能似乎更好一些, 虽然我也看不懂为什么乘法会比位移更好
不懂, 反正事实如此, 开完O2后两个差不多, 那看来可能是没优化吧
seed的选择也相当无所谓, 我是没测出来素数好在哪

标签:std,hash,int,long,collision,str,字符串,相关
From: https://www.cnblogs.com/ryougi/p/17851690.html

相关文章

  • js 数组、字符串常用方法
    JavaScript数组的常用操作增:push()向数组的末尾添加一个或更多元素,并返回新的长度unshift()在数组开头添加任意多个值,然后返回新的数组长度splice()传入三个参数,分别是开始位置、0(要删除的元素数量)、插入的元素,返回空数组concat()首先会创建一个当前数组的副本,然后再把它......
  • 电脑网站支付报错“验签出错,建议检查签名字符串或私钥与应用公钥是否匹配”问题解决记
    在对接支付宝电脑网站支付的时候,遇到如下报错:“错误代码invalid-signature错误原因:验签出错,建议检查签名字符串或签名私钥与应用公钥是否匹配”。但展示的报错内容跟实际原因有所出入(在下文中有解答),这里记录下问题的解决排查过程。问题复现在对接电脑网站支付时,生成form表单......
  • redis -- 相关
    https://cloud.tencent.com/developer/article/1553633 1.下载https://redis.io/downloadcd/usr/local/srcwget-chttp://download.redis.io/releases/redis-3.2.6.tar.gz复制2.解压cd/usr/local/srctarxzfredis-3.2.6.tar.gz复制3.编译cd/usr/local/src/re......
  • js如何计算字符串的字节数
    如果计算字符长度只需要使用length,letstr="hello世界";console.log(str.length)//7如何计算所占用的字节数呢?functiongetByteLength(str){letlength=0;for(leti=0;i<str.length;i++){letcharCode=s......
  • GeminiDB新特性:让Redis广告频控爱不释手的exHASH
    本文分享自华为云社区《GeminiDB新特性:让Redis广告频控爱不释手的exHASH》,作者:GeminiDB-Redis博客。exHash类型是一种支持Field过期的新型数据类型,它在原先的Hash类型基础上进行了扩展:在支持Hash类型的通用功能以外,exHash类型还支持为Field设置过期时间和版本,增强了数据结构的灵......
  • Python中列表和字符串常用的数据去重方法你还记得几个?
    (Python中列表和字符串常用的数据去重方法你还记得几个?)1关于数据去重关于数据去重,咱们这里简单理解下,就是删除掉重复的数据;应用的场景比如某些产品产生的大数据,有很多重复的数据,为了不影响分析结果,我们可能需要对这些数据进行去重,删除重复的数据,提高分析效率等等。2字符串......
  • C#.NET 循环字符串 V20231123
    C#.NET循环字符串V20231123 publicstaticboolIsIllegalOutTradeNo(stringOutTradeNo){foreach(chariteminOutTradeNo){if(item=='('||item==')'||item==','||item=......
  • 字符串之多种个性化格式处理
    此文重点讲述:字符串之个性化格式处理。个性化字符串工具类importjava.util.List;importjava.util.Random;importjava.util.regex.Matcher;importjava.util.regex.Pattern;/***字符串工具类*/publicfinalclassStringUtils{privateStringUtils(){......
  • (字符串)01-字符串变形
    1importjava.util.*;23publicclassSolution{4/**5*@paramsstring字符串6*@paramnint整型7*@returnstring字符串8*/9publicStringtrans(Strings,intn){10//校验字符串长度11if......
  • 什么是hash
    哈希(Hash)通常指的是将任意长度的输入数据映射为固定长度的输出数据的过程。这个输出通常被称为哈希值或散列值。哈希函数是执行哈希的算法。哈希函数有以下几个特性:确定性:对于相同的输入,哈希函数应该始终产生相同的哈希值。固定长度输出:无论输入的大小是多少,哈希函数的输......