哈希表
哈希表是一种使用哈希函数组织数据,以支持快速插入和搜索的数据结构。
有两种不同类型的哈希表:哈希集合和哈希映射。
哈希集合是Set数据结构的实现之一,用于存储非重复值。
哈希映射是Map数据结构的实现之一,用于存储(key, value)键值对。
1.设计哈希表
1.1 哈希表的原理
哈希表的关键思想是使用哈希函数将键映射到存储桶。
1.当我们插入一个新的键时,哈希函数将决定该键应该分配到哪个桶中,并将该键存储在相应的桶中;
2.当我们想要搜索一个键时,哈希表将使用相同的哈希函数来查找对应的桶,并只在特定的桶中进行搜索。
例如下边一个例子,哈希函数是: y%5

1.2 关键点
通过上边的介绍,可以得出,设计哈希表的两个关键点是 哈希函数 和 冲突解决。
上边介绍的例子, 以 y = x % 5 作为散列函数,其中 x 是键值,y 是分配的桶的索引。
1.2.1 散列函数:
散列函数的设计将取决于键值的范围和桶的数量。
下面是一些有代表性的哈希函数示例:

哈希函数的设计是一个很开发而且复杂的事情,其思想是尽可能将键分配到桶中,理想情况下,完美的哈希函数将是键和桶之间的一对一映射。然而,在大多数情况下,哈希函数并不完美,它需要在桶的数量和桶的容量之间进行权衡。
1.2.2 冲突解决:
理想情况下,如果我们的哈希函数是完美的一对一映射,我们将不需要处理冲突。不幸的是,在大多数情况下,冲突几乎是不可避免的。例如,在我们之前的哈希函数(y = x % 5)中,1987 和 2 都分配给了桶 2,这是一个冲突。
冲突解决算法应该解决以下几个问题:
- 如何组织在同一个桶中的值?
- 如果为同一个桶分配了太多的值,该怎么办?
- 如何在特定的桶中搜索目标值?
根据我们的哈希函数,这些问题与桶的容量和可能映射到同一个桶的键的数目有关。
让我们假设存储最大键数的桶有 N 个键。
通常,如果 N 是常数且很小,我们可以简单地使用一个数组将键存储在同一个桶中。如果 N 是可变的或很大,我们可能需要使用高度平衡的二叉树来代替.。
1.3 实现哈希集合和哈希映射:
不使用高级的数据结构,实现一个哈希集合,要求在注释中标明。
1 package leet_pro.ds; 2 3 /** 4 * @Title:MyHashSet 5 * @Description: 6 * 7 * 不使用任何内建的哈希表库设计一个哈希集合,具体地说,你的设计应该包含以下的功能: 8 * add(value):向哈希集合中插入一个值。 9 * contains(value) :返回哈希集合中是否存在这个值。 10 * remove(value):将给定值从哈希集合中删除。如果哈希集合中没有这个值,什么也不做。 11 * 12 * 注意: 13 * 所有的值都在 [0, 1000000]的范围内。 (值范围) 14 * 操作的总数目在[1, 10000]范围内。 (桶范围) 15 * 不要使用内建的哈希集合库。 16 * 17 * 示例: 18 * MyHashSet hashSet = new MyHashSet(); 19 * hashSet.add(1); 20 * hashSet.add(2); 21 * hashSet.contains(1); // 返回 true 22 * hashSet.contains(3); // 返回 false (未找到) 23 * hashSet.add(2); 24 * hashSet.contains(2); // 返回 true 25 * hashSet.remove(2); 26 * hashSet.contains(2); // 返回 false (已经被删除) 27 * 28 * @Author: natty 29 * @Version: 1.0 30 * @Date: 2020-02-07 00:14 31 */ 32 class MyHashSet { 33 private int bucketSize; //桶数 34 private int size; //桶容量 35 private int[][] array; //存储数据结构,二维数组 36 private boolean flag; //数值0不存储,flag为了判定0是否存在 37 38 /** Initialize your data structure here. */ 39 public MyHashSet() { 40 bucketSize = 10000; //桶数量 41 size = 100; //桶容量 42 array=new int[100][10000]; //数据存储结构 43 flag =false; 44 } 45 46 public void add(int key) { 47 if(key==0){ 48 flag=true; 49 return; 50 } 51 key = key - 1; //防止1000000存在在 array[100][0]而发生越界,前挪到array[99][9999]存储。 52 int bucket1=key/bucketSize; 53 int bucket2=key%bucketSize; 54 array[bucket1][bucket2]=key+1; 55 } 56 57 public void remove(int key) { 58 if(key==0){ 59 flag=false; 60 return; 61 } 62 key=key-1; 63 int bucket1=key/bucketSize; 64 int bucket2=key%bucketSize; 65 array[bucket1][bucket2]=0; 66 } 67 68 /** Returns true if this set contains the specified element */ 69 public boolean contains(int key) { 70 if(key==0){ 71 return flag; 72 } 73 key=key-1; 74 int bucket1=key/bucketSize; 75 int bucket2=key%bucketSize; 76 return key+1==array[bucket1][bucket2]; 77 } 78 79 }

浙公网安备 33010602011771号