Hash算法:双重散列

  双重散列线性开型寻址散列开放寻址法)中的冲突解决技术。双重散列使用在发生冲突时将第二个散列函数应用于的想法。

  此算法使用:

     (hash1(key) + i * hash2(key)) % TABLE_SIZE 

  来进行双哈希处理。hash1()hash2() 是哈希函数,而 TABLE_SIZE 是哈希表的大小。当发生碰撞时,我们通过重复增加 步长i 来寻找键。

  第一个Hash函数:hash1(key) = key % TABLE_SIZE

1     /**
2      * 计算首次的Hash值
3      *
4      * @param key
5      * @return
6      */
7     private int hash1(int key) {
8         return (key % TABLE_SIZE);
9     }

  第二个Hash函数是:hash2(key) = PRIME – (key % PRIME),其中 PRIME 是小于 TABLE_SIZE 的质数

1     /**
2      * 发生碰撞是时继续计算Hash值
3      *
4      * @param key
5      * @return
6      */
7     private int hash2(int key) {
8         return (PRIME - (key % PRIME));
9     }

  第二个Hash函数表现好的特征:

  • 绝对不会产生 0 索引
  • 能在整个HashTable 循环探测
  • 计算会快点
  • 与第一个Hash函数互相独立
  • PRIME 与 TABLE_SIZE 是 “相对质数”

  

Java实现代码:

  1 package algorithm.hash;
  2
  3 /**
  4  *  双重哈希
  5  */
  6 public class DoubleHash {
  7     private static final int TABLE_SIZE = 13;   // 哈希表大小
  8     private static int PRIME = 7;               // 散列函数值
  9
 10     private int[] hashTable;
 11     private int curr_size;                      // 当前表中存的元素
 12
 13     public DoubleHash() {
 14         this.hashTable = new int[TABLE_SIZE];
 15         this.curr_size = 0;
 16         for (int i = 0; i < TABLE_SIZE; i++)
 17             hashTable[i] = -1;
 18     }
 19
 20     private boolean isFull() {
 21         return curr_size == TABLE_SIZE;
 22     }
 23
 24     /**
 25      * 计算首次的Hash值
 26      *
 27      * @param key
 28      * @return
 29      */
 30     private int hash1(int key) {
 31         return (key % TABLE_SIZE);
 32     }
 33
 34     /**
 35      * 发生碰撞是时继续计算Hash值
 36      *
 37      * @param key
 38      * @return
 39      */
 40     private int hash2(int key) {
 41         return (PRIME - (key % PRIME));
 42     }
 43
 44     /**
 45      * 向Hash表中存值
 46      *
 47      * @param key
 48      */
 49     private void insertHash(int key) {
 50         /* 表是否已满 */
 51         if (isFull()) {
 52             return;
 53         }
 54
 55         /* 获取首次的Hash值 */
 56         int index = hash1(key);
 57
 58         // 如果发生碰撞
 59         if (hashTable[index] != -1) {
 60             /* 计算第二次的Hash值 */
 61             int index2 = hash2(key);
 62             int i = 1;
 63             while (true) {
 64                 /* 再次合成新的地址 */
 65                 int newIndex = (index + i * index2) % TABLE_SIZE;
 66
 67                 // 如果再次寻找时没有发生碰撞,把key存入表中的对应位置
 68                 if (hashTable[newIndex] == -1) {
 69                     hashTable[newIndex] = key;
 70                     break;
 71                 }
 72                 i++;
 73             }
 74         } else {
 75             // 一开始没有发生碰撞
 76             hashTable[index] = key;
 77         }
 78         curr_size++;    // Hash表中当前所存元素数量加1
 79     }
 80
 81     /**
 82      * 打印Hash表
 83      */
 84     private void displayHash() {
 85         for (int i = 0; i < TABLE_SIZE; i++) {
 86             if (hashTable[i] != -1)
 87                 System.out.println(i + " --> " + hashTable[i]);
 88             else
 89                 System.out.println(i);
 90         }
 91     }
 92
 93     public static void main(String[] args) {
 94         int[] a = {19, 27, 36, 10, 64};
 95
 96         DoubleHash doubleHash = new DoubleHash();
 97         for (int i = 0; i < a.length; i++)
 98             doubleHash.insertHash(a[i]);
 99
100         doubleHash.displayHash();
101     }
102
103 }

原文地址:https://www.cnblogs.com/magic-sea/p/12003883.html

时间: 2024-07-30 09:13:30

Hash算法:双重散列的相关文章

非对称算法,散列(Hash)以及证书的那些事

转载请注明出处 http://blog.csdn.net/pony_maggie/article/details/35389657 作者:小马 这几个概念在金融电子支付领域用得比较多,我忽然觉得把它们串起来一起讲,层层引入,可能更好理解一些.希望能以最简单朴实的方式讲明白他们之间的关系. 一非对称算法 关于非对称算法,你只要知道下面这些就行了,密钥是一对,一个叫公钥,一个叫私钥,前者公开,后者保密.假设你有一对公私钥,给你一串数据,你可以用私钥加密,然后把密文和公钥都放出去,别人可以用这个公钥解

散列(2)线性探测法和双重散列法

接上篇 散列的简要描述和链地址法 解决散列冲突的方法: 1. 线性探测法 如果我们能够预测将要存入表中元素的数目,而且我们有足够的内存空间可以容纳带有空闲空间的所有关键字,那么使用链地址法是不值得的.我们依靠空的存储空间解决冲突:设计表长M大于元素数目N,开放地址法,最简单的开放地址法是线性探测法: 初始化 该符号表的实现将元素保存到大小是元素个数两倍的散列表中. void HashTableInit(int max) { N = 0; M = 2*max; hash_table = new I

--算法分析与设计--课程作业--【顺序统计】--【采用链表法散列表】--【开放地址法(双重散列)】

本次作业大力感谢以下量 参考信息 经典算法总结之线性时间做选择 http://www.cnblogs.com/javaspring/archive/2012/08/17/2656208.html 11.4 双重散列法 : http://blog.csdn.net/zixiawzm/article/details/6746946 [未完待续]

散列算法与散列码

一.引入 1 /** 2 * Description:新建一个类作为map的key 3 */ 4 public class Groundhog 5 { 6 protected int number; 7 8 public Groundhog(){ 9 } 10 public Groundhog(int number) 11 { 12 this.number = number; 13 } 14 15 @Override 16 public String toString() 17 { 18 ret

数据结构与算法之散列

散列 基于数组进行设计的数据结构 优点:可以快速插入,删除和取用数据 缺点:查找操作效率低下 在使用散列表存储数据时,通过一个散列函数将键映射为一个数字,这个数字的范围是0到散列表的长度.理想情况下从key到index应该是一一对应的,然而键的数量可以是无限的,而数组长度是有限的,因此一个更现实的目标是让散列函数尽量均匀地映射到数组中(即让两个或多个key对于1个index,这种现象称为碰撞). 对数组大小常见的限制是: 数组长度应该是一个质数.也会有多种确定数组大小的策略, 所有的策 略都基于

双重散列法http://blog.csdn.net/zixiawzm/article/details/6746946

#include <iostream>#include <math.h>#include <stdlib.h>#include <time.h>#include <windows.h> #define slot_size 100000 //散列槽的大小#define arr_size 80000 //动态关键字集合#define min_size 0 //动态关键字集合的最小值#define max_size 999 #define total_

Hash算法总结

1. Hash是什么,它的作用 先举个例子.我们每个活在世上的人,为了能够参与各种社会活动,都需要一个用于识别自己的标志.也许你觉得名字或是身份证就足以代表你这个人,但是这种代表性非常脆弱,因为重名的人很多,身份证也可以伪造.最可靠的办法是把一个人的所有基因序列记录下来用来代表这个人,但显然,这样做并不实际.而指纹看上去是一种不错的选择,虽然一些专业组织仍然可以模拟某个人的指纹,但这种代价实在太高了. 而对于在互联网世界里传送的文件来说,如何标志一个文件的身份同样重要.比如说我们下载一个文件,文

hash算法学习

1. Hash是什么,它的作用 先举个例子.我们每个活在世上的人,为了能够参与各种社会活动,都需要一个用于识别自己的标志.也许你觉得名字或是身份证就足以代表你这个人,但是这种代表性非常脆弱,因为重名的人很多,身份证也可以伪造.最可靠的办法是把一个人的所有基因序列记录下来用来代表这个人,但显然,这样做并不实际.而指纹看上去是一种不错的选择,虽然一些专业组织仍然可以模拟某个人的指纹,但这种代价实在太高了. 而对于在互联网世界里传送的文件来说,如何标志一个文件的身份同样重要.比如说我们下载一个文件,文

算法导论-散列表(Hash Table)

目录 引言 直接寻址 散列寻址 散列函数 除法散列 乘法散列 全域散列 完全散列 碰撞处理方法 链表法 开放寻址法 线性探查 二次探查 双重散列 随机散列 再散列问题 完整源码(C++) 参考资料 内容 1.引言 如果想在一个n个元素的列表中,查询元素x是否存在于列表中,首先想到的就是从头到尾遍历一遍列表,逐个进行比较,这种方法效率是Θ(n):当然,如果列表是已经排好序的话,可以采用二分查找算法进行查找,这时效率提升到Θ(logn);  本文中,我们介绍散列表(HashTable),能使查找效率