哈希查找要用到的概念:
哈希查找:在记录的存储地址和它关键字之间建立一个确定的对应关系。不经过比较,一次存取就能得到所查元素的查找方法。
哈希函数:在记录的关键字与记录的存储地址之间建立的一种对应关系叫哈希函数。
哈希表:应用哈希函数,由记录的关键字确定记录在表中的地址,并将记录放入此地址,这样构成的表叫哈希表。
利用哈希函数进行查找的过程叫哈希查找
冲突:对于不同的关键字ki、kj。若ki != kj,但H(ki)=H(kj)的现象。
哈希函数的设计要求:应该是简单的,能在短时间内计算出结果。并且能存储全部关键字。
一般来说,我们采用除留余数法作为哈希函数的设计。即H(key) = key % p(其中p<= m、m为表长且p为不大于m的素数或是不含20以下的质因子),这样设计是为了减少冲突的可能。
比如说有一组关键字为:
12 39 18 24 33 21 ,若p = 9,则他们对应的哈希函数值为:
3 3 0 6 6 3
这样会出现12、39、21发生冲突,24和33发生冲突。冲突的可能性就增大了。
为了处理除留余数法的冲突现象。我们需要定一个规则,将39、24、33、21放入应该放的位置。一般来说,有以下规则:
1、开放定址法。
2、再哈希法。
3、链地址法。
开放地址法:
为产生冲突的地址H(key)求得一个地址序列:H0、H1…HS
Hi = [H(key) + di] % m,其中m为哈希表长。
当di取1,2,3…m-1时,称为线性探测再散列
当di取1,-1,4,-4,9,-9,25…时,称为二次探测再散列
当di取随机数时,称为伪随机探测再散列。
假设关键字集合为{19,1,23,14,55,68,11,82,36},m=11【表长】
采用线性探测再散列,最后的结果是:
0 1 2 3 4 5 6 7 8 9 10
55 1 23 14 68 11 82 36 19
查找次数 1 1 2 1 3 6 2 5 1
采用二次探测再散列,最后的结果是:
0 1 2 3 4 5 6 7 8 9 10
55 1 23 14 36 82 68 19 11
伪随机就是产生随机数然后去探测,原理与上述两种方法类似,就不赘述。
链地址法:
将所有哈希地址相同的记录都链接在同一链表中。假设还是上述的关键字集合。采用表后插入的方式:
采用表头插入的方式:
一般来说,表后插入需要做查找,而表头插入不需要,所以一般采用表头插入的方式。以减少时间消耗
假设哈希函数为关键字求模,哈希表用链地址法解决冲突。下面演示算法实现:
// 链
class List {
Node head;
}
// 链中结点
class Node {
int data;
Node next;
}
// 用于创建哈希链表
public static List[] createHash(int[] a) {
List[] lists = new List[11];
for (int i = 0; i < lists.length; i++) {
lists[i] = new List();
lists[i].head = new Node();
}
for (int i = 0; i < a.length; i++) {
int model = a[i] % 11;
Node next = new Node();
next.data = a[i];
Node head = lists[model].head;
Node node = head.next;
next.next = node;
head.next = next;
}
return lists;
}
// 查找关键字,返回查找次数
public static int findKey(List[] lists, int key) {
int index = 0;
for (int i = 0; i < lists.length; i++) {
Node head = lists[i].head;
Node next = head.next;
while (next != null) {
if(next.data == key)
return index;
index ++;
next = next.next;
}
}
return -1;
}
int[] a = new int[] { 19, 1, 23, 14, 55, 68, 11, 82, 36 };
int key = 55;
List[] lists = createHash(a);
System.out.println("哈希表内容为:");
for (int i = 0; i < lists.length; i++) {
Node head = lists[i].head;
Node next = head.next;
while (next != null) {
System.out.print(next.data + "->");
next = next.next;
}
System.out.println();
}
int position = findKey(lists, key);
System.out.println("查找次数为:" + position);
程序运行结果:
哈希表内容为:
11->55->
23->1->
68->
36->14->
82->
19->
查找次数为:1