Hash表

Hash表是什么?

Hash表是一种数据结构,可以提供快速的插入操作和查找操作。

优点:运算速度快,查找操作比树块。

缺点:基于数组的,创建后难以扩展,而且当Hash表基本被填满时,性能下降很严重,此外,Hash表无法顺序遍历。

如果不需要遍历数据,并且可以提前预测数据量大小,Hash表非常合适。

解决冲突的方法:

开放地址法:

包括线性探测、二次探测和再哈希法。

线性探测,就是冲突后移动到相邻的下一个位置,直到找到空位。此方法的缺点是数据容易聚集,使得聚集的数据范围越来越多。

二次探测:解决数据聚集的问题。二次探测中,冲突后移动的步数依次是x+i2,其中x为哈希运算值,i为依次去1,2,3,4……直到找到空位。二次探测消除了线性探测的聚集问题(原始聚集),但是却产生了另外一种聚集问题(二次聚集),因为二次探测算法产生的探测序列总是固定的。

再哈希法:为了消除原始聚集和二次聚集所提出的方法。再哈希法利用一个哈希函数来根据位置来改变步长。再哈希法要求表的容量是一个质数,防止函数只会循环探查几个固定的区域,找不到空位而崩溃。

链地址法: 在每个哈希表中国设置链表。

哈希函数:

哈希函数使用频繁,因此惩罚和除法不可取(可以采用移位操作)。

哈希函数的目的是得到关键字值的范围,用一种方法成数组的下标,哈希函数应该随机分布在整个哈希表。

随机关键字:index = key%arraySize,效果较好

非随机关键字:对于非随机分布的数据(如车牌、身份证号等),因为此类数据会集中在某一范围,应该采用合适的哈希法使结果随机分布在数组内。

几点要求:

不要使用无用数据

要体现所有数据

使用质数作为取模的技术

哈希化字符串:

将短小的字符串转换为数字,方法是每个数位乘以一个对应的常数的幂值。

哈希表解决冲突方法对比

方法

查找/插入

装填因子增大

线性探测

(1+1/(1-loadFactor)2)/2(成功查找)

(1+1/(1-loadFactor))/2 (不成功查找)

性能下降很严重(指数增长)

二次探测

Log2(1-loadFactor)/ loadFactor(成功查找)

1/(1-loadFactor)(不成功查找)

性能下降较严重(指数增长)

再哈希法

Log2(1-loadFactor)/ loadFactor(成功查找)

1/(1-loadFactor)(不成功查找)

性能下降较严重(指数增长)

链地址法

1+ loadFactor/2(无序)

1+loadFactor(有序)

线性增长

 

  1.开放地址法:容易产生堆积问题;不适于大规模的数据存储;对于小型的哈希表,再哈希法效果较好。如果装填因子低于0.5,线性探测更容易实现,而且性能几乎不下降。

     2.链地址法:处理冲突简单,且无堆积现象,平均查找长度短;适合填入项数未知的情况。

哈希表知识点汇总

  1. 哈希表基于数组
  2. 关键字值范围比数组容量大
  3. 关键字值通过哈希函数映射为数组下标
  4. 一个关键字哈希化到已占用的数组单元,叫做冲突
  5. 冲突解决方法:开发地址法和链地址法
  6. 开放地址法中,冲突的数据放在数组的其他位置
  7. 开放地址法包括:线性探测、二次探测和再哈希法
  8. 找到一个特定项所需要的步数叫做探测长度
  9. 线性探测步长总是为1
  10. 线性探测中,会出现首次聚集
  11. 二次探测中,步长是步数的平方,能够消除首次聚集,但是产生二次聚集
  12. 二次聚集的危害相对小,造成二次聚集的原因是是步长只依赖与哈希值,与关键字无关
  13. 再哈希法中,步长通过第二个哈希函数得到,依赖于关键字,能够消除二次聚集
  14. 装填因子=数据项/数组容量
  15. 开放地址法最大装填因子应该在0.5附近,采用再哈希法查找探测长度是2.0
  16. 开放地址法中,装填因子接近1,查找时间接近无限,因此·采用开放地址法中哈希表不能太满
  17. 链地址法中,每个数组单元包含一个链表,相同位置的数据都插入此链表
  18. 链地址法中,装填因子为1比较合适,此时成功的探测长度是1.5,不成功是2.0
  19. 链地址法探测长度随着装填因子变大线性增长
  20. 字符串哈希化,每个字符乘以常数不同次幂,求和,去模(防止溢出)
  21. 哈希表的熔炼通常是个质数,这在二次探测和再哈希法中很重要

Hash表的实现:

线性地址法:

  1 package dataStructure;
  2 //线性地址法
  3 import java.util.Scanner;
  4 
  5 class DataItem{
  6     private int iData;         //key
  7     public DataItem(int data){//构造
  8         iData = data;
  9     } 
 10     public int getKey(){
 11         return iData;
 12     }
 13 }
 14 
 15 //线性探测法
 16 public class HashTable {
 17     
 18     
 19     private DataItem[] hashArray;    //hash表
 20     private int arraySize;    //表大小
 21     private DataItem nonItem;    //空节点 
 22     
 23     public HashTable(int size){//构造
 24         arraySize = size;
 25         hashArray = new DataItem[arraySize];
 26         nonItem = new DataItem(-1);//删除的节点置为-1
 27     }
 28     
 29     public void displayTable(){
 30         System.out.print("Table: ");
 31         for(int j=0; j<arraySize; j++){
 32             if(hashArray[j] != null)
 33                 System.out.print(hashArray[j].getKey() + " ");
 34             else
 35                 System.out.print("** ");
 36         }
 37         System.out.println(" ");
 38     }
 39     
 40     public int hashFunc(int key){
 41         return key % arraySize;        //哈希函数
 42     }
 43     
 44     public DataItem find(int key){
 45         int hashVal = hashFunc(key);
 46         
 47         while(hashArray[hashVal] != null){
 48             if(hashArray[hashVal].getKey() == key)
 49                 return hashArray[hashVal];
 50             ++hashVal; 
 51             hashVal %= arraySize;
 52         }
 53         return null;
 54     }
 55     
 56     public void insert(DataItem item){
 57         int key = item.getKey();
 58         int hashVal = hashFunc(key);
 59         
 60         while(hashArray[hashVal] != null &&    hashArray[hashVal].getKey() != -1){
 61             ++hashVal;
 62             hashVal %= arraySize;
 63         }
 64         hashArray[hashVal] = item;
 65     }
 66     
 67     public DataItem delete(int key){
 68         int hashVal = hashFunc(key);
 69         while(hashArray[hashVal] != null){
 70             if(hashArray[hashVal].getKey() == key){
 71                 DataItem temp = hashArray[hashVal];
 72                 hashArray[hashVal] = nonItem;
 73                 return temp;                    //弹出删除的item
 74             }
 75             ++hashVal;
 76             hashVal %= arraySize;
 77         }
 78         return null;
 79     }
 80     
 81     
 82     /**
 83      * @param args
 84      */
 85     public static void main(String[] args) {
 86         
 87         int aKey, size, n, keysPerCell;
 88         System.out.println("Enter size of hash table: ");
 89         Scanner out = new Scanner(System.in);
 90         size = out.nextInt();
 91         System.out.println("Enter initial number of items: ");
 92         n = out.nextInt();
 93         keysPerCell = 10;
 94         HashTable theHashTable = new HashTable(size);
 95         
 96         for(int j=0; j<n; j++){    //插入元素
 97             DataItem aDataItem;
 98             aKey = (int) (Math.random() * keysPerCell * size);
 99             aDataItem = new DataItem(aKey);
100             theHashTable.insert(aDataItem);
101         }
102         
103         while(true){
104             System.out.println("Enter first letter of ");
105             System.out.println("show, intsert, delete, or find: ");
106             Scanner in = new Scanner(System.in);
107             char choice = in.next().charAt(0);
108             switch(choice){
109             case 's':
110                 theHashTable.displayTable();
111                 break;
112             case 'i':
113                 System.out.print("Enter key value to insert: ");
114                 Scanner keyIn = new Scanner(System.in);
115                 aKey = keyIn.nextInt();
116                 theHashTable.insert(new DataItem(aKey));
117                 break;
118             case 'd':
119                 System.out.print("Enter key value to delete: ");
120                 Scanner keyDel = new Scanner(System.in);
121                 aKey = keyDel.nextInt();
122                 theHashTable.delete(aKey);
123                 break;
124             case 'f':
125                 System.out.print("Enter key value to find: ");
126                 Scanner keyFind = new Scanner(System.in);
127                 aKey = keyFind.nextInt();
128                 DataItem aDataItem;
129                 aDataItem = theHashTable.find(aKey);
130                 if(aDataItem != null){
131                     System.out.print("Found " + aKey);
132                 }
133                 else
134                     System.out.print("Could not find " + aKey);
135                 break;
136                 default:
137                     System.out.print("Invalid entry\n");
138             }
139         }
140     }
141 
142 }
View Code

再哈希法:

  1 package dataStructure;
  2 
  3 import java.util.Scanner;
  4 //再hash法
  5 
  6 public class HashTable2 {
  7     private DataItem[] hashArray;    //hash表
  8     private int arraySize;    //表大小
  9     private DataItem nonItem;    //空节点 
 10     
 11     public HashTable2(int size){//构造
 12         arraySize = size;
 13         hashArray = new DataItem[arraySize];
 14         nonItem = new DataItem(-1);//删除的节点置为-1
 15     }
 16     
 17     public void displayTable(){
 18         System.out.print("Table: ");
 19         for(int j=0; j<arraySize; j++){
 20             if(hashArray[j] != null)
 21                 System.out.print(hashArray[j].getKey() + " ");
 22             else
 23                 System.out.print("** ");
 24         }
 25         System.out.println(" ");
 26     }
 27     
 28     public int hashFunc(int key){
 29         return key % arraySize;        //哈希函数
 30     }
 31     
 32     public int hashFunc2(int key){
 33         return 5-key%5;
 34     }
 35     
 36     public void insert(DataItem item){
 37         int key = item.getKey();
 38         int hashVal = hashFunc(key);
 39         int stepSize = hashFunc2(key);
 40         
 41         while(hashArray[hashVal] != null &&    hashArray[hashVal].getKey() != -1){
 42             hashVal += stepSize;
 43             hashVal %= arraySize;
 44         }
 45         hashArray[hashVal] = item;
 46     }
 47     
 48     public DataItem delete(int key){
 49         int hashVal = hashFunc(key);
 50         int stepSize = hashFunc2(key);
 51         
 52         while(hashArray[hashVal] != null){
 53             if(hashArray[hashVal].getKey() == key){
 54                 DataItem temp = hashArray[hashVal];
 55                 hashArray[hashVal] = nonItem;
 56                 return temp;                    //弹出删除的item
 57             }
 58             hashVal += stepSize;
 59             hashVal %= arraySize;
 60         }
 61         return null;
 62     }
 63     
 64     public DataItem find(int key){
 65         int hashVal = hashFunc(key);
 66         int stepSize = hashFunc2(key);
 67         
 68         while(hashArray[hashVal] != null){
 69             if(hashArray[hashVal].getKey() == key)
 70                 return hashArray[hashVal];
 71             hashVal += stepSize;
 72             hashVal %= arraySize;
 73         }
 74         return null;
 75     }
 76     
 77 public static void main(String[] args) {
 78         
 79         int aKey, size, n, keysPerCell;
 80         System.out.println("Enter size of hash table: ");
 81         Scanner out = new Scanner(System.in);
 82         size = out.nextInt();
 83         System.out.println("Enter initial number of items: ");
 84         n = out.nextInt();
 85         keysPerCell = 10;
 86         HashTable2 theHashTable = new HashTable2(size);
 87         
 88         for(int j=0; j<n; j++){    //插入元素
 89             DataItem aDataItem;
 90             aKey = (int) (Math.random() * keysPerCell * size);
 91             aDataItem = new DataItem(aKey);
 92             theHashTable.insert(aDataItem);
 93         }
 94         
 95         while(true){
 96             System.out.println("Enter first letter of ");
 97             System.out.println("show, intsert, delete, or find: ");
 98             Scanner in = new Scanner(System.in);
 99             char choice = in.next().charAt(0);
100             switch(choice){
101             case 's':
102                 theHashTable.displayTable();
103                 break;
104             case 'i':
105                 System.out.print("Enter key value to insert: ");
106                 Scanner keyIn = new Scanner(System.in);
107                 aKey = keyIn.nextInt();
108                 theHashTable.insert(new DataItem(aKey));
109                 break;
110             case 'd':
111                 System.out.print("Enter key value to delete: ");
112                 Scanner keyDel = new Scanner(System.in);
113                 aKey = keyDel.nextInt();
114                 theHashTable.delete(aKey);
115                 break;
116             case 'f':
117                 System.out.print("Enter key value to find: ");
118                 Scanner keyFind = new Scanner(System.in);
119                 aKey = keyFind.nextInt();
120                 DataItem aDataItem;
121                 aDataItem = theHashTable.find(aKey);
122                 if(aDataItem != null){
123                     System.out.print("Found " + aKey);
124                 }
125                 else
126                     System.out.print("Could not find " + aKey);
127                 break;
128                 default:
129                     System.out.print("Invalid entry\n");
130             }
131         }
132     }
133 }
View Code

链地址法:

  1 package dataStructure;
  2 
  3 import java.util.Scanner;
  4 
  5 //链地址法
  6 class Link{
  7     private int iData;
  8     public Link next;
  9     public Link(int data){
 10         iData = data;
 11     }
 12     
 13     public int getKey(){
 14         return iData;
 15     }
 16     
 17     public void displayLink(){
 18         System.out.print(iData + " ");
 19     }
 20 
 21 }
 22 
 23 class SortedList{
 24     private Link first;
 25     public void sortedList(){
 26         first = null;
 27     }
 28     
 29     public void insert(Link theLink){
 30         int key = theLink.getKey();
 31         Link previous = null;
 32         Link current = first;
 33         
 34         while(current != null && key > current.getKey()){//找到要插入的位置
 35             previous = current;
 36             current = current.next;
 37         }
 38         if(previous == null)//如果链表为空,放在第一个位置
 39             first = theLink;
 40         else
 41             previous.next = theLink;
 42         theLink.next = current;
 43     }
 44     
 45     public void delete(int key){
 46         Link previous = null;
 47         Link current = first;
 48         
 49         while(current != null && key != current.getKey()){//移动到要删除的位置
 50             previous = current;
 51             current = current.next;
 52         }
 53         
 54         if(previous == null)//要删除的是第一个
 55             first = first.next;
 56         else
 57             previous.next = current.next;
 58     }
 59     
 60     public Link find(int key){
 61         Link current = first;
 62         
 63         while(current != null && current.getKey() <= key){
 64             if(current.getKey() == key)
 65                 return current;
 66             current = current.next;
 67         }
 68         return null;
 69     }
 70     
 71     public void displayList(){
 72         System.out.println("List first to last:");
 73         Link current = first;
 74         while(current != null){
 75             current.displayLink();
 76             current = current.next;
 77         }
 78         System.out.println();
 79     }
 80 }
 81 
 82 public class HashTable3 {
 83     private SortedList[] hashArray;
 84     private int arraySize;
 85     
 86     public HashTable3(int size){
 87         arraySize = size;
 88         hashArray = new SortedList[arraySize];
 89         for(int j=0; j<arraySize; j++)
 90             hashArray[j] = new SortedList();
 91     }
 92     
 93     public void displayTable(){
 94         for(int j=0; j<arraySize; j++){
 95             System.out.print(j + " ");//打印号
 96             hashArray[j].displayList();
 97         }
 98     }
 99     
100     public int hashFunc(int key){
101         return key%arraySize;
102     }
103     
104     public void insert(Link theLink){
105         int key = theLink.getKey();
106         int hashVal = hashFunc(key);
107         hashArray[hashVal].insert(theLink);
108     }
109     
110     public void delete(int key){
111         int hashVal = hashFunc(key);
112         hashArray[hashVal].delete(key);
113     }
114     
115     public Link find(int key){
116         int hashVal = hashFunc(key);
117         Link theLink = hashArray[hashVal].find(key);
118         return theLink;
119     }
120     
121 public static void main(String[] args) {
122         
123         int aKey, size, n, keysPerCell;
124         System.out.println("Enter size of hash table: ");
125         Scanner out = new Scanner(System.in);
126         size = out.nextInt();
127         System.out.println("Enter initial number of items: ");
128         n = out.nextInt();
129         keysPerCell = 10;
130         HashTable3 theHashTable = new HashTable3(size);
131         
132         for(int j=0; j<n; j++){    //插入元素
133             Link aDataItem;
134             aKey = (int) (Math.random() * keysPerCell * size);
135             aDataItem = new Link(aKey);
136             theHashTable.insert(aDataItem);
137         }
138         
139         while(true){
140             System.out.println("Enter first letter of ");
141             System.out.println("show, intsert, delete, or find: ");
142             Scanner in = new Scanner(System.in);
143             char choice = in.next().charAt(0);
144             switch(choice){
145             case 's':
146                 theHashTable.displayTable();
147                 break;
148             case 'i':
149                 System.out.print("Enter key value to insert: ");
150                 Scanner keyIn = new Scanner(System.in);
151                 aKey = keyIn.nextInt();
152                 theHashTable.insert(new Link(aKey));
153                 break;
154             case 'd':
155                 System.out.print("Enter key value to delete: ");
156                 Scanner keyDel = new Scanner(System.in);
157                 aKey = keyDel.nextInt();
158                 theHashTable.delete(aKey);
159                 break;
160             case 'f':
161                 System.out.print("Enter key value to find: ");
162                 Scanner keyFind = new Scanner(System.in);
163                 aKey = keyFind.nextInt();
164                 Link aDataItem;
165                 aDataItem = theHashTable.find(aKey);
166                 if(aDataItem != null){
167                     System.out.print("Found " + aKey);
168                 }
169                 else
170                     System.out.print("Could not find " + aKey);
171                 break;
172                 default:
173                     System.out.print("Invalid entry\n");
174             }
175         }
176     }
177 }
View Code

 

posted @ 2017-11-17 15:56  大尾巴贝贝  阅读(403)  评论(0编辑  收藏  举报