POJ2785 ——哈希

解题思路:链式哈希

   链式hash表实现的数据结构,实际上没有使用链表,而是使用数组,用数组索引代替指针(原因是在POJ中一次开很大的数组是允许的,这样可以避免每次动态申请空间的时间开销,算是用空间换时间)head用做索引,指向hash值为key的第一个cnt;


下面是 hash 链表的插入过程:

void Insert(int num)
{
    int key = hash(num);
    for(int i = head[key]; i != -1; i = edge[i].next)
    {
        if(edge[i].v == num)
        {
            edge[i].cnt++;
            return ;
        }
    }
    edge[tot].v = num;
    edge[tot].cnt = 1;
    edge[tot].next = head[key];
    head[key] = tot++;
}

首先对num取hash,根据head找到第一个hash值为key的数在edge中的索引,如果找到,则cnt加1。否则在edge表的末尾(索引为tot,tail of table)保存下这个数的信息(数值num, 计数为1)。注意的是这里让这个新的节点下一跳指向当前的头结点,然后更新头结点为这个新节点。这样实际上将节点插入在了这一系列值的最前列。体会下当head[s]为-1时,即没有值时的情况。这样写要比将新节点报错在链式表的末端要统一。


edge中的每一个元素是一个结构体,保存这个元素的num(用v表示),下一跳在edge数组中的索引,还有num出现了多少次(用cnt表示)。hash值取0~3999970(见hash函数中的取余素数)。所以两个数组开3999971这么大。


   下面是查找过程:

int find(int num)
{
    int key = hash(num);
    for(int i = head[key]; i != -1; i = edge[i].next)
    {
        if(edge[i].v == num)
        {
            return edge[i].cnt;
        }
    }
    return 0;
}

下面是完整代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 4100;

struct edge
{
    int v;
    int next;
    int cnt;
} edge[3999972];

int head[3999972];

int hash(int num)
{
    return (num + 3899971) % 3999971;
}

int tot;
int a[maxn] , b[maxn];
int c[maxn] , d[maxn];


void Insert(int num)
{
    int key = hash(num);
    for(int i = head[key]; i != -1; i = edge[i].next)
    {
        if(edge[i].v == num)
        {
            edge[i].cnt++;
            return ;
        }
    }
    edge[tot].v = num;
    edge[tot].cnt = 1;
    edge[tot].next = head[key];
    head[key] = tot++;
}

int find(int num)
{
    int key = hash(num);
    for(int i = head[key]; i != -1; i = edge[i].next)
    {
        if(edge[i].v == num)
        {
            return edge[i].cnt;
        }
    }
    return 0;
}

int main()
{
    //freopen("in.txt","r",stdin);
    int n,i,j;
    while(cin>>n)
    {
        tot=0;
        memset(head,-1,sizeof(head));
        for(i = 1; i <= n; i++)
            cin>>a[i]>>b[i]>>c[i]>>d[i];
        for(i = 1; i <= n; i++)
        {
            for(j = 1; j <= n; j++)
            {
                Insert(a[i] + b[j]);
            }
        }
        __int64 ans = 0;
        for(i = 1; i <= n; i++)
        {
            for(j = 1; j <= n; j++)
            {
                ans += find(- c[i] - d[j]);
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值