大数据计数原理1+0=1这你都不会算(一)

企业动态
hello哈,大家是不是好久没见到我啦?我也是一直在摸索小伙伴们喜欢看到什么东西,不喜欢看什么东西,还请大家多多支持。为了表示感谢。小蕉在这给你们一鞠躬,二鞠躬,三。事不过三~

[[203755]]

hello哈,大家是不是好久没见到我啦?我也是一直在摸索小伙伴们喜欢看到什么东西,不喜欢看什么东西,还请大家多多支持。为了表示感谢。小蕉在这给你们一鞠躬,二鞠躬,三。事不过三~

1+0=1你都不会谈什么大数据?

这篇呢,又是开坑之作,这是一个系列,主要会将大数据下的计数原理。说到计数,不知道大家会***印象想到什么,我估计会是。。数手指。。没错,小蕉从小学开始就开始数手指,所有20以内的加减法很早就掌握了。研表究明,这估计也是我们现在使用十进制的原因,如果我们每个人每只手都有6只手指,那我们可能就用十二进制了。

好了不扯了,那用程序怎么计数呢?要去重那种。按照我拍脑袋设想呢,***印象,嗯用HastSet准没错,但是HashSet占用的内存有多少你们知道吗?可以装下我一年的米饭。内存占用太大,所以就有了后面的B-tree,Bitmap,Bloom Filter,Linear Counting,LogLog Counting,Adaptive Counting,HyperLogLog Counting,HyperLogLog++ Counting。

如果现在你们一个都听不懂的话,那就对了,但那也木有关系,我会一个一个跟你们讲清楚哒。(如果我不断更的话,嗯)

那***篇就开始讲HashSet是怎么进行计数的吧。首先我们看一下HashSet的底层结构是什么。

  1. from HashSet 
  2. private transient HashMap<E,Object> map; 
  3. public HashSet() { 
  4.     map = new HashMap<E,Object>(); 

唔,咩你甘噶。想不到你是这样的HashSet,底层居然是一个私有的无法序列化的HashMap,黑人问号脸。计数嘛,我们就会想知道,集合中有没有存在过这个数字,那HashSet是怎么知道它自己的集合中有没有存在某个值的呢?

  1. from HashSet 
  2. public boolean contains(Object o) { 
  3.     return map.containsKey(o); 

oh,原来是直接调用了HashMap的containsKey这个方法,那HashMap又是怎么找的呢?

  1. from HashMap 
  2. final Entry<K,V> getEntry(Object key) { 
  3.     int hash = (key == null) ? 0 : hash(key.hashCode()); 
  4.     for (Entry<K,V> e = table[indexFor(hash, table.length)]; 
  5.          e != null
  6.          e = e.next) { 
  7.         Object k; 
  8.         if (e.hash == hash && 
  9.             ((k = e.key) == key || (key != null && key.equals(k)))) 
  10.             return e; 
  11.     } 
  12.     return null

看不懂也没关系我讲给你听。首先算一下key的hash值,然后在自己的HashEntry的数组里面(其实就是一个元素都是链表的数组,哎呀好拗口),找到对应的HashEntry,找到之后呢,再根据链表一个一个找,如果发现key的hash值,引用,或者equals完全相等,嗯没错,那这个key就已经存在在HashSet中啦。这时候计数就不用+1了。

那如果一个值不存在呢?那就计数+1,顺便把自己放到集合里边嘛~怎么放呢?程序员有一句黑话叫,"don't bb,show me the code"。

  1. from HashSet 
  2. private static final Object PRESENT = new Object(); 
  3. public boolean add(E e) { 
  4.     return map.put(e, PRESENT)==null

由此可见,也只是调用了HashMap的put方法,还特么把一个叫PRESENT的不知道什么鬼的静态的私有的无法修改的Object当成value值了。oh好像这样也可以理解,我们只是需要借助HashMap的key就知道重不重复了。至于HashMap是怎么put一个值得呢?

  1. from HashMap 
  2. public V put(K key, V value) { 
  3.     if (key == null
  4.         return putForNullKey(value); 
  5.     int hash = hash(key.hashCode()); 
  6.     int i = indexFor(hash, table.length); 
  7.     for (Entry<K,V> e = table[i]; e != null; e = e.next) { 
  8.         Object k; 
  9.         if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 
  10.             V oldValue = e.value; 
  11.             e.value = value; 
  12.             e.recordAccess(this); 
  13.             return oldValue; 
  14.         } 
  15.     } 
  16.     modCount++; 
  17.     addEntry(hash, key, value, i); 
  18.     return null

好这一堆基本都不用看,就看那个addEntry就够了,上面一大坨大概的意思就是,如果key已经存在了,那就覆盖原有的value值,然后就啥也不干,这不是我们本次的重点(modCount跟线程安全有关感兴趣同学自省度娘)。

  1. from HashMap 
  2.   void addEntry(int hash, K key, V value, int bucketIndex) { 
  3.         Entry<K,V> e = table[bucketIndex]; 
  4.                table[bucketIndex] = new Entry<K,V>(hash, key, value, e); 
  5.                if (size++ >= threshold) 
  6.                    resize(2 * table.length); 
  7.  } 

这一小段大概的意思呢,就是,把原来HashEntry的数组对应hash位置的值拿出来,然后把现在的值接到最前面去。然后非常关键的代码出现了。

size++

哇哇哇,size++,嗯,计数靠谱了,可以计数了。

  1. from HashSet 
  2. public int size() { 
  3.     return map.size(); 
  4. from HashMap 
  5. public int size() { 
  6.     return size

嗯我们可以看到,就是直接把size返回了。

到这里我们已经说完了HashSet的计数原理啦。那么如果有N个值,这个HashSet需要多少空间呢?假设整个HashMap都放满了。

至少需要N*8+PRESENT,还要加上HashEntry的开销,只能说是吃内存大户。

下一次,我们继续聊聊,稍微不太那么占内存的计数方法。

【本文为51CTO专栏作者“大蕉”的原创稿件,转载请通过作者微信公众号“一名叫大蕉的程序员”获取授权】

戳这里,看该作者更多好文

责任编辑:武晓燕 来源: 51CTO专栏
相关推荐

2017-09-30 08:05:41

大数据计数原理

2017-09-19 15:09:50

大数据计数原理

2017-09-12 14:58:27

大数据计数原理

2017-10-13 16:32:49

大数据计数原理

2017-09-26 15:51:29

大数据计数原理

2017-10-25 16:03:08

大数据计数原理

2017-10-27 15:23:56

大数据计数原理

2023-05-16 07:15:11

架构模型对象

2022-03-27 22:07:35

元宇宙虚拟人IBM

2015-03-16 11:33:16

程序员代码bug

2019-12-26 09:56:34

Java多线程内部锁

2021-07-07 06:54:37

网页Selenium浏览器

2017-02-08 19:49:03

内存SSDDRAM

2019-12-17 15:10:21

Python字符串代码

2020-09-27 06:50:56

Java互联网注解

2021-04-20 09:55:37

Linux 开源操作系统

2013-06-05 22:45:25

阿里云

2010-10-26 11:05:27

霍金

2014-12-11 10:01:09

程序员

2016-09-13 22:46:41

大数据
点赞
收藏

51CTO技术栈公众号