程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 從內部剖析C# 集合之---- HashTable

從內部剖析C# 集合之---- HashTable

編輯:C#入門知識

計劃寫幾篇文章專門介紹HashTable,Dictionary,HashSet,SortedList,List 等集合對象,從內部剖析原理,以便在實際應用中有針對性的選擇使用。 這篇文章先介紹HashTable  。        先例舉幾個問題:1,Hashtable為什麼速度查詢速度快,而添加速度相對慢,且其添加和查詢速度之比相差一個數量等級?                              2,裝填因子( Load Factor)是什麼,hashtable默認的裝填因子是多少?                              3,hashtable裡的元素是順序排序的嗎?                              4,hashtable內部的數據桶(數組)默認長度多少,其長度為什麼只能是素數?   Hashtable中的數據實際存儲在內部的一個數據桶裡(bucket結構數組),其和普通的數組一樣,容量固定,根據數組索引獲取值。   下面從正常使用Hashtable場景看內部是如何實現的,內部都做了哪些工作。   一,new一個Hashtable,Hashtable ht=new Hashtable();   Hashtable有多個構造函數,常用的是無參構造函數:Hashtable ht=new Hashtable(),在new一個hashtable時,其內部做了如下工作:調用Hashtable(int capacity,float loadFactor),其中capacity為:0,loadFactor為:1,然後初始化bocket數組大小為3,裝載因子為0.72(該值是微軟權衡後給的值),如下圖所示,該圖截取Reflector       二,向Hashtable添加一個元素,ht.Add("a","123")      1,判斷當前Hashtable :ht的元素個數與bucket數組之比是否超過裝載因子0.72,          1)小於0.72:對a進行哈希取值,然後將得到的值與bucket數組長度進行取模計算,將取模的結果插入到bucket數組對應索引,將“123”賦值其value.               因為哈希值可能會重復(不明白的百度一下),從而導致地址沖突,Hashtable 采用的是 "開放定址法" 處理沖突, 具體行為是把 HashOf(k) % Array.Length 改為 (HashOf(k) + d(k)) % Array.Length , 得出另外一個位置來存儲關鍵字 "a" 所對應的數據, d 是一個增量函數. 如果仍然沖突, 則再次進行增量, 依此循環直到找到一個 Array 中的空位為止。          2)  大於0.72:對bucket數組進行擴容,a, 新建一個數組(該數組的大小為兩倍於當前容量最小的素數,比如當前數組長度是3,那麼新數組長度為7)。                                                              b,將原來數組元素拷貝到新的數組中,因為bocket數組長度變了,所以需要對所有key重新哈希計算(這是影響hashtable性能的重要因素)。                        c, 進行上面a步驟。         三,通過key獲取Hashtable對應的value,var v=ht["a"];       1) 計算"a"的哈希值。       2)將計算的結果與bocket數組長度進行取模計算,因為哈希值可能會沖突,所以類似定位索引上的key可能與輸入的key不相同,這時繼續查找下一個位置。。。。。       3)取模計算結果即是存儲在bocket數組上"123"的索引。       Hashtable還有很多方法,比如Clear ,Remove ,ContainsKey,ContainsValue等方法,因篇幅有限這裡就不一一介紹了。         寫到這裡來回答一下篇幅開頭的幾個問題。   1,Hashtable查詢速度快是因為內部是基於數組索引定位的,稍微消耗性能的是取KEY的哈希值,添加性能相對查詢慢是因為:a,添加元素時可能會地址沖突,需要重新定位地址 。 b,擴容後 數組拷貝,重新哈希計算舊數組所有key。   2, 裝填因子是Hashtable“已存元素個數/內部bucket數組長度”,這個比值太大會造成沖突概率增大,太小會造成空間的浪費。默認是0.72,該值是微軟經過大量實驗得出的一個比較平衡的值,裝填因子范圍 0.1<loadFactor<1,否則拋出ArgumentOutOfRangeException異常。   3,不是順序的(各位看了文章應該知道為什麼不是順序的了吧?)   4,默認長度是3,我看的是.net framework 4.5版本反編譯的代碼,其他版本的.net framework不確定是不是這個值。為什麼擴容的數組長度一定要是素數呢?因為素數有一個特點,只能被自己和1整除,如果不是素數那麼在進行取模計算的時候可能會出現多個值。      今天就寫到這,有很多不對或不合理的地方希望各位看到了及時指出,本菜鳥知錯就改!!!   先介紹Hashtable,下篇介紹dictionary,到時綜合分析在項目中選擇使用他們的場景。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved