整数散列(hash)

在复杂度学习的过程中,我们明白了时间复杂度与空间复杂度的概念,我们主要利用时间复杂度来评判算法的时间效率,空间复杂度则是指算法消耗的最大空间,而通常来说一段代码的空间应该充裕,可以使用散列将时间复杂度降低,转换为空间复杂度,依靠消耗更多的空间来换取时间上的高效

此题很显然我们可以设定一个数组来存放球道数,数组中的每个元素则代表了球道的瓶子数,但是它明确规定了询问次数,因而我们不能使用传统的依次扫描数组中的每个元素来寻找我们需要的发球球道。 此时就可以试着将空间换时间,使用hash来寻找需要发球的球道。 (当然此题还有更简答的解答方法但现在作为hash例题使用hash表实现)

#include <iostream>
#define mod 538211 

using namespace std;
int n,m,j,a[mod+2];

int main()
{
    cin>>n;//输入球道数
    for(int i=0;i<n;i++)
    {
        cin>>m;//输入第i个球道上的瓶子数
        m%=mod;//m即为key,m与mod取余作为hash值
        a[m]=i+1;//将hash值作为数组下标,赋赛道数于hash值对应的的数组内(赛道从0开始)
    }
    cin>>j;//输入想要击打的瓶子数量
    j%=mod;//求出对应hash值
    cout<<a[j]<<endl;//j的a[hash]即为对应的赛道

    return 0;
}

从例题中可以看到,散列可以将元素通过一个函数转换为整数,并尽可能用一个整数唯一的元素代表一个元素。可是虽然看起来很美好,只用了一个长度大小为mod+2的数组就完成了问题,但是仍然存在着可能存在某两个赛道上的瓶子数的hash值相等的问题,当出现hash值相等的H(key1),H(key2)就会出现“冲突” 。

并且,上述代码中的表长必须大于等于mod,且mod取素数时H可以更尽可能落在0到mod之间。


对于解决“冲突”这个问题可以:

#include <bits/stdc++.h>
#define mod 538211

using namespace std;
vector <int> a [mod+2] ;
int n,m,k1,k2;
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>m;
        k1=m%mod;
        a[k1].push_back(i+1);//压入赛道
        a[k1].push_back(m);//压入保龄球数
    }
    cin>>m;
    k2=m%mod;
    for(int i=0;i<a[k2].size();i++)
    {
        if(a[k2][i+1]==m)//检测保龄球数对应的赛道
         cout<<a[k2][i];
    }
    cout<<endl;
    return 0;
}

运用了vector数组,将数据压入动态数组中,对于H相同的数据,通过检测数据数值输出数据,可以避免出现“冲突”,类似于“链地址法”。 

对于解决“冲突”还有“线性探查法”、“平方探查法”、“链地址法”。

这两种方法都是利用各种方法,寻找这个一维的hash表中剩余的空地方,将起冲突的H,储存在这些空地方中。

线性探查法:加入得到key的H值被 占用之后,检测H+1是否被占用,若没有则占用H+1,若已被占用,则检验下一个位置(超过表长就回到开头继续寻找),以此类推知道找到合适的位置。

平方探查法:若位置被占,按照:H+1^ 2、H-1^ 2、H+2^ 2、H-2^ 2、H+3^ 2……的顺序检测,超出表长,对(H+k^ 2)对表长取模继续检测。

当然,在学习map函数之后,可以使用map函数来实现hash的功能,一般不需要自己解决“冲突”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值