可并堆,离散优化以及HASH表,线段树总结
来源:互联网 发布:mac装不了软件说版本低 编辑:程序博客网 时间:2024/06/01 11:39
最近学了点数据结构,觉得有必要总结一下。
下面首先是离散优化:
离散化,把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。
例如:
原数据: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的写法:
未完待续
- 可并堆,离散优化以及HASH表,线段树总结
- 离散hash优化总结
- 平衡树?可并堆?线段树!
- [BZOJ 2809][Apio2012]dispatching:可持久化线段树|可并堆
- 【dp+离散化+线段树优化】Paint
- 可并堆之左偏树总结
- POJ2528 线段树+离散化+hash(成段更新)
- HDU 1264(离散化线段树;hash暴力)
- poj 2528 Mayor's posters (线段树+离散化+hash)
- bzoj2333 棘手的操作 可并堆or dfs序列+线段树
- bzoj 2333: [SCOI2011]棘手的操作(线段树+离线操作,可并堆+set)
- [BZOJ2333][SCOI2011]棘手的操作(可并堆||线段树+离线)
- [BZOJ2333][SCOI2011]棘手的操作(可并堆||线段树)
- poj2104 K-th Number 离散+可持久化线段树
- HDU1512 可并堆
- 【模板】可并堆
- 可并堆?左偏树?
- 可并堆模板
- 星星评论
- MongoDB常用命令汇总之数据库常用命令。
- sort函数的第三个参数cmp
- Leetcode 94 Binary Tree Inorder Traversal
- 文本样式
- 可并堆,离散优化以及HASH表,线段树总结
- 变换
- [BZOJ 2429] 聪明的猴子 Kruskal+贪心
- Mysql 批量插入 事务插入 性能对比
- sql多表查询分组最大值
- list容器2
- 浅谈数位DP
- 成为java高级工程师需要什么
- POJ2676-搜索-Sudoku