三位数组实现的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 

ok 
oo 

源码:

转自:http://128kj.iteye.com/blog/1749453






本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/archive/2012/12/26/2834234.html,如需转载请自行联系原作者

目录
相关文章
|
1月前
每日一题(づ ̄3 ̄)づ╭❤~(数字在升序数组中出现的次数,整数转换)
每日一题(づ ̄3 ̄)づ╭❤~(数字在升序数组中出现的次数,整数转换)
11 0
|
2月前
|
存储 Java 索引
【Java编程进阶之路 03】深入探索:HashMap的长度为什么是2的幂次方
HashMap的长度为2的幂次方是为了利用位运算快速计算索引,提高数据分散性和减少哈希冲突。这样设计能确保元素均匀分布,提高搜索效率。同时,2的幂次方长度便于动态扩容时计算新位置,简化元素迁移过程。
|
10月前
剑指offer_数组---数组中只出现一次的数字
剑指offer_数组---数组中只出现一次的数字
50 0
|
算法 Java C#
数组中数字出现的个数(剑指offer 56-I)
一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
面试官:判断一个数是否为2的整数次幂
面试官:判断一个数是否为2的整数次幂
力扣刷题记录——326.3的幂、338. 比特位计数、342. 4的幂、350. 两个数组的交集 II
力扣刷题记录——326.3的幂、338. 比特位计数、342. 4的幂、350. 两个数组的交集 II
力扣刷题记录——326.3的幂、338. 比特位计数、342. 4的幂、350. 两个数组的交集 II
|
存储 算法 Python
python 力扣算法实现2 :#给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。 # #最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。
python 力扣算法实现2 :#给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。 # #最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。
|
开发框架 .NET C#
C# 找出数组中只出现了一次的数字
.NET 生态越来越好,初学的朋友也越来越多。处理同一件简单的问题,随着我们知识的积累解决问题的方法也会越来越多。 开始学习一门新的语言,我们经常会去解决之前用别的语言解决过无数次的老问题,今天我们来看看这么一道简单的查重题。
106 0
找出数组中只出现一次的数字
找出数组中只出现一次的数字
97 0
|
存储 算法 C++
Day6——有效的字母异位词、两个数组的交集、快乐数、两数之和(哈希)
Day6——有效的字母异位词、两个数组的交集、快乐数、两数之和(哈希)
78 0

热门文章

最新文章