1. 程式人生 > >Collection原始碼之路(3)——HashMap 上篇

Collection原始碼之路(3)——HashMap 上篇

首先糾正一個錯誤,HashMap不屬於Collection,而是屬於Map,之所以本篇文章叫Collection原始碼之路,是為了和之前的文章呼應。

之前的兩篇文章介紹我的我們實際開發中用到最多的ArrayList或者結構簡單的LinkedList,但是找工作面試問得最多的卻是HashMap,我被問了不下6次吧,當我仔細閱讀原始碼的時候才發現,這個資料結構真的是精髓中的精髓,一篇文章講起來可能會非常長,於是分幾篇介紹。

首先我們看下HashMap的結構圖

這裡寫圖片描述

上面是陣列,陣列中的元素是連結串列或者紅黑樹,okay 先把這個大致結構認識下,我們開始補補課外知識

位運算&

我們知道 &符號在位運算的時候表示的含義是

& 兩個數一個為0就為0

比如 a=1,b=1, a&b=1; a=1,b=0, a&b=0
比如 a=11,b=11, a&b=11; a=11,b=10, a&b=10
我們計算機是二進位制計數,十進位制8等於二進位制的1000,位運算多用於2的n次方的數上是因為2的n次方數對於與運算來說是極其便利的,接下來舉例說明

若b等於2的n次方,a%b=a&(b-1)

我們就以b=8,a分別為1和9為例

a=1時
 b =  1000
 b-1
= 0111 a= 0001 a&(b-1)=0001a=9時 b = 1000 b-1= 0111 a= 1001 a&(b-1)=0001

簡單來說,因為2的n次方-1這個數1比較多,不會影響除數,所以 知識點1:當b=2的次方的時候,a&(b-1)這個公式一般被用來求餘數,如果b不等於2的n次方,這個規律就不存在了,讀者可以去驗證

若b等於2的n次方,a&b 要麼值為0要麼值為b

我們就以b=8,a分別為1和9為例

a=1時
 b =  1000
 a=   0001
 a&b=0000=0a=9時
 b =  1000
 a=   1001
 a
&b=1000=8

所以 知識點2:當b=2的n次方的時候,a&b只能為0或者b

既然知識點一說可以通過這種方式求餘數,那麼我程式碼裡面如果遇到18%8這種情況是寫成18%8好還是寫成18&(8-1)這種方式好呢?位運算效率更高

如果機器比較快是看不出來很大差距的,但是如果我們在android裝置上測試就很容易看出來區別

 Log.i("TAG", "start: "+System.currentTimeMillis()%10000);
        for(int i=0;i<100000000;i++){
            if((i%1024)==0){

            }

        }
 Log.i("TAG", "end: "+System.currentTimeMillis()%10000);

平均消耗時間500ms左右

 Log.i("TAG", "start: "+System.currentTimeMillis()%10000);
        for(int i=0;i<100000000;i++){
            if((i&(1023))==0){

            }

        }
 Log.i("TAG", "end: "+System.currentTimeMillis()%10000);

平均消耗時間大約300ms

的確是位運算效率更高,為什麼呢?在計算機處理中,加減很簡單但是乘除很複雜,所以老一輩開發者在機器執行速度不快的時候更多考慮的是效率優先。