可并堆,离散优化以及HASH表,线段树总结

最近学了点数据结构,觉得有必要总结一下。
下面首先是离散优化:

离散化,把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。
例如:
原数据:1,999,100000,15;处理后:1,3,4,2;
原数据:{100,200},{20,50000},{1,400};
处理后:{3,4},{2,6},{1,5};

离散优化是建立数据与存储结构间的对应关系。
HASH优化:是对于字符串和数字的一种优化方式。它通过将数据映射到数组内的某个元素从而达到节省空间的效果。
但对于f( )可能有f(keyA)==f(keyB) (keyA!=keyB)
这里我们通常有两种解决方法:
1.拉链法
样例

3
abcdefg
gabcedf
kajshdb

给出hash值计算函数和结构体

const int maxn=100000;
struct node{
    char s[100];
    int next;
}arc[maxn*10];
  int Hash(char str[]){
    int i,len,sum=0;
    len=strlen(str+1);
    for(i=1;i<=len;i++){
        sum+=str[i]-'a'+1;
    }
    return sum%51;
}  

易得第一,第二字符串返回的Hash值都是28,发生冲突,可实际上在我看来,无论是否冲突,我们都可以使用静态链接表储存,例如str[]使用fir[Hash(str[])]储存。
如下代码:

int fir[maxn],cur=0;
void add(int val,char s[])
{
    arc[++cur].next=fir[val];
    int len=strlen(s+1);
    for(int i=1;i<=len;i++)
     arc[cur].str[i]=s[i];
    fir[val]=cur;//就是普通图论的存法
}

2.开地址法

当hash所对密码冲突时,将数据存入另外的位置(可以是下一个空位置,也可以是计算出的任意位置)。

比如:

while(hashtable[ad]!=0){
    ad+=ad%3+1;
    }

下面来一道例题,[ http://noi.openjudge.cn/ch0305/1551/ ]
题意:
给出一个整数集合s,找到集合中最大的d,让等式a+b+c=d成立,

其中,a,b,c,d是集合S中不同的元素

样例输入:
5

2

3

5

7

12

5

2

16

64

256

1024

0

样例输出:

12

no solution

思路:

a+b+c=d变为a+b=d-c。那么我们就可以通过枚举a+b与d-c的组合进行判断,这里对a+b构建哈希表,table[]数组判断地址使用。对具体值使用data[]数组保存。后来判断减法的时候进入hash函数分别对data[]以及table判断。成立时结束寻找。(即用加法找减法)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int ADD=536870911; //大质数 
int flag[1000020],in[1020],ha1[1000020],ha2[1000020],data[1000000];
int hashh(int key){
    int ad=((key%1000000)+10061894)%1000000; //ad=(kry%p+P(大质数))%p
    while(flag[ad]!=0){
        ad+=ad%11+1;
        if(ad>1000000) ad%=1000000;//注意不能超过数组 
    }
    return ad;
}

int find(int key){
    int ad=((key%1000000)+10061894)%1000000;
    while(data[ad]!=key&&flag[ad]!=0){
        ad+=ad%11+1;
        if(ad>1000000) ad%=1000000;
    }
    return flag[ad]==0?-1:ad;//找到空位置跳出(flag[ad]==0)或者因为 找到对应data[ad]==key(即找到对应的a+b时跳出) 
}

int main(){
    int n,maxx;
    while(scanf("%d",&n)!=EOF&&n!=0){
        memset(flag,0,sizeof(flag));
        maxx=-1;
        for(int i=1;i<=n;i++)
            scanf("%d",&in[i]);
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++){
                int ans=hashh(in[i]+in[j]);
                flag[ans]=1,ha1[ans]=in[i],ha2[ans]=in[j],data[ans]=in[i]+in[j];//保存a,b,a+b; 
            }

        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++){
                int ans=find(in[i]-in[j]);
                if(i==j||ans==-1) continue;
                if(ha1[ans]!=in[i]&&ha1[ans]!=in[j]&&ha2[ans]!=in[i]&&ha2[ans]!=in[j])//因为要求a,b,c,d 是不同元素 
                    maxx=max(maxx,in[i]); //最大的d值 
            }
        if(maxx!=-1) printf("%d\n",maxx);
        else printf("no solution\n");
    }


    return 0;
}

特殊的字符串hahs处理方法—–BKDRHASH:

公式:

Hashvalue[i]=(hashvalue[i-1]*p+str[i])%P
p是一个奇数,且必须大于26;
P是个较大的数
p与P必须互质

下面给一组常用的P :

1e9+7
1e9+9

为了更完美的解决冲突概率问题,下面使用更高级的方法:

双hash

构造两个字符串哈希函数:hash1(),hash2() 如果:hash1(str1)==hash1(str2) &&
hash2(str1)==hash2(str2) 可以断定:str1==str2;

一般双hash函数构造:
hash1[i]=(hash1[i-1]*p+idx(s[i]))%mod1
hash2[i]=(hash2[i-1]*p+idx(s[i]))%mod2
mod1一般取1e9+7,mod2一般取1e9+9
1000000007和1000000009是一对孪生素数,取它们,冲突的概率极低!

下面是BKDRHASH的写法:

未完待续

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值