zoukankan      html  css  js  c++  java
  • 三位数组实现的HashMap

    网上的一个HashMap代码,用三个数组实现,不同于jdk中的实现方式。处理哈希冲突是采用二次哈希(再哈希)的策略,学习了一把,个别地方可能没有理解到位。写了一些注释,如果有错误,敬请指出。

    Java代码  收藏代码
    1. public final class LongHashMap {  
    2.   
    3.       
    4.     protected long table[];//存放键,类型为long,应该是用于特殊场所  
    5.     protected Object values[];//存放值  
    6.     protected byte state[];//state[i]=0,1,2表示table[i]与values[i]没有使用,已经使用,已删除  
    7.     protected int freeEntries;//空闲的空间数  
    8.   
    9.     protected int distinct;//当前存了多少对键值  
    10.    
    11.     protected int lowWaterMark;//当LongHashMap存放的键值对少于此数时,将重新调整(再哈希)  
    12.     protected int highWaterMark;//当LongHashMap存放的键值对大于此数时,将重新调整,由容量和装载因子决定  
    13.   
    14.      
    15.     protected double minLoadFactor;//最小装载因子  
    16.     protected double maxLoadFactor;//最大装载因子  
    17.   
    18.    // 如果元素放得太满,就必须进行rehash(再哈希)。再哈希使空间增大,并将原有的对象重新导入新的LongHashMap中,  
    19.    //而原始的LongHashMap被删除。loadfactor(装载因子)决定何时要对LongHashMap进行再哈希。  
    20.     protected static final int DEFAULT_CAPACITY = 277;//缺省的容量,一个素数  
    21.     protected static final double DEFAULT_MIN_LOAD_FACTOR = 0.2;//缺省的最小的装载因子  
    22.     protected static final double DEFAULT_MAX_LOAD_FACTOR = 0.6;//缺省的最大的装载因子  
    23.   
    24.     protected static final byte FREE = 0;  
    25.     protected static final byte FULL = 1;  
    26.     protected static final byte REMOVED = 2;  
    27.   
    28.    //用缺省的容量构建HashMap  
    29.     public LongHashMap() {  
    30.         this(DEFAULT_CAPACITY);  
    31.     }  
    32.   
    33.    //构造函数  
    34.     public LongHashMap(int initialCapacity) {  
    35.         this(initialCapacity, DEFAULT_MIN_LOAD_FACTOR, DEFAULT_MAX_LOAD_FACTOR);  
    36.     }  
    37.   
    38.    //构造函数  
    39.     public LongHashMap(int initialCapacity, double minLoadFactor, double maxLoadFactor) {  
    40.         setUp(initialCapacity,minLoadFactor,maxLoadFactor);  
    41.     }  
    42.   
    43.     //使用指定的初始化容量,最小装载因子,最大装载因子构建LongHashMap  
    44.     protected void setUp(int initialCapacity, double minLoadFactor, double maxLoadFactor) {  
    45.         if (initialCapacity < 0) {//参数检查  
    46.             throw new IllegalArgumentException(  
    47.                 "Initial Capacity must not be less than zero: "+ initialCapacity  
    48.             );  
    49.         }  
    50.         if (minLoadFactor < 0.0 || minLoadFactor >= 1.0) {  
    51.                 throw new IllegalArgumentException(  
    52.                     "Illegal minLoadFactor: "+ minLoadFactor  
    53.                 );  
    54.         }  
    55.         if (maxLoadFactor <= 0.0 || maxLoadFactor >= 1.0) {  
    56.                 throw new IllegalArgumentException(  
    57.                     "Illegal maxLoadFactor: "+ maxLoadFactor  
    58.                 );  
    59.         }  
    60.         if (minLoadFactor >= maxLoadFactor) {  
    61.                 throw new IllegalArgumentException(  
    62.                     "Illegal minLoadFactor: " + minLoadFactor +  
    63.                     " and maxLoadFactor: " + maxLoadFactor  
    64.                 );  
    65.         }  
    66.   
    67.         int capacity = initialCapacity;  
    68.         capacity = nextPrime(capacity);//程序将调整初始化容量,使之为素数  
    69.         
    70.         if (capacity==0) {  
    71.             capacity=1;  
    72.         }  
    73.   
    74.         this.table = new long[capacity];//关键字数组  
    75.         this.values = new Object[capacity];//值数组  
    76.         this.state = new byte[capacity];//状态数组  
    77.   
    78.          
    79.         this.minLoadFactor = minLoadFactor;  
    80.           
    81.         if (capacity == LARGEST_PRIME) this.maxLoadFactor = 1.0;  
    82.         else this.maxLoadFactor = maxLoadFactor;  
    83.   
    84.         this.distinct = 0;//开始时,LongHashMap中没有存入键值对  
    85.         this.freeEntries = capacity; // 开始时空闲的空间数=容量  
    86.          
    87.         this.lowWaterMark = 0;  
    88.   
    89.         // Math.min(capacity-2, (int) (capacity * maxLoadFactor));  
    90.         this.highWaterMark = chooseHighWaterMark(capacity, this.maxLoadFactor);  
    91.     }  
    92.   
    93.        
    94.      //扩容量,一个素数  
    95.      private int chooseGrowCapacity(int size, double minLoad, double maxLoad) {  
    96.         return nextPrime(Math.max(size+1, (int) ((4*size / (3*minLoad+maxLoad)))));  
    97.     }  
    98.   
    99.      public boolean put(long key, Object value) {//在LongHashMap中存放键值对  
    100.         int i = indexOfInsertion(key);  
    101.         if (i<0) {   
    102.             i = -i -1;  
    103.             this.values[i]=value;  
    104.             return false;  
    105.         }  
    106.          if (this.distinct > this.highWaterMark) {//当存的健值对超过highWaterMark时,将重新构建LongHashMap  
    107.             int newCapacity = chooseGrowCapacity(  
    108.                     this.distinct+1,  
    109.                     this.minLoadFactor,  
    110.                     this.maxLoadFactor  
    111.                 );  
    112.             rehash(newCapacity);//用新容量重新构造  
    113.             return put(key, value);  
    114.         }  
    115.   
    116.         this.table[i]=key;  
    117.         this.values[i]=value;  
    118.         if (this.state[i]==FREE) this.freeEntries--;//剩余空间少了一个  
    119.         this.state[i]=FULL;  
    120.         this.distinct++;//当前存放的键值对数目加1  
    121.   
    122.         if (this.freeEntries < 1) {  
    123.             int newCapacity = chooseGrowCapacity(  
    124.                     this.distinct+1,  
    125.                     this.minLoadFactor,  
    126.                     this.maxLoadFactor  
    127.                 );  
    128.             rehash(newCapacity);//用新容量重新构造  
    129.         }  
    130.   
    131.         return true;  
    132.     }  
    133.     
    134.   
    135.          //求关键字key的索引值,用于插入(添加)  
    136.     private final int indexOfInsertion(long key) {  
    137.         final long tab[] = table;  
    138.         final byte stat[] = state;  
    139.         final int length = tab.length;  
    140.         //这就是哈希函数了  
    141.         final int hash = ((int)(key ^ (key >> 32))) & 0x7FFFFFFF;  
    142.         int i = hash % length;  
    143.   
    144.          //发生哈希冲突时,用于再哈希探测的步长  
    145.         int decrement = (hash) % (length-2);  
    146.         
    147.         if (decrement == 0) decrement = 1;  
    148.         //stat[i]有三种情况  
    149.         while (stat[i] == FULL && tab[i] != key) {//第一种,发生哈希冲突,往前探测  
    150.             i -= decrement;  
    151.             if (i<0) i+=length;  
    152.         }  
    153.   
    154.         if (stat[i] == REMOVED) {//第二种,此位置原来的键值对已删除  
    155.              
    156.             int j = i;  
    157.             //有意思,已删除的位置并不用来存新的  
    158.             while (stat[i] != FREE && (stat[i] == REMOVED || tab[i] != key)) {  
    159.                 i -= decrement;  
    160.                 if (i<0) i+=length;  
    161.             }  
    162.             if (stat[i] == FREE) i = j;  
    163.         }  
    164.   
    165.         if (stat[i] == FULL) {//第三种,这种情况会出现吗?  
    166.             
    167.             return -i-1;  
    168.         }  
    169.         //第三种,stat[i]=FREE  
    170.          
    171.         return i;  
    172.     }  
    173.   
    174.      //删除key的value  
    175.     public boolean removeKey(long key) {  
    176.         int i = indexOfKey(key);//获取关键字的索引  
    177.         if (i<0return false;   
    178.   
    179.         this.state[i]=REMOVED;//作删除标记  
    180.         this.values[i]=null//注意:table[i]并没有置为null  
    181.         this.distinct--;  
    182.   
    183.         if (this.distinct < this.lowWaterMark) {//存放的键值对少于lowWaterMark,重新调整  
    184.                 int newCapacity = chooseShrinkCapacity(  
    185.                         this.distinct,  
    186.                         this.minLoadFactor,  
    187.                         this.maxLoadFactor  
    188.                     );  
    189.          rehash(newCapacity);//用新容量重新构造  
    190.         }  
    191.   
    192.         return true;  
    193.     }  
    194.   
    195.   
    196.       public final Object get(long key) {//获取关键字对应的值  
    197.         int i = indexOfKey(key);  
    198.         if (i<0) {  
    199.             return null;  
    200.         }  
    201.         else {  
    202.             return values[i];  
    203.         }  
    204.     }  
    205.   
    206.     private final int indexOfKey(long key) {//求关键字之索引值,用于查找  
    207.         final long tab[] = table;  
    208.         final byte stat[] = state;  
    209.         final int length = tab.length;  
    210.         //这个是哈希函数  
    211.         final int hash = ((int)(key ^ (key >> 32))) & 0x7FFFFFFF;  
    212.         int i = hash % length;//得到了关键字的索引值  
    213.          
    214.         //用于再哈希探测的步长  
    215.         int decrement = (hash) % (length-2);//减量  
    216.     
    217.         if (decrement == 0) decrement = 1;  
    218.   
    219.         while (stat[i] != FREE && (stat[i] == REMOVED || tab[i] != key)) {  
    220.             i -= decrement;//往前找  
    221.             if (i<0) i+=length;  
    222.         }  
    223.   
    224.         if (stat[i] == FREE) return -1// 没有找到  
    225.         return i; //找到了,返回索引值  
    226.     }  
    227.   
    228.     
    229.       public void clear() {//清空  
    230.         for (int i=0; i<state.length; i++) {  
    231.             state[i] = FREE;  
    232.         }  
    233.         for (int i=0; i<values.length-1; i++) {  
    234.             values[i] = null;  
    235.         }  
    236.   
    237.         this.distinct = 0;  
    238.         this.freeEntries = table.length;   
    239.         trimToSize();//清空以后,容量不能太大,这里重新调整,以节约空间  
    240.     }  
    241.   
    242.      public void trimToSize() {  
    243.        int newCapacity = nextPrime((int)(1 + 1.2*size()));  
    244.         if (table.length > newCapacity) {  
    245.             rehash(newCapacity);  
    246.         }  
    247.     }  
    248.   
    249.   
    250.   
    251.     //是否包含key  
    252.     public boolean containsKey(long key) {  
    253.         return indexOfKey(key) >= 0;  
    254.     }  
    255.   
    256.     //是否包含value  
    257.     public boolean containsValue(Object value) {  
    258.         return indexOfValue(value) >= 0;  
    259.     }  
    260.   
    261.     
    262.     public void ensureCapacity(int minCapacity) {//确保容量不小于minCapacity  
    263.         if (table.length < minCapacity) {  
    264.             int newCapacity = nextPrime(minCapacity);  
    265.             rehash(newCapacity);//再哈希  
    266.         }  
    267.     }  
    268.   
    269.   
    270.     protected int indexOfValue(Object value) {//获取值的索引  
    271.         final Object val[] = values;  
    272.         final byte stat[] = state;  
    273.   
    274.         for (int i=stat.length; --i >= 0;) {  
    275.             if (stat[i]==FULL && val[i]==value) return i;  
    276.         }  
    277.   
    278.         return -1// not found  
    279.     }  
    280.   
    281.    //获取value的第一个键值,可能的多个  
    282.     public long keyOf(Object value) {  
    283.         int i = indexOfValue(value);  
    284.         if (i<0return Long.MIN_VALUE;  
    285.         return table[i];  
    286.     }  
    287.   
    288.    
    289.     public long[] keys() {//所有的键  
    290.         long[] elements = new long[distinct];  
    291.         long[] tab = table;  
    292.         byte[] stat = state;  
    293.         int j=0;  
    294.         for (int i = tab.length ; i-- > 0 ;) {  
    295.             if (stat[i]==FULL) {  
    296.                 elements[j++]=tab[i];  
    297.             }  
    298.         }  
    299.         return elements;  
    300.     }  
    301.   
    302.     
    303.      public int size() {//当前存了多少对键值  
    304.         return distinct;  
    305.     }  
    306.   
    307.       
    308.     public boolean isEmpty() {  
    309.         return distinct == 0;  
    310.     }  
    311.   
    312.      // 如果元素放得太满,就必须进行rehash(再哈希)。再哈希使空间增大,并将原有的对象重新导入新的LongHashMap中,  
    313.    //而原始的LongHashMap被删除。loadfactor(装载因子)决定何时要对LongHashMap进行再哈希。  
    314.   
    315.     protected void rehash(int newCapacity) {//用新的容量重新构建LongHashMap  
    316.         int oldCapacity = table.length;//原来的容量  
    317.         long oldTable[] = table;//原来的键  
    318.         Object oldValues[] = values;//原来的值  
    319.         byte oldState[] = state;  
    320.   
    321.         long newTable[] = new long[newCapacity];  
    322.         Object newValues[] = new Object[newCapacity];  
    323.         byte newState[] = new byte[newCapacity];  
    324.           
    325.          //(int) (newCapacity * minLoadFactor);  
    326.         this.lowWaterMark  = chooseLowWaterMark(newCapacity,this.minLoadFactor);  
    327.         this.highWaterMark = chooseHighWaterMark(newCapacity,this.maxLoadFactor);  
    328.   
    329.         this.table = newTable;  
    330.         this.values = newValues;  
    331.         this.state = newState;  
    332.         this.freeEntries = newCapacity-this.distinct; // 当前的剩余空间  
    333.   
    334.         for (int i = oldCapacity ; i-- > 0 ;) {  
    335.             if (oldState[i]==FULL) {  
    336.                 long element = oldTable[i];  
    337.                 int index = indexOfInsertion(element);  
    338.                 newTable[index]=element;  
    339.                 newValues[index]=oldValues[i];  
    340.                 newState[index]=FULL;  
    341.             }  
    342.         }  
    343.     }  
    344.   
    345.      
    346.   
    347.     
    348.     public Object[] values() {  
    349.         Object[] elements = new Object[distinct];  
    350.   
    351.         Object[] val = values;  
    352.         byte[] stat = state;  
    353.   
    354.         int j=0;  
    355.         for (int i = stat.length ; i-- > 0 ;) {  
    356.             if (stat[i]==FULL) {  
    357.                 elements[j++]=val[i];  
    358.             }  
    359.         }  
    360.         return elements;  
    361.     }  
    362.   
    363.      
    364.   
    365.       
    366.     private int chooseHighWaterMark(int capacity, double maxLoad) {  
    367.           return Math.min(capacity-2, (int) (capacity * maxLoad));  
    368.     }  
    369.   
    370.      
    371.     protected int chooseLowWaterMark(int capacity, double minLoad) {  
    372.         return (int) (capacity * minLoad);  
    373.     }  
    374.   
    375.       
    376.     protected int chooseMeanCapacity(int size, double minLoad, double maxLoad) {  
    377.         return nextPrime(Math.max(size+1, (int) ((2*size / (minLoad+maxLoad)))));  
    378.     }  
    379.   
    380.    
    381.     protected int chooseShrinkCapacity(int size, double minLoad, double maxLoad) {  
    382.         return nextPrime(Math.max(size+1, (int) ((4*size / (minLoad+3*maxLoad)))));  
    383.     }  
    384.   
    385.     
    386.     protected int nextPrime(int desiredCapacity) {//对指定的容量,在素数表中进行对半查找,返回一个素数容量  
    387.         int i = java.util.Arrays.binarySearch(primeCapacities, desiredCapacity);  
    388.         if(desiredCapacity==100) System.out.println("i="+i);  
    389.         if (i<0) {  
    390.              i = -i -1;   
    391.         }  
    392.         return primeCapacities[i];  
    393.     }  
    394.   
    395.    private void printState(){  
    396.       for(int i=0;i<state.length;i++)  
    397.         System.out.print(state[i]+"  ");  
    398.       System.out.println();  
    399.    }  
    400.       
    401.     public static final int LARGEST_PRIME = Integer.MAX_VALUE; //最大的素数.  
    402.   
    403.      
    404.     private static final int[] primeCapacities = {//容量素数表  
    405.         LARGEST_PRIME,  
    406.   
    407.         //chunk #1  
    408.         5,11,23,47,97,197,397,797,1597,3203,6421,12853,25717,51437,102877,205759,  
    409.         411527,823117,1646237,3292489,6584983,13169977,26339969,52679969,105359939,  
    410.         210719881,421439783,842879579,1685759167,  
    411.   
    412.         //chunk #2  
    413.         433,877,1759,3527,7057,14143,28289,56591,113189,226379,452759,905551,1811107,  
    414.         3622219,7244441,14488931,28977863,57955739,115911563,231823147,463646329,927292699,  
    415.         1854585413,  
    416.   
    417.         //chunk #3  
    418.         953,1907,3821,7643,15287,30577,61169,122347,244703,489407,978821,1957651,3915341,  
    419.         7830701,15661423,31322867,62645741,125291483,250582987,501165979,1002331963,  
    420.         2004663929,  
    421.   
    422.         //chunk #4  
    423.         1039,2081,4177,8363,16729,33461,66923,133853,267713,535481,1070981,2141977,4283963,  
    424.         8567929,17135863,34271747,68543509,137087021,274174111,548348231,1096696463,  
    425.   
    426.         //chunk #5  
    427.         31,67,137,277,557,1117,2237,4481,8963,17929,35863,71741,143483,286973,573953,  
    428.         1147921,2295859,4591721,9183457,18366923,36733847,73467739,146935499,293871013,  
    429.         587742049,1175484103,  
    430.   
    431.         //chunk #6  
    432.         599,1201,2411,4831,9677,19373,38747,77509,155027,310081,620171,1240361,2480729,  
    433.         4961459,9922933,19845871,39691759,79383533,158767069,317534141,635068283,1270136683,  
    434.   
    435.         //chunk #7  
    436.         311,631,1277,2557,5119,10243,20507,41017,82037,164089,328213,656429,1312867,  
    437.         2625761,5251529,10503061,21006137,42012281,84024581,168049163,336098327,672196673,  
    438.         1344393353,  
    439.   
    440.         //chunk #8  
    441.         3,7,17,37,79,163,331,673,1361,2729,5471,10949,21911,43853,87719,175447,350899,  
    442.         701819,1403641,2807303,5614657,11229331,22458671,44917381,89834777,179669557,  
    443.         359339171,718678369,1437356741,  
    444.   
    445.         //chunk #9  
    446.         43,89,179,359,719,1439,2879,5779,11579,23159,46327,92657,185323,370661,741337,  
    447.         1482707,2965421,5930887,11861791,23723597,47447201,94894427,189788857,379577741,  
    448.         759155483,1518310967,  
    449.   
    450.         //chunk #10  
    451.         379,761,1523,3049,6101,12203,24407,48817,97649,195311,390647,781301,1562611,  
    452.         3125257,6250537,12501169,25002389,50004791,100009607,200019221,400038451,800076929,  
    453.         1600153859  
    454.     };  
    455.   
    456.     static {   
    457.         java.util.Arrays.sort(primeCapacities);  
    458.     }  
    459.   
    460.     //测试一下  
    461.      public static void main(String args[]){  
    462.       LongHashMap lh=new LongHashMap(5);//初始容量为5  
    463.       System.out.println("size="+lh.size());  
    464.       for(int i=0;i<3;i++)//先放三个  
    465.         lh.put(i, Integer.valueOf(i));  
    466.       System.out.println("size="+lh.size());  
    467.       lh.removeKey(1);//删除二个  
    468.        lh.removeKey(2);  
    469.       lh.put(123,"ok");//添加一个  
    470.   
    471.       //看看状态  
    472.       lh.printState();  
    473.       lh.put(1234,"oo");//再放一个  
    474.       //看看状态   
    475.       lh.printState();  
    476.   
    477.       //取出来  
    478.        System.out.println(lh.get(0));  
    479.       System.out.println(lh.get(123));  
    480.       System.out.println(lh.get(1234));  
    481.   
    482.     }  
    483. }  



    运行:

    C:\ex>java   LongHashMap
    size=0
    size=3
    1  2  2  1  0
    1  0  0  0  1  0  0  0  0  0  1  0  0  0  0  0  0
    0
    ok
    oo

    源码:


    微信公众号: 猿人谷
    如果您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】
    如果您希望与我交流互动,欢迎关注微信公众号
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

  • 相关阅读:
    联考20200725 T1 String
    联考20200723 T1 数
    联考20200722 T3 积木
    联考20200722 T2 ACT4!无限回转!
    联考20200722 T1 集合划分
    联考20200721 T2 s2mple
    联考20200721 T1 s1mple
    联考20200719 T2 寻找规律
    联考20200719 T1 合并奶牛
    联考20200718 T2 树论
  • 原文地址:https://www.cnblogs.com/heyonggang/p/2834234.html
Copyright © 2011-2022 走看看