zoukankan      html  css  js  c++  java
  • 哈希哈希

    前言:
      哈希表(Hash Table)也叫散列表,是一种用于快速存取的数据结构。其内部实现是通过把键(key)码映射到表中的一个位置来访问记录,其中的“映射”也就是哈希函数,而“表”即哈希表。本文将重点介绍实现哈希表的2种方法:拉链法和线性探测法。

    1.实验数据

    A 2
    C 1
    B 6
    B 11
    H 1
    J 3
    数据说明:为了跟前面博文保持一致,本文的数据依然采用键值对(Key-Value)的形式。哈希表中主要有"存"和"取"操作。前者为:void put(Key key,Value);后者为: Value get(Key key);执行put操作时,如果数据已经存在则更新为新数据。

    2.HashMap实现

      实现哈希表主要分以下两步:
    step1:定义哈希函数
      哈希函数的实现不唯一,在此我们以java自带的hashCode()为基础进行修改。(对hashCode()底层实现感兴趣的朋友可另找资料进行了解~)

    public int hash(Key key){
            return (key.hashCode() & 0x7fffffff)%M;
        }

    step2:解决哈希冲突
      当出现 hash(k1)== hash(k2)时,即产生冲突。
    解决方法一(拉链法):因为哈希值相等,我们可以将k1,k2利用链表 st 进行存储。即,凡是hash(x)相等的x都存入同一链表。当要进行查找操作时,先利用hash(x)定位到链表st[hash(x)],再通过顺序链表遍历进行查找。
    解决方法二(线性探测法):利用两张足够大的哈希表 keys[M]和Values[M](其中,M>=2*N),当出现冲突之后,顺势循环向下遍历查找还没有存放 key 的keys[hash(key)],直到找到keys[hash(key)]==null为止。
    ------------

    拉链法与线性探测法的存储比较:

    3.Java代码实现
    a.拉链法code:

     1 package com.gdufe.hash;
     2 
     3 import java.io.File;
     4 import java.util.Scanner;
     5 
     6 public class SequenceChain<Key,Value>{
     7 
     8     private int N;
     9     private int M;
    10     private SequentialSearch<Key, Value> []st;
    11     
    12     public SequenceChain() {
    13         this(997);
    14     }
    15     String s;
    16     public SequenceChain(int M){
    17         this.M = M;        //赋值M
    18         st = (SequentialSearch<Key,Value>[]) new SequentialSearch[M];
    19         for(int i=0;i<M;i++)
    20             st[i] = new SequentialSearch();    //初始化
    21     }
    22     
    23     public int hash(Key key){    //自定义哈希,防止哈希值为负
    24         return (key.hashCode() & 0x7fffffff) % M;   
    25     }
    26     public void put(Key key,Value value){
    27         st[hash(key)].put(key, value);
    28     }
    29     public Value get(Key key){
    30         return st[hash(key)].get(key);
    31     }
    32     
    33     public static void main(String[] args) throws Exception{
    34         Scanner input = new Scanner(new File("data_hash.txt"));
    35         SequenceChain<String, Integer> sequence = new SequenceChain<String, Integer>();
    36         while(input.hasNext()){
    37             String key = input.next();
    38             int value = input.nextInt();
    39             sequence.put(key, value);
    40         }
    41         input.close();    //关闭控制台输入
    42         System.out.println("-----output----");
    43         System.out.println(sequence.get("H"));
    44         System.out.println(sequence.get("B"));
    45         
    46     }
    47 
    48 }

    辅助数据结构---顺序链表code:

     1 package com.gdufe.hash;
     2 
     3 import java.io.File;
     4 import java.util.Scanner;
     5 
     6 public class SequentialSearch<Key,Value> {
     7     
     8     private Node root;    //顺序链表的根root
     9     class Node{
    10         Key key;
    11         Value value;
    12         Node next;
    13         public Node(Key key,Value value){
    14             this.key=key;
    15             this.value=value;
    16         }
    17     }
    18     //在表头新增结点
    19     public void put(Key key,Value value){
    20         if(get(key)!=null){            //更新即可
    21             for(Node x=root;x!=null;x=x.next){
    22                 if(x.key.equals(key)){
    23                     x.value=value;
    24                     return;
    25                 }
    26             }
    27         }
    28         Node h = new Node(key,value);
    29         h.next=root;
    30         root = h;
    31     }
    32     
    33     public Value get(Key key){
    34         for(Node x=root;x!=null;x=x.next){
    35             if(x.key.equals(key)){
    36                 return x.value;
    37             }
    38         }
    39         return null;
    40     }
    41     
    42 }    

    b.线性探测法code:

     1 package com.gdufe.hash;
     2 
     3 import java.io.File;
     4 import java.util.Scanner;
     5 
     6 public class LinearIndex<Key,Value> {
     7     
     8     int N=0;
     9     int M=16;    //初始大小
    10     Key[] keys;
    11     Value[] values;
    12     
    13     public LinearIndex() { 
    14         keys = (Key[]) new Object[M];   //强制转型
    15         values = (Value[]) new Object[M];
    16     }
    17     public void put(Key key,Value value){
    18         if(N*2>=M) resize();  //扩大哈希表
    19         int i;
    20         for(i=hash(key);keys[i]!=null;i=(i+1)%M){
    21             if(keys[i].equals(key)){  //    更新value
    22                 values[i]=value;
    23                 return;        
    24             }
    25         }
    26         keys[i]=key;
    27         values[i]=value;
    28         N++;
    29     }
    30     
    31     private void resize() {        //扩大一倍
    32         Key[] keyTemp = (Key[]) new Object[2*keys.length];
    33         System.arraycopy(keys, 0, keyTemp, 0, keys.length);
    34         keys = keyTemp;
    35         Value[] valueTemp = (Value[]) new Object[2*values.length];
    36         System.arraycopy(values, 0, valueTemp, 0, values.length);
    37         values = valueTemp;
    38         
    39         M = M*2;    //shouldn't be neglected!
    40     }
    41     public Value get(Key key){
    42         for(int i=hash(key);keys[i]!=null;i=(i+1)%M){
    43             if(keys[i].equals(key))
    44                 return values[i];
    45         }
    46         return null;
    47     }
    48     public int hash(Key key){
    49         return (key.hashCode() & 0x7fffffff)%M;
    50     }
    51     
    52     public static void main(String[] args) throws Exception {
    53         Scanner input = new Scanner(new File("data_BST.txt"));
    54         LinearIndex<String, Integer> li = new LinearIndex<String, Integer>();
    55         while(input.hasNext()){
    56             String key = input.next();
    57             int value = input.nextInt();
    58             li.put(key, value);
    59         }
    60         input.close();
    61         System.out.println("-----output----");
    62         System.out.println(li.get("H"));
    63         System.out.println(li.get("B"));
    64     }
    65 }

    4.测试结果

    -----output----
    1
    11

    注意:

      (1)Java底层实现HashMap采用的是上述介绍的拉链法。关于HashMap的底层实现在Java面试中是面试官喜欢问的问题之一。

      (2)关于拉链法采用的辅助结构为什么选择顺序链表而不采用高效的“二叉查找树“是因为,当哈希表较大而每张链表存储的数据不多时,顺序链表的效率反而更高一些。

    结语:

      同之前介绍的红黑树一样,哈希表也是一种高效的存储于查找的数据结构,特别适用于大数据的场合。至于在何时使用哈希表何时使用红黑树这个不一而论。因为,存储的效率还更数据本身相关。不过,由于哈希一向擅长处理跟字符串相关的存储,所以对于大量的字符串存储与查找可以优先考虑哈希表。

  • 相关阅读:
    CSS外边距的合并
    四大主流浏览器内核
    ViewPort视口
    url、src、href定义以及使用区别
    Debug和Release区别
    基线概念
    浅谈C#循环控制流程语句(web前端基础)
    With you With me
    css元素内容基础
    年轻人有梦想,老人有回忆
  • 原文地址:https://www.cnblogs.com/SeaSky0606/p/4805012.html
Copyright © 2011-2022 走看看