P4305 [JLOI2011]不重复数字

终于掌握了两种处理哈希冲突的方法了!特意来总结

哈希是很好的一样东西。但是unordered_map更好啊

By the way, NOIP是可以用unordered_map的,需要这么用:

#include<tr1/unordered_map>

int main()
{
    std::tr1::unordered_map<int.int> mmp;
    .......
}

亲测在NOI Linux下面可以编译,所以就ok了哇!


解决哈希冲突的好方法有两种:一种是开放地址法,一种是拉链法。

开放地址法

一句话的思路:自己的地方被人占了,我就占别人的地方。

一旦发生冲突,就把自己的下标++,然后再取哈希函数,直至不冲突为止,那么就在这个不冲突的地方直接安居。

期望的时间复杂度不是很优,但是还可以。至少比map快啊!

拉链法

一句话的思路:自己的地方被人占了,我就排在她后面就好了哇!

一旦发生冲突,就拉一条链表,把自己插在这条链表的尾部(或者首部)。

这样的期望复杂度真的很优秀。是值得学习的一种方法。

下面的代码是使用拉链法解决的。开放地址法的luogu的题解上面有,可以自己去学一下,很简单的。

讲道理拉链法比开放地址法跑得快太多太多了

拉链法用的时间是565ms,2.28M的内存。

开放地址法的时间是7176ms,七十多M的内存。

所以你懂了吧?

代码:

#include<cstdio>
#include<cstring>
const int MOD = 100007;
struct Hashtable
{
    int head[MOD], next[MOD], key[MOD], value[MOD];
    int tot;
    int hash(int x)
    {
        if(x < 0) x = -x;
        return x % MOD;
    }
    int count(int ke)
    {
        for(int i = head[hash(ke)]; i; i = next[i])
        {
            if(key[i] == ke) return value[i];
        }
    }
    void insert(int ke, int val)
    {
        tot++;
        key[tot] = ke; value[tot] = val; next[tot] = head[hash(ke)];
        head[hash(ke)] = tot;
    }
    void clear()
    {
        tot = 0;
        memset(head, 0, sizeof head);
        memset(next, 0, sizeof next);
        memset(key, 0, sizeof key);
        memset(value, 0, sizeof value);
    }
} hashtable;
int n;
int read()
{
    int ans = 0, s = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0'){ if(ch == '-') s = -1; ch = getchar(); }
    while(ch >= '0' && ch <= '9') ans = ans * 10 + ch - '0', ch = getchar();
    return s * ans;
}
int main()
{
    int T = read();
    while(T--)
    {
        hashtable.clear();
        n = read();
        bool first = true;
        for(int i = 1; i <= n; i++)
        {
            int temp = read();
            if(!hashtable.count(temp))
            {
                if(first) printf("%d", temp), first = false;
                else printf(" %d", temp);
                hashtable.insert(temp, 1);
            }
        }
        printf("\n");
    }
    return 0;
}

转载于:https://www.cnblogs.com/Garen-Wang/p/9911916.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值