Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 1272|回复: 0

[算法学习]LongHashMap学习笔记

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-12-3 00:07:15 | 显示全部楼层 |阅读模式
    一个HashMap代码,来自于jive。用三个数组实现,不同于jdk中的实现方式。处理哈希冲突是采用二次哈希(再哈希)的策略,学习了一把,个别地方可能没有理解透。


    1. public final class LongHashMap {
    2.    
    3.     protected long table[];//存放键,类型为long,应该是用于特殊场所
    4.     protected Object values[];//存放值
    5.     protected byte state[];//state[i]=0,1,2表示table[i]与values[i]没有使用,已经使用,已删除
    6.     protected int freeEntries;//空闲的空间数
    7.     protected int distinct;//当前存了多少对键值

    8.     protected int lowWaterMark;//当LongHashMap存放的键值对少于此数时,将重新调整(再哈希)
    9.     protected int highWaterMark;//当LongHashMap存放的键值对大于此数时,将重新调整,由容量和装载因子决定
    10.    
    11.     protected double minLoadFactor;//最小装载因子
    12.     protected double maxLoadFactor;//最大装载因子
    13.    // 如果元素放得太满,就必须进行rehash(再哈希)。再哈希使空间增大,并将原有的对象重新导入新的LongHashMap中,
    14.    //而原始的LongHashMap被删除。loadfactor(装载因子)决定何时要对LongHashMap进行再哈希。
    15.     protected static final int DEFAULT_CAPACITY = 277;//缺省的容量,一个素数
    16.     protected static final double DEFAULT_MIN_LOAD_FACTOR = 0.2;//缺省的最小的装载因子
    17.     protected static final double DEFAULT_MAX_LOAD_FACTOR = 0.6;//缺省的最大的装载因子
    18.     protected static final byte FREE = 0;
    19.     protected static final byte FULL = 1;
    20.     protected static final byte REMOVED = 2;
    21.    //用缺省的容量构建HashMap
    22.     public LongHashMap() {
    23.         this(DEFAULT_CAPACITY);
    24.     }
    25.    //构造函数
    26.     public LongHashMap(int initialCapacity) {
    27.         this(initialCapacity, DEFAULT_MIN_LOAD_FACTOR, DEFAULT_MAX_LOAD_FACTOR);
    28.     }
    29.    //构造函数
    30.     public LongHashMap(int initialCapacity, double minLoadFactor, double maxLoadFactor) {
    31.         setUp(initialCapacity,minLoadFactor,maxLoadFactor);
    32.     }
    33.     //使用指定的初始化容量,最小装载因子,最大装载因子构建LongHashMap
    34.     protected void setUp(int initialCapacity, double minLoadFactor, double maxLoadFactor) {
    35.         if (initialCapacity < 0) {//参数检查
    36.             throw new IllegalArgumentException(
    37.                 "Initial Capacity must not be less than zero: "+ initialCapacity
    38.             );
    39.         }
    40.         if (minLoadFactor < 0.0 || minLoadFactor >= 1.0) {
    41.                 throw new IllegalArgumentException(
    42.                     "Illegal minLoadFactor: "+ minLoadFactor
    43.                 );
    44.         }
    45.         if (maxLoadFactor <= 0.0 || maxLoadFactor >= 1.0) {
    46.                 throw new IllegalArgumentException(
    47.                     "Illegal maxLoadFactor: "+ maxLoadFactor
    48.                 );
    49.         }
    50.         if (minLoadFactor >= maxLoadFactor) {
    51.                 throw new IllegalArgumentException(
    52.                     "Illegal minLoadFactor: " + minLoadFactor +
    53.                     " and maxLoadFactor: " + maxLoadFactor
    54.                 );
    55.         }
    56.         int capacity = initialCapacity;
    57.         capacity = nextPrime(capacity);//程序将调整初始化容量,使之为素数
    58.       
    59.         if (capacity==0) {
    60.             capacity=1;
    61.         }
    62.         this.table = new long[capacity];//关键字数组
    63.         this.values = new Object[capacity];//值数组
    64.         this.state = new byte[capacity];//状态数组
    65.       
    66.         this.minLoadFactor = minLoadFactor;
    67.         
    68.         if (capacity == LARGEST_PRIME) this.maxLoadFactor = 1.0;
    69.         else this.maxLoadFactor = maxLoadFactor;
    70.         this.distinct = 0;//开始时,LongHashMap中没有存入键值对
    71.         this.freeEntries = capacity; // 开始时空闲的空间数=容量
    72.       
    73.         this.lowWaterMark = 0;
    74.         // Math.min(capacity-2, (int) (capacity * maxLoadFactor));
    75.         this.highWaterMark = chooseHighWaterMark(capacity, this.maxLoadFactor);
    76.     }
    77.      
    78.      //扩容量,一个素数
    79.      private int chooseGrowCapacity(int size, double minLoad, double maxLoad) {
    80.         return nextPrime(Math.max(size+1, (int) ((4*size / (3*minLoad+maxLoad)))));
    81.     }
    82.      public boolean put(long key, Object value) {//在LongHashMap中存放键值对
    83.         int i = indexOfInsertion(key);
    84.         if (i< 0) {
    85.             i = -i -1;
    86.             this.values[i]=value;
    87.             return false;
    88.         }
    89.          if (this.distinct > this.highWaterMark) {//当存的健值对超过highWaterMark时,将重新构建LongHashMap
    90.             int newCapacity = chooseGrowCapacity(
    91.                     this.distinct+1,
    92.                     this.minLoadFactor,
    93.                     this.maxLoadFactor
    94.                 );
    95.             rehash(newCapacity);//用新容量重新构造
    96.             return put(key, value);
    97.         }
    98.         this.table[i]=key;
    99.         this.values[i]=value;
    100.         if (this.state[i]==FREE) this.freeEntries--;//剩余空间少了一个
    101.         this.state[i]=FULL;
    102.         this.distinct++;//当前存放的键值对数目加1
    103.         if (this.freeEntries < 1) {
    104.             int newCapacity = chooseGrowCapacity(
    105.                     this.distinct+1,
    106.                     this.minLoadFactor,
    107.                     this.maxLoadFactor
    108.                 );
    109.             rehash(newCapacity);//用新容量重新构造
    110.         }
    111.         return true;
    112.     }
    113.   
    114.          //求关键字key的索引值,用于插入(添加)
    115.     private final int indexOfInsertion(long key) {
    116.         final long tab[] = table;
    117.         final byte stat[] = state;
    118.         final int length = tab.length;
    119.         //这就是哈希函数了
    120.         final int hash = ((int)(key ^ (key >> 32))) & 0x7FFFFFFF;
    121.         int i = hash % length;
    122.          //发生哈希冲突时,用于再哈希探测的步长
    123.         int decrement = (hash) % (length-2);
    124.       
    125.         if (decrement == 0) decrement = 1;
    126.         //stat[i]有三种情况
    127.         while (stat[i] == FULL && tab[i] != key) {//第一种,发生哈希冲突,往前探测
    128.             i -= decrement;
    129.             if (i< 0) i+=length;
    130.         }
    131.         if (stat[i] == REMOVED) {//第二种,此位置原来的键值对已删除
    132.            
    133.             int j = i;
    134.             //有意思,已删除的位置并不用来存新的
    135.             while (stat[i] != FREE && (stat[i] == REMOVED || tab[i] != key)) {
    136.                 i -= decrement;
    137.                 if (i< 0) i+=length;
    138.             }
    139.             if (stat[i] == FREE) i = j;
    140.         }
    141.         if (stat[i] == FULL) {//第三种,这种情况会出现吗?
    142.          
    143.             return -i-1;
    144.         }
    145.         //第三种,stat[i]=FREE
    146.       
    147.         return i;
    148.     }
    149.      //删除key的value
    150.     public boolean removeKey(long key) {
    151.         int i = indexOfKey(key);//获取关键字的索引
    152.         if (i< 0) return false;
    153.         this.state[i]=REMOVED;//作删除标记
    154.         this.values[i]=null; //注意:table[i]并没有置为null
    155.         this.distinct--;
    156.         if (this.distinct < this.lowWaterMark) {//存放的键值对少于lowWaterMark,重新调整
    157.                 int newCapacity = chooseShrinkCapacity(
    158.                         this.distinct,
    159.                         this.minLoadFactor,
    160.                         this.maxLoadFactor
    161.                     );
    162.          rehash(newCapacity);//用新容量重新构造
    163.         }
    164.         return true;
    165.     }
    166.       public final Object get(long key) {//获取关键字对应的值
    167.         int i = indexOfKey(key);
    168.         if (i< 0) {
    169.             return null;
    170.         }
    171.         else {
    172.             return values[i];
    173.         }
    174.     }
    175.     private final int indexOfKey(long key) {//求关键字之索引值,用于查找
    176.         final long tab[] = table;
    177.         final byte stat[] = state;
    178.         final int length = tab.length;
    179.         //这个是哈希函数
    180.         final int hash = ((int)(key ^ (key >> 32))) & 0x7FFFFFFF;
    181.         int i = hash % length;//得到了关键字的索引值
    182.       
    183.         //用于再哈希探测的步长
    184.         int decrement = (hash) % (length-2);//减量
    185.   
    186.         if (decrement == 0) decrement = 1;
    187.         while (stat[i] != FREE && (stat[i] == REMOVED || tab[i] != key)) {
    188.             i -= decrement;//往前找
    189.             if (i< 0) i+=length;
    190.         }
    191.         if (stat[i] == FREE) return -1; // 没有找到
    192.         return i; //找到了,返回索引值
    193.     }
    194.   
    195.       public void clear() {//清空
    196.         for (int i=0; i< state.length; i++) {
    197.             state[i] = FREE;
    198.         }
    199.         for (int i=0; i< values.length-1; i++) {
    200.             values[i] = null;
    201.         }
    202.         this.distinct = 0;
    203.         this.freeEntries = table.length;
    204.         trimToSize();//清空以后,容量不能太大,以节约空间
    205.     }
    206.      public void trimToSize() {
    207.        int newCapacity = nextPrime((int)(1 + 1.2*size()));
    208.         if (table.length > newCapacity) {
    209.             rehash(newCapacity);
    210.         }
    211.     }
    212.     //是否包含key
    213.     public boolean containsKey(long key) {
    214.         return indexOfKey(key) >= 0;
    215.     }
    216.     //是否包含value
    217.     public boolean containsValue(Object value) {
    218.         return indexOfValue(value) >= 0;
    219.     }
    220.   
    221.     public void ensureCapacity(int minCapacity) {//确保容量不小于minCapacity
    222.         if (table.length < minCapacity) {
    223.             int newCapacity = nextPrime(minCapacity);
    224.             rehash(newCapacity);//再哈希
    225.         }
    226.     }
    227.     protected int indexOfValue(Object value) {//获取值的索引
    228.         final Object val[] = values;
    229.         final byte stat[] = state;
    230.         for (int i=stat.length; --i >= 0;) {
    231.             if (stat[i]==FULL && val[i]==value) return i;
    232.         }
    233.         return -1; // not found
    234.     }
    235.    //获取value的第一个键值,可能的多个
    236.     public long keyOf(Object value) {
    237.         int i = indexOfValue(value);
    238.         if (i< 0) return Long.MIN_VALUE;
    239.         return table[i];
    240.     }

    241.     public long[] keys() {//所有的键
    242.         long[] elements = new long[distinct];
    243.         long[] tab = table;
    244.         byte[] stat = state;
    245.         int j=0;
    246.         for (int i = tab.length ; i-- > 0 ;) {
    247.             if (stat[i]==FULL) {
    248.                 elements[j++]=tab[i];
    249.             }
    250.         }
    251.         return elements;
    252.     }
    253.   
    254.      public int size() {//当前存了多少对键值
    255.         return distinct;
    256.     }
    257.    
    258.     public boolean isEmpty() {
    259.         return distinct == 0;
    260.     }
    261.      // 如果元素放得太满,就必须进行rehash(再哈希)。再哈希使空间增大,并将原有的对象重新导入新的LongHashMap中,
    262.    //而原始的LongHashMap被删除。loadfactor(装载因子)决定何时要对LongHashMap进行再哈希。
    263.     protected void rehash(int newCapacity) {//用新的容量重新构建LongHashMap
    264.         int oldCapacity = table.length;//原来的容量
    265.         long oldTable[] = table;//原来的键
    266.         Object oldValues[] = values;//原来的值
    267.         byte oldState[] = state;
    268.         long newTable[] = new long[newCapacity];
    269.         Object newValues[] = new Object[newCapacity];
    270.         byte newState[] = new byte[newCapacity];
    271.         
    272.          //(int) (newCapacity * minLoadFactor);
    273.         this.lowWaterMark  = chooseLowWaterMark(newCapacity,this.minLoadFactor);
    274.         this.highWaterMark = chooseHighWaterMark(newCapacity,this.maxLoadFactor);
    275.         this.table = newTable;
    276.         this.values = newValues;
    277.         this.state = newState;
    278.         this.freeEntries = newCapacity-this.distinct; // 当前的剩余空间
    279.         for (int i = oldCapacity ; i-- > 0 ;) {
    280.             if (oldState[i]==FULL) {
    281.                 long element = oldTable[i];
    282.                 int index = indexOfInsertion(element);
    283.                 newTable[index]=element;
    284.                 newValues[index]=oldValues[i];
    285.                 newState[index]=FULL;
    286.             }
    287.         }
    288.     }
    289.    
    290.   
    291.     public Object[] values() {
    292.         Object[] elements = new Object[distinct];
    293.         Object[] val = values;
    294.         byte[] stat = state;
    295.         int j=0;
    296.         for (int i = stat.length ; i-- > 0 ;) {
    297.             if (stat[i]==FULL) {
    298.                 elements[j++]=val[i];
    299.             }
    300.         }
    301.         return elements;
    302.     }
    303.    
    304.    
    305.     private int chooseHighWaterMark(int capacity, double maxLoad) {
    306.           return Math.min(capacity-2, (int) (capacity * maxLoad));
    307.     }
    308.    
    309.     protected int chooseLowWaterMark(int capacity, double minLoad) {
    310.         return (int) (capacity * minLoad);
    311.     }
    312.    
    313.     protected int chooseMeanCapacity(int size, double minLoad, double maxLoad) {
    314.         return nextPrime(Math.max(size+1, (int) ((2*size / (minLoad+maxLoad)))));
    315.     }

    316.     protected int chooseShrinkCapacity(int size, double minLoad, double maxLoad) {
    317.         return nextPrime(Math.max(size+1, (int) ((4*size / (minLoad+3*maxLoad)))));
    318.     }
    319.   
    320.     protected int nextPrime(int desiredCapacity) {//对指定的容量,在素数表中进行对半查找,返回一个素数容量
    321.         int i = java.util.Arrays.binarySearch(primeCapacities, desiredCapacity);
    322.         if(desiredCapacity==100) System.out.println("i="+i);
    323.         if (i< 0) {
    324.              i = -i -1;
    325.         }
    326.         return primeCapacities[i];
    327.     }
    328.    private void printState(){
    329.       for(int i=0;i< state.length;i++)
    330.         System.out.print(state[i]+"  ");
    331.       System.out.println();
    332.    }
    333.    
    334.     public static final int LARGEST_PRIME = Integer.MAX_VALUE; //最大的素数.
    335.    
    336.     private static final int[] primeCapacities = {//容量素数表
    337.         LARGEST_PRIME,
    338.         //chunk #1
    339.         5,11,23,47,97,197,397,797,1597,3203,6421,12853,25717,51437,102877,205759,
    340.         411527,823117,1646237,3292489,6584983,13169977,26339969,52679969,105359939,
    341.         210719881,421439783,842879579,1685759167,
    342.         //chunk #2
    343.         433,877,1759,3527,7057,14143,28289,56591,113189,226379,452759,905551,1811107,
    344.         3622219,7244441,14488931,28977863,57955739,115911563,231823147,463646329,927292699,
    345.         1854585413,
    346.         //chunk #3
    347.         953,1907,3821,7643,15287,30577,61169,122347,244703,489407,978821,1957651,3915341,
    348.         7830701,15661423,31322867,62645741,125291483,250582987,501165979,1002331963,
    349.         2004663929,
    350.         //chunk #4
    351.         1039,2081,4177,8363,16729,33461,66923,133853,267713,535481,1070981,2141977,4283963,
    352.         8567929,17135863,34271747,68543509,137087021,274174111,548348231,1096696463,
    353.         //chunk #5
    354.         31,67,137,277,557,1117,2237,4481,8963,17929,35863,71741,143483,286973,573953,
    355.         1147921,2295859,4591721,9183457,18366923,36733847,73467739,146935499,293871013,
    356.         587742049,1175484103,
    357.         //chunk #6
    358.         599,1201,2411,4831,9677,19373,38747,77509,155027,310081,620171,1240361,2480729,
    359.         4961459,9922933,19845871,39691759,79383533,158767069,317534141,635068283,1270136683,
    360.         //chunk #7
    361.         311,631,1277,2557,5119,10243,20507,41017,82037,164089,328213,656429,1312867,
    362.         2625761,5251529,10503061,21006137,42012281,84024581,168049163,336098327,672196673,
    363.         1344393353,
    364.         //chunk #8
    365.         3,7,17,37,79,163,331,673,1361,2729,5471,10949,21911,43853,87719,175447,350899,
    366.         701819,1403641,2807303,5614657,11229331,22458671,44917381,89834777,179669557,
    367.         359339171,718678369,1437356741,
    368.         //chunk #9
    369.         43,89,179,359,719,1439,2879,5779,11579,23159,46327,92657,185323,370661,741337,
    370.         1482707,2965421,5930887,11861791,23723597,47447201,94894427,189788857,379577741,
    371.         759155483,1518310967,
    372.         //chunk #10
    373.         379,761,1523,3049,6101,12203,24407,48817,97649,195311,390647,781301,1562611,
    374.         3125257,6250537,12501169,25002389,50004791,100009607,200019221,400038451,800076929,
    375.         1600153859
    376.     };
    377.     static {
    378.         java.util.Arrays.sort(primeCapacities);
    379.     }
    380.      public static void main(String args[]){
    381.       LongHashMap lh=new LongHashMap(5);//初始容量为5
    382.       System.out.println("size="+lh.size());
    383.       for(int i=0;i< 3;i++)//先放三个
    384.         lh.put(i, Integer.valueOf(i));
    385.       System.out.println("size="+lh.size());
    386.       lh.removeKey(1);//删除二个
    387.       lh.removeKey(2);
    388.       lh.put(123,"ok");//添加一个
    389.       //看看状态
    390.       lh.printState();
    391.       lh.put(1234,"oo");//再放一个
    392.       //看看状态
    393.       lh.printState();
    394.       //取出来
    395.       System.out.println(lh.get(0));
    396.       System.out.println(lh.get(123));
    397.       System.out.println(lh.get(1234));
    398.       
    399.     }
    400. }
    复制代码
    运行:
    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

       
         
         
          
          

            
          

            
          
         
       

      


    源码下载:http://file.javaxxz.com/2014/12/3/000714812.zip
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-25 04:18 , Processed in 0.401835 second(s), 46 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表