Golang hashmap 的使用及實現(xiàn)

基本語法

定義hashmap變量

由于go語言是一個強類型的語言姑食,因此hashmap也是有類型的褥紫,具體體現(xiàn)在key和value都必須指定類型,比如聲明一個key為string,value也是string的map,
需要這樣做

var m map[string]string // 聲明一個hashmap蒋腮,還不能直接使用,必須使用make來初始化
m = make(map[string]string) // 初始化一個map
m = make(map[string]string, 3) // 初始化一個map并附帶一個可選的初始bucket(非準(zhǔn)確值藕各,只是有提示意義)

m := map[string]string{} // 聲明并初始化

m := make(map[string]string) // 使用make來初始化

大部分類型都能做key池摧,某些類型是不能的,共同的特點是:不能使用==來比較激况,包括: slice, map, function

get,set,delete

m := map[string]int
m["a"] = 1

fmt.Println(m["a"]) // 輸出 1

// 如果訪問一個不存在的key作彤,返回類型默認(rèn)值
fmt.Println(m["b"]) // 輸出0

// 測試key是否存在
v, ok := m["b"]

if ok {
    ...
}

// 刪除一個key
delete(m, "a")

迭代器

// 只迭代key
for k := range m {
    ...
}

// 同時迭代key-value
for k, v := range m {
    ...
}

在迭代的過程中是可以對map進(jìn)行刪除和更新操作的,規(guī)則如下:

  • 迭代是無序的誉碴,跟插入是的順序無關(guān)
  • 迭代的過程中刪除一個key宦棺,無論遍歷還是沒有遍歷過都不會再遍歷到
  • 迭代的過程中添加一個key,不確定是否能遍歷到
  • 未初始化的map也可以迭代

其他

  • map的value是不可取地址的黔帕,意味著 &m["a"]這樣的語法是非法的
  • len和cap分別可以獲取當(dāng)前map的kv個數(shù)和總?cè)萘?/li>

內(nèi)部結(jié)構(gòu)

hashmap結(jié)構(gòu)

golang的map是hash結(jié)構(gòu)的,意味著平均訪問時間是O(1)的蹈丸。同傳統(tǒng)的hashmap一樣成黄,由一個個bucket組成:


// A header for a Go map.
type hmap struct {
 // Note: the format of the Hmap is encoded in ../../cmd/internal/gc/reflect.go and
 // ../reflect/type.go.  Don't change this structure without also changing that code!
 count int // # live cells == size of map.  Must be first (used by len() builtin)
 flags uint8
 B     uint8  // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
 hash0 uint32 // hash seed

 buckets    unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
 oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
 nevacuate  uintptr        // progress counter for evacuation (buckets less than this have been evacuated)

 // If both key and value do not contain pointers and are inline, then we mark bucket
 // type as containing no pointers. This avoids scanning such maps.
 // However, bmap.overflow is a pointer. In order to keep overflow buckets
 // alive, we store pointers to all overflow buckets in hmap.overflow.
 // Overflow is used only if key and value do not contain pointers.
 // overflow[0] contains overflow buckets for hmap.buckets.
 // overflow[1] contains overflow buckets for hmap.oldbuckets.
 // The first indirection allows us to reduce static size of hmap.
 // The second indirection allows to store a pointer to the slice in hiter.
 overflow *[2]*[]*bmap
}

bucket內(nèi)部

// A bucket for a Go map.
type bmap struct {
 tophash [bucketCnt]uint8 // Followed by bucketCnt keys and then bucketCnt values.
 // NOTE: packing all the keys together and then all the values together makes the
 // code a bit more complicated than alternating key/value/key/value/... but it allows
 // us to eliminate padding which would be needed for, e.g., map[int64]int8.
 // Followed by an overflow pointer.
}

根據(jù)一個key得到value

func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer

maptype為map的類型信息,是編譯器在編譯期靜態(tài)生成的逻杖,里面包含了map的一些元信息奋岁,比如 key和value的類型信息等等

  • *hmap為map的header,即map的引用
  • key是一個通用的指針荸百,代表了key的引用
  • 返回值為一個指針闻伶,指向?qū)?yīng)的value引用

hash計算找到bucket

那我們怎么訪問到對應(yīng)的bucket呢,我們需要得到對應(yīng)key的hash值


alg := t.key.alghash := alg.
hash(key, uintptr(h.hash0))
m := uintptr(1)<<h.B - 1
b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))

根據(jù) tophash 和 key 定位到具體的 bucket

  • tophash 可以快速試錯够话,如果 tophash 不相等直接跳過
  • tophash 相等的話蓝翰,根據(jù) key 的比較來判斷是否相等,如果相等則找到
  • 如果當(dāng)前 bucket 都試玩還沒有找到女嘲,則調(diào)到下一個 bucket

擴(kuò)容


各個參數(shù)的意思:

  • %overflow 溢出率畜份,平均一個 bucket 有多少個 kv 的時候會溢出
  • bytes/entry 平均存一個 kv 需要額外存儲多少字節(jié)的數(shù)據(jù)
  • hitprobe 找到一個存在的 key 平均需要找?guī)紫?/li>
  • missprobe 找到一個不存在的 key 平均需要找?guī)紫?/li>

目前采用的是這一行:


作者丨icexin
鏈接丨http://t.cn/RCXgEjr

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市欣尼,隨后出現(xiàn)的幾起案子爆雹,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钙态,死亡現(xiàn)場離奇詭異慧起,居然都是意外死亡,警方通過查閱死者的電腦和手機册倒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進(jìn)店門蚓挤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人剩失,你說我怎么就攤上這事屈尼。” “怎么了拴孤?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵脾歧,是天一觀的道長。 經(jīng)常有香客問我演熟,道長鞭执,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任芒粹,我火速辦了婚禮兄纺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘化漆。我一直安慰自己估脆,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布座云。 她就那樣靜靜地躺著疙赠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪朦拖。 梳的紋絲不亂的頭發(fā)上圃阳,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天,我揣著相機與錄音璧帝,去河邊找鬼捍岳。 笑死,一個胖子當(dāng)著我的面吹牛睬隶,可吹牛的內(nèi)容都是我干的锣夹。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼理疙,長吁一口氣:“原來是場噩夢啊……” “哼晕城!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起窖贤,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤砖顷,失蹤者是張志新(化名)和其女友劉穎贰锁,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體滤蝠,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡豌熄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了物咳。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锣险。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖览闰,靈堂內(nèi)的尸體忽然破棺而出芯肤,到底是詐尸還是另有隱情,我是刑警寧澤压鉴,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布崖咨,位于F島的核電站,受9級特大地震影響油吭,放射性物質(zhì)發(fā)生泄漏击蹲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一婉宰、第九天 我趴在偏房一處隱蔽的房頂上張望歌豺。 院中可真熱鬧,春花似錦心包、人聲如沸类咧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽轮听。三九已至,卻和暖如春岭佳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背萧锉。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工珊随, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人柿隙。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓叶洞,卻偏偏與公主長得像,于是被迫代替她去往敵國和親禀崖。 傳聞我的和親對象是個殘疾皇子衩辟,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容