當前位置:編程學習大全網 - 編程語言 - 如何高效的實現壹個計數器map

如何高效的實現壹個計數器map

這本是多年前壹個stackoverflow上的壹個討論,回答中涉及到了多種計數方法。對於壹個key-value結構的map,我們在編程時會經常涉及到key是對象,而value是壹個integer或long來負責計數,從而統計多個key的頻率。

面對這樣壹個基本需求,可能有很多種實現。比如最基本的使用jdk的map直接實現——value是壹個integer或者long。其基本代碼型如下:

1: final Map<String, Integer> freq = new HashMap<String, Integer>();

2: int count = freq.containsKey(word) ? freq.get(word) : 0;

3: freq.put(word, count + 1);

邏輯簡單,判斷是否存在,是則get取值,否則為0,再put進去壹個加1後的值。總***要contain判斷,get,put做三次方法調用。

當然進壹步我們可以把contain判斷去掉,代碼如下:

1: final Map<String, Integer> freq = new HashMap<String, Integer>();

2: Integer count = freq.get(word);

3: if (count == null) {

4: freq.put(word, 1);

5: } else {

6: freq.put(word, count + 1);

7: }

壹般情況,我們做到這個地步,多數人對其邏輯已經滿足,簡單性能也能接受,試著想壹下,難道不是這樣嗎?get加put,解決了。

當然這樣的實現還不夠高效,於是我們開始去嘗試實現或尋找更高效的方法,看看開源的集合類庫是否有需要的:

有個Trove,可以讓我們參考壹下:

1: final TObjectIntHashMap<String> freq = new TObjectIntHashMap<String>();

2: freq.adjustOrPutValue(word, 1, 1);

這樣做,非常優雅啊,性能如何呢?不知道,需要看源碼了解細節。那再看看大名鼎鼎的guava如何呢?

1: AtomicLongMap<String> map = AtomicLongMap.create();

2: map.getAndIncrement(word);

實現依然優雅,但是,但是看這名字,再看源碼,好吧,線程安全的,支持並發,這不好搞了,我們場景需要嗎?不需要的話直覺告訴我們這肯定是“慢”的。再找:

1: Multiset<String> bag = HashMultiset.create();

2: bag.add(word);

這個看上去合適了,bag的實現明顯好很多,而且從語義理解上,這樣的接口更容易讓人理解。

那麽這些方法,性能如何呢?做了個簡單的比較,將26個英文字母做key,均勻循環若幹次比較各個方法的效率(單純時間效率),而且時間不統計構建開銷。外加了壹個線程安全版的concurrentMap實現,而其實google的guava裏的AtomicLongMap也是包裝了juc的concurrentMap而已。裏面有最終極的MutableInt方法,找找看吧,性能最好的就是它了。

  • 上一篇:華為平板M6成學生最愛,升級款或將強勢來襲
  • 下一篇:讀書真的能改變命運嗎
  • copyright 2024編程學習大全網