[导入]散列表

散列表是普通数组的推广。

设计散列表主要是对哈希函数和处理冲突碰撞的选择和设计,好的哈希函数h可以使关键字比较均匀的散列在哈希表中,冲突较少。所谓“好”的哈希函数的主导思想,是使h尽可能地随机,减少碰撞,但是不可能完全避免碰撞,因为关键字域的势 |U|>m,m为散列表的槽数,总会有两个不同的关键字映射到同一个槽中,产生碰撞。

1、哈希函数

一个好的哈希函数应(近似地)满足简单一致散列的假设:每个关键字都等可能的散列到m个槽位的任何一个中去,并与其他的关键字已被散列到哪个槽位中无关。

不幸的是,一般情况下不太可能检查这一条件是否成立,因为人们很少能知道关键字所符合的概率分布,而各关键字可能并不是完全相互独立的。

算法导论中列举了四种哈希函数:直接定址法、除法散列法、乘法散列法和全域散列法。

其中除法散列法和乘法散列法利用了启发式的方法,第三个利用了随机化的技术。

a、除法散列法(模除法)

h(k)=k mod m

m的取值常常是与2的整数幂不太接近的质数(m是指散列表的槽数)。

b、乘法散列法

h(k)=|m*(k*A mod 1)| (取底)

用关键字k乘以常数A(0<A<1),并取出kA的小数部分。然后用m乘以这个值,对结果取底。

对 m 的选择没有特别的要求,一般选择为 2 的整数次幂

Knuth认为 A=(sqrt(5)-1)=0.6180339887......,取这个值比较理想

c、全域散列

h(k)=((a*k+b) mod p) mod m   (哈希函数族)

选择一个足够大的质数p,使得每一个可能的关键字k都落到0到p-1之间(包括0和p-1)。

Zp表示集合{0,1,……,p-1},Zp*表示集合{1,2,……,p-1}。

容易知道p>m(p>=|U|>m)

a属于Zp*,B属于Zp

从函数族中随机的选取一个作为哈希函数

d、在严蔚敏的数据结构中还介绍了其他的构造哈希函数的方法(比如平方取中法,折叠法等)

2、处理碰撞的方法

a、哈希链接法

把冲突的关键字存储在冲突槽的链表中

在简单一致散列的假设下,一次不成功查找的期望时间为O(1+α),平均情况下一次成功的查找也需要同样的时间

b、开放寻址法

线性探测    h(k,i)=(h'(k)+i) mod m,i=0,1,……,m-1

二次探测   h(k,i)=(h'(k)+c1*i+c2*i*i) mod m     严蔚敏的数据结构中 c1=0,c2=-1

双重哈希(再哈希法) h(k,i)=(h1(k)+i*h2(k)) mod m

每一个关键字的探查序列

<h(k,0),h(k,1),……,h(k,m-1)>    

直到探寻到合适的位置为止

c、完全散列法

基本思想比较简单,采用两级的散列方案,每一级都采用全域散列。

有点类似哈希链接法,只不过,在冲突槽的链表上再采用一次全域哈希。

d、严蔚敏的数据结构中还介绍了 建立一个公共溢出区 的方法

------------------------------------一个小例子(哈希链接法 处理冲突)-------------------------------------------------

/*
* 算法导论 第十一章 散列表
*
* 哈希函数:模除散列法
* 冲突避免:哈希链接法
* */

/* 输出:14 1

               1   0

*/

#include<stdio.h>
#include<stdlib.h>

struct hash_node{
struct hash_node *next;
int data;
};

struct hash_table{
struct hash_node *base;
unsigned int count;
unsigned int size;
};

unsigned int hash1(int key, int m)
{
/*int rt=-1;*/
return key%m;
}

unsigned int hash2(int key, int m)
{
return 1+(key%(m-1));
}

unsigned int hash(int key, int m, int i)
{
return (hash1(key,m)+i*hash2(key,m))%m;
}

void chain_insert(struct hash_table *tbl, int key)
{
unsigned int pos=-1;
struct hash_node *new_node=NULL;

new_node=(struct hash_node *)malloc(sizeof(struct hash_node));
new_node->data=key;
new_node->next=NULL;

pos=hash(key,tbl->size,0);

if(tbl[pos].count==0)
{
   tbl[pos].base=new_node;
   tbl[pos].count += 1;
}
else
{
   new_node->next=tbl[pos].base;
   tbl[pos].base=new_node;
   tbl[pos].count += 1;
}
}

void chain_search(struct hash_table *tbl, int key, unsigned int *row,unsigned int *col)
{
int i=0;
int idx=-1;
struct hash_table tb;

idx=hash(key,tbl->size,0);

if(tbl[idx].count > 0)
{
   tb=tbl[idx];
   while(tb.base!=NULL && tb.base->data!=key)
   {
    tb.base=tb.base->next;
    i += 1;
   }
  
   *row=idx;
   *col=i;
  
   if(tb.base==NULL)
   {
    *row=-1;
    *col=-1;
   }
}
else
{
   *row=-1;
   *col=-1;
}
}

#define m 13

int main()
{
int i=0;
int row, col;
struct hash_table tbl[m];

for(i=0;i<m;i++)
{
   tbl[i].base=NULL;
   tbl[i].count=0;
   tbl[i].size=m;
}
chain_insert(tbl,1);
chain_insert(tbl,14);
chain_search(tbl,14,&row,&col);

printf("%d ",tbl[1].base->data);
printf("%d ",tbl[1].base->next->data);
printf("\n%d %d\n",row,col);

return 0;
}

阅读全文
类别:算法 查看评论
文章来源:http://hi.baidu.com/janqii/blog/item/68f8d9f87233052e4f4aea5c.html

posted on 2010-04-27 23:48 janqii 阅读(233) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


导航

统计

常用链接

留言簿

随笔档案(15)

搜索

最新评论

阅读排行榜

评论排行榜