導航:首頁 > 源碼編譯 > map變數源碼

map變數源碼

發布時間:2023-11-29 21:46:40

1. golang map源碼淺析

golang 中 map的實現結構為: 哈希表 + 鏈表。 其中鏈表,作用是當發生hash沖突時,拉鏈法生成的結點。

可以看到, []bmap 是一個hash table, 每一個 bmap是我們常說的「桶」。 經過hash 函數計算出來相同的hash值, 放到相同的桶中。 一個 bmap中可以存放 8個 元素, 如果多出8個,則生成新的結點,尾接到隊尾。

以上是只是靜態文件 src/runtime/map.go 中的定義。 實際上編譯期間會給它加料 ,動態地創建一個新的結構:

上圖就是 bmap的內存模型, HOB Hash 指的就是 top hash。 注意到 key 和 value 是各自放在一起的,並不是 key/value/key/value/... 這樣的形式。源碼里說明這樣的好處是在某些情況下可以省略掉 padding 欄位,節省內存空間。

每個 bmap設計成 最多隻能放 8 個 key-value 對 ,如果有第 9 個 key-value 落入當前的 bmap,那就需要再構建一個 bmap,通過 overflow 指針連接起來。

map創建方法:

我們實際上是通過調用的 makemap ,來創建map的。實際工作只是初始化了hmap中的各種欄位,如:設置B的大小, 設置hash 種子 hash 0.

注意 :

makemap 返回是*hmap 指針, 即 map 是引用對象, 對map的操作會影響到結構體內部

使用方式

對應的是下面兩種方法

map的key的類型,實現了自己的hash 方式。每種類型實現hash函數方式不一樣。

key 經過哈希計算後得到hash值,共 64 個 bit 位。 其中後B 個bit位置, 用來定位當前元素落在哪一個桶里, 高8個bit 為當前 hash 值的top hash。 實際上定位key的過程是一個雙重循環的過程, 外層循環遍歷 所有的overflow, 內層循環遍歷 當前bmap 中的 8個元素

舉例說明: 如果當前 B 的值為 5, 那麼buckets 的長度 為 2^5 = 32。假設有個key 經過hash函數計算後,得到的hash結果為:

外層遍歷bucket 中的鏈表

內層循環遍歷 bmap中的8個 cell

建議先不看此部分內容,看完後續 修改 map中元素 -> 擴容 操作後 再回頭看此部分內容。

擴容前的數據:

等量擴容後的數據:

等量擴容後,查找方式和原本相同, 不多做贅述。

兩倍擴容後的數據

兩倍擴容後,oldbuckets 的元素,可能被分配成了兩部分。查找順序如下:

此處只分析 mapaccess1 ,。 mapaccess2 相比 mapaccess1 多添加了是否找到的bool值, 有興趣可自行看一下。

使用方式:

步驟如下:

擴容條件 :

擴容的標識 : h.oldbuckets != nil

假設當前定位到了新的buckets的3號桶中,首先會判斷oldbuckets中的對應的桶有沒有被搬遷過。 如果搬遷過了,不需要看原來的桶了,直接遍歷新的buckets的3號桶。

擴容前:

等量擴容結果

雙倍擴容會將old buckets上的元素分配到x, y兩個部key & 1 << B == 0 分配到x部分,key & 1 << B == 1 分配到y部分

注意: 當前只對雙倍擴容描述, 等量擴容只是重新填充了一下元素, 相對位置沒有改變。

假設當前map 的B == 5,原本元素經過hash函數計算的 hash 值為:

因為雙倍擴容之後 B = B + 1,此時B == 6。key & 1 << B == 1, 即 當前元素rehash到高位,新buckets中 y 部分. 否則 key & 1 << B == 0 則rehash到低位,即x 部分。

使用方式:

可以看到,每一遍歷生成迭代器的時候,會隨機選取一個bucket 以及 一個cell開始。 從前往後遍歷,再次遍歷到起始位置時,遍歷完成。

https://www.qcrao.com/2019/05/22/dive-into-go-map/

https://draveness.me/golang/docs/part2-foundation/ch03-datastructure/golang-hashmap/

https://www.bilibili.com/video/BV1Q4411W7MR?spm_id_from=333.337.search-card.all.click

2. 關於C++ STL裡面的map 今天見的代碼(見問題補充)為什麼開始就能判斷b[str1]==0;是int的初始都是0嗎

你可以看看map的源碼,其中[]的實現是這樣的:

mapped_type&operator[](key_type&&_Keyval)
{
iterator_Where=this->lower_bound(_Keyval);

if(_Where==this->end()
||this->comp(_Keyval,this->_Key(_Where._Mynode())))
_Where=this->insert(_Where,
_STDpair<key_type,mapped_type>(
_STDmove(_Keyval),
mapped_type()));
return((*_Where).second);
}

首先,會在map查找這個鍵值的項,map如果不包含某個鍵值,會返回map的end,然後它發現此鍵值沒有找到(_Where == this->end())的話,會自動在末尾插入(this->insert(_Where)一個以你輸入的鍵值和value的默認值(mapped_type())構成的對兒(pair),然後返回這個插入項的值(second,鍵是first)。而int的默認構造函數int(),就是0。

也就是時候,哪怕你沒有對map進行插入操作,哪怕只是用[]判斷了下返回值是否是0,map對象也會自動添加一項。

不過一般判斷map是否包含一個鍵,是用map的find方法,判斷find的返回結果是否是map的end。

3. Mapbox源碼分析(2)url解析

通過源碼,我們來一步步分析Mapbox地圖引擎如何進行指定字元串變數解析成url地址載入的,這里是基於5.3.0的版本.

在官方demo中,我們不僅可以載入本地樣式文件,已定義樣式文件和網路在線文件,它們的格式分別是

1. "asset://test.json"

2 . "https://www.mapbox.com/android-docs/files/mapbox-raster-v8.json"

3 . "mapbox://styles/mapbox/streets-v10"

這些格式,那麼Mapbox如果解析這些字元串去獲取到需要的樣式數據呢?我們從 Mapbox源碼分析(1)樣式載入 這篇的loadURL()方法開始看起

我們在這里看到,樣式的數據是通過fileSource.request進行請求載入的,通過調試我們發現這個fileSource是FileSource的子類DefaultFileSource,那麼我們先看看這個DefaultFileSource是什麼時候傳進來的

我們在這里看到,是在構造方法時對fileSource變數進行初始化的,那麼我們只需要看到Style::Impl對象什麼時候構造的,便知道了fileSource的來源,繼續往回找

在這里我們發現Impl對象的fileSource是Style對象構造時傳進來的,那麼我們繼續往回找

這里我們看到Style對象是通過map.cpp里的getStyle對象獲取的,而style對象是在Map::Impl::Impl構造方法時初始化的,繼續往回找

這里我們其實也能大概猜出來Map::Impl對象是在Map構造方法時初始化的,那麼map對象又是什麼時候初始化的,是不是覺得很繞,馬上就快到了,我們找到native_map_view.cpp文件,發現在NativeMapView構造方法中構造了map對象

到這里我們已經基本清楚fileSource的來源了,是JAVA層NativeMapView對象初始化的時候傳下來的,我們繼續看到開頭,既然我們已經知道fileSource對象是DefaultFileSource,那麼它調用的request方法,也就是調用的DefaultFileSource的request方法,這里我們看到default_file_source.cpp文件

這里我們看到它轉到了它的實現類的request方法

這里我們可以看到根據url的不同,和載入方法的不同,將請求分別轉給了assetFileSource,localFileSource,onlineFileSource等的request方法,這里我們看onlineFileSource的request方法

看到這里我們看到根據請求的類型不同,去處理不同的url,在這些參數里我們看下apiBaseURL這個變數,這是一個base url,指定了伺服器地址,我們在constants.hpp文件中找到了它

constexpr const char* API_BASE_URL = "https://api.mapbox.com";

繼續往下看,我們選normalizeStyleURL()方法往下看

這里我們看到它先驗證了一下url,然後將url字元串包裝成URL對象,然後進行一個拼接成tpl變數,最後再通過transformURL函數進行一個轉換,這里我們先看它如何包裝這個URL對象的

這里我們看到它將字元串分解成query,scheme,domain,path四個變數進行存儲,我們再看看transformURL()函數

這里我們看到根據url的不同變數值進行了再次字元串拼接,甚至根據路徑的不同,繼續拆分成Path對象,最後將拼接結果返回,到這里有關url解析拼接的過程就講完了.

4. map函數的用法python

map函數的用法如下:

map(func, lst) ,將傳⼊的函數變數 func 作⽤到 lst 變數的每個元素中,並將結果組成新的列表 (Python2)/ 迭代器(Python3) 返回。

注意:

map()返回的是一個迭代器,直接列印map()的結果是返回的一個對象。

map函數示例代碼:

lst = ['1', '2', '3', '4', '5', '6']

print(lst)

lst_int = map(lambda x: int(x), lst)

# print(list(lst_int))

for i in lst_int:

print(i, end=' ')

print()

print(list(lst_int))

閱讀全文

與map變數源碼相關的資料

熱點內容
電腦用文件夾玩大型游戲 瀏覽:252
安卓耳塞失靈怎麼辦 瀏覽:763
華三交換機保存命令 瀏覽:603
命令方塊怎麼調鍵盤 瀏覽:841
不把密碼存在伺服器上怎麼辦 瀏覽:398
怎麼讓指令方塊的命令消失 瀏覽:543
用單片機做plc 瀏覽:404
雲伺服器進入子目錄命令 瀏覽:795
伺服器機櫃如何配電 瀏覽:578
怎麼刪除iphone資源庫里的app 瀏覽:940
pdf魚 瀏覽:648
單片機pcf8591什麼作用 瀏覽:805
sql命令學院 瀏覽:283
加密軟體在電腦那個盤 瀏覽:988
android獲取外部存儲 瀏覽:573
怎麼查自己家的伺服器地址 瀏覽:858
編程c語言工作好不好 瀏覽:569
單片機焊接地怎麼連接 瀏覽:694
游戲源碼怎麼抓 瀏覽:216
程序員幫大家引走怪物 瀏覽:16