zoukankan      html  css  js  c++  java
  • 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
    ");
    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
    ");
    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
    ");
    174             }
    175         }
    176     }
    177 }
    View Code
  • 相关阅读:
    INI配置文件的格式
    MFC的DLL中实现定时器功能
    三维数组的动态申请与释放
    bat批处理,实现获取目录
    windows 系统变量
    php分享二十一:mysql语句
    php分享二十:mysql优化
    php分享十九:网络带宽预估
    php分享十七:http状态码
    从“什么是程序化购买”到“程序化购买+”
  • 原文地址:https://www.cnblogs.com/feichangnice/p/7852030.html
Copyright © 2011-2022 走看看