zoukankan      html  css  js  c++  java
  • 开放地址法实现HashTable

    前注:本文不是讲解Java类库的Hashtable实现原理,而是根据计算机哈希表原理自己实现的一个Hashtable。

    HashTable内部是用数组存放一个(Key-Value pair)键值对的引用,其原理是根据Key的hashCode来计算出数组下标。因为存放位置是直接计算出来,不需要遍历数据结构,这使得hash table具有快速增删查改的优势。下面介绍HashTable的实现步骤:

    • 取得Key的hashCode。

      通过Eclipse等工具可以轻松的复写Object的hashCode方法,生成的hashCode是不会有重复值的。

    • 将hashCode与地址映射(压缩地址):

      但是,Hashtable内部是用一个数组来存储Key-Value对的,数组容量有限,本文中设置数组容量为10。那么现在的问题就是如何将hashCode和数组地址相对应?一个简单的方法就是对hashCode取模运算(hashCode%10)。这样就可以将hashCode与数组地址做映射(多对一)。同时注意,hashCode可能为负数,而数组的下标不能为负数,所以在映射的时候需要处理一下。

    1 int hashCode =  Math.abs(key.hashCode())% this.maxSize;
    • 解决hashCode重复问题:

    上文已经说过,数组容量为10,当我们在将hashCode映射为数组下标的时候,肯定会遇到有重复的情况。比如hashCode为21和31,分别对他们取模运算,结果都是1,也就是说这两个hashCode对应数组的下标都是1.那么第一个元素添加上去后,再添加第二个元素,则新元素会覆盖之前的元素。这时,如果我们想后面添加的重复地址元素也能添加上去,只能将其放在其它位置。这时,我们可以将新元素放在改地址的下一位,如果下一位已经有元素,那么就继续往后找,直到找到空位为止(其实这个过程有些边界条件需要考虑,比如找到数组末尾后应跳到数组开头继续找。以及数组已经满了,找遍数组都找不到合适的位置,就应该提示该数组已满,不能插入)。 

    现在既然解决了上面的问题,也就是说每个元素都能在数组中找到合适的位置(除非数组已满)。那么可以根据这个算法实现数组的增删查改。下面是Hashtable的实现代码:

      1 package org.lyk.impl;
      2 
      3 public class HashTable<K, V>
      4 {
      5     /**
      6      * Key-Value pair 存放键值对
      7      * @author liuyuank
      8      *
      9      */
     10     private class KeyValue
     11     {
     12         K key;
     13         V value;
     14 
     15         private KeyValue(K key, V value)
     16         {
     17             this.key = key;
     18             this.value = value;
     19         }
     20 
     21         public K getKey()
     22         {
     23             return key;
     24         }
     25 
     26         public void setKey(K key)
     27         {
     28             this.key = key;
     29         }
     30 
     31         public V getValue()
     32         {
     33             return value;
     34         }
     35 
     36         public void setValue(V value)
     37         {
     38             this.value = value;
     39         }
     40 
     41     }
     42 
     43     private Object[] table;
     44     private int maxSize = 10;
     45     private int currentAmmount = 0;
     46 
     47     public HashTable()
     48     {
     49         this.table = new Object[this.maxSize];
     50     }
     51 
     52     public HashTable(int maxSize) throws Exception
     53     {
     54         if (0 == maxSize || maxSize < 0 || maxSize > 100)
     55         {
     56             throw new Exception("table容量非法!");
     57         }
     58 
     59         this.maxSize = maxSize;
     60         this.table = new Info[maxSize];
     61     }
     62 
     63     /**
     64      * 增加一个键值对
     65      * @param key
     66      * @param value
     67      */
     68     public void add(K key, V value)
     69     { 
     70         //将hashCode映射到数组下标
     71         int hashCode =  Math.abs(key.hashCode())% this.maxSize;
     72         
     73         //将元素插入到数组中,如果该位置已经被占用,则循环查找下一个位置,直到找到合适的位置,或发现数组已满,退出循环
     74         while (this.table[hashCode] != null
     75                 && (this.currentAmmount < this.maxSize))
     76         {
     77             hashCode++;
     78             hashCode = hashCode % this.maxSize;
     79         }
     80 
     81         if (this.currentAmmount == this.maxSize)
     82         {
     83             //数组已满
     84             System.out.println("Hash table 已满");
     85         } else
     86         {
     87             //找到合适位置
     88             this.table[hashCode] = new KeyValue(key, value); 
     89             this.currentAmmount++;
     90         }
     91     }
     92 
     93     /**
     94      * 与add方法同样的算法,根据key值找到数组中元素,然后将改元素设置为null
     95      * @param key
     96      * @return
     97      */
     98     public boolean remove(K key)
     99     {
    100         int hashCode = Math.abs(key.hashCode()) % this.maxSize;
    101         int count = 0;
    102         while (this.table[hashCode] != null && count < this.maxSize)
    103         {
    104             if (((KeyValue) this.table[hashCode]).getKey().equals(key))
    105             {
    106                 this.table[hashCode] = null;
    107                 return true;
    108             }
    109             count++;
    110             hashCode++;
    111             hashCode = hashCode%this.maxSize;
    112         }
    113 
    114         return false;
    115     }
    116 
    117     public V get(K key)
    118     {
    119         int hashCode = Math.abs(key.hashCode()) % this.maxSize;
    120         int count = 0;
    121         while (this.table[hashCode] != null && count < this.maxSize)
    122         {
    123             if (key.equals(((KeyValue)this.table[hashCode]).getKey()))
    124                 return ((KeyValue) this.table[hashCode]).getValue();
    125             
    126             hashCode++;
    127             count++;
    128             hashCode = hashCode%this.maxSize;
    129         }
    130         return null;
    131     }
    132 
    133     public boolean contains(K key)
    134     {
    135         if (this.get(key) != null)
    136         {
    137             return true;
    138         } else
    139         {
    140             return false;
    141         }
    142     }
    143     
    144     public void replace(K key, V value)
    145     {
    146         KeyValue kv = this.find(key);
    147         if(kv != null)
    148         { 
    149             kv.setValue(value);
    150         }
    151     }
    152     
    153     private KeyValue find(K key)
    154     {
    155         int hashCode = Math.abs(key.hashCode()) % this.maxSize;
    156         int count = 0;
    157         while (this.table[hashCode] != null && count < this.maxSize)
    158         {
    159             if (key.equals(((KeyValue)this.table[hashCode]).getKey()))
    160                 return ((KeyValue) this.table[hashCode]);
    161             
    162             hashCode++;
    163             count++;
    164             hashCode = hashCode%this.maxSize;
    165         }
    166         return null;
    167     }
    168 }
    HashTable实现
    package org.lyk.impl;
    
    import java.math.BigInteger;
    
    public class Info
    {
        private String name;
        private String address;
        private Integer age; 
        
        
        public Info(String name, String address, Integer age)
        {
            super();
            this.name = name;
            this.address = address;
            this.age = age;
        }
        @Override
        public int hashCode()
        {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((address == null) ? 0 : address.hashCode());
            result = prime * result + ((age == null) ? 0 : age.hashCode());
            result = prime * result + ((name == null) ? 0 : name.hashCode());
            return result;
        }
        
    //    @Override
    //    public int hashCode()
    //    {
    //        final int prime = 27;
    //        int result = 1;
    //        result = prime*result + (this.name == null ? 0:this.name.hashCode());
    //        result = prime*result + (this.address == null ? 0:this.address.hashCode());
    //        result = prime*result + (this.age == null ? 0 : this.age.hashCode());
    //        return result;
    //    }
        
        
        @Override
        public boolean equals(Object obj)
        {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Info other = (Info) obj;
            if (address == null)
            {
                if (other.address != null)
                    return false;
            } else if (!address.equals(other.address))
                return false;
            if (age == null)
            {
                if (other.age != null)
                    return false;
            } else if (!age.equals(other.age))
                return false;
            if (name == null)
            {
                if (other.name != null)
                    return false;
            } else if (!name.equals(other.name))
                return false;
            return true;
        }
        public String getName()
        {
            return name;
        }
        public void setName(String name)
        {
            this.name = name;
        }
        public String getAddress()
        {
            return address;
        }
        public void setAddress(String address)
        {
            this.address = address;
        }
        public Integer getAge()
        {
            return age;
        }
        public void setAge(Integer age)
        {
            this.age = age;
        }
        @Override
        public String toString()
        {
            return "Info [name=" + name + ", address=" + address + ", age=" + age
                    + "]";
        }
        
        
        
        
    }
    Value实现

    测试代码:String为Key Info为Value

    package org.lyk.main;
     
    
    import org.lyk.impl.BiTree;
    import org.lyk.impl.HashTable;
    import org.lyk.impl.Info;
    
    public class Main
    {
        public static void main(String[] args)
        {
            HashTable<String, Info> ht = new HashTable<>();
            for(int i =0; i <15;i++)
            {
                Info info = new Info("sheldon" + i, "address" + i , i);
                //System.out.println("hashCode in main:" + info.getName().hashCode());
                ht.add(info.getName(), info);
            }
            
            String key = "sheldon3";
            System.out.println(ht.contains(key));
            ht.replace(key, new Info("谢耳朵","美国洛杉矶", 999));
            System.out.println(ht.contains(key));
            System.out.println(ht.get(key));
            System.out.println("///~ main done");
        } 
         
    }
  • 相关阅读:
    基于 WebGL 的 HTML5 楼宇自控 3D 可视化监控
    基于 HTML5 的 WebGL 楼宇自控 3D 可视化监控
    基于 WebGL 3D 的 HTML5 档案馆可视化管理系统
    基于 HTML5 的 WebGL 3D 档案馆可视化管理系统
    基于 HTML5 的 WebGL 和 VR 技术的 3D 机房数据中心可视化
    代码管理(四)SVN和Git对比
    代码管理(二)sourcetree 安装与使用
    代码管理(一)git
    iOS11新特性之LargeTitle
    使用Cordova搭建Andoid和iOS开发环境
  • 原文地址:https://www.cnblogs.com/kuillldan/p/6079992.html
Copyright © 2011-2022 走看看