日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
淺談Hashtable與Dictionary的異同

以前對于這兩個集合類的認識只是停留在是否支持泛型上,這幾天趁著看算法導(dǎo)論的機會,把兩個類的內(nèi)部的實現(xiàn)機制好好的了解了一下。

創(chuàng)新互聯(lián)公司專注于當陽企業(yè)網(wǎng)站建設(shè),響應(yīng)式網(wǎng)站,成都商城網(wǎng)站開發(fā)。當陽網(wǎng)站建設(shè)公司,為當陽等地區(qū)提供建站服務(wù)。全流程按需網(wǎng)站策劃,專業(yè)設(shè)計,全程項目跟蹤,創(chuàng)新互聯(lián)公司專業(yè)和態(tài)度為您提供的服務(wù)

Hashtable和Dictionary從數(shù)據(jù)結(jié)構(gòu)上來說都屬于Hashtable,都是對關(guān)鍵字(鍵值)進行散列操作,將關(guān)鍵字散列到Hashtable的某一個槽位中去,不同的是處理碰撞的方法。散列函數(shù)有可能將不同的關(guān)鍵字散列到Hashtable中的同一個槽中去,這個時候我們稱發(fā)生了碰撞,為了將數(shù)據(jù)插入進去,我們需要另外的方法來解決這個問題。

鏈接法(chaining)

在鏈接法中,把散列到同一個槽中的所有元素放在一個鏈表中,槽中有一個指針,指向鏈表的頭,如果沒有的話,則為NIL。對于一個能存放n個元素,具有m個槽位的散列表,我們定義裝載因子a為n/m,即一個鏈中平均存儲的元素的個數(shù)。

鏈接法中的加入,刪除,尋找操作其實基本上就是鏈表的基本操作。在這里就不仔細講了。

開放尋址法(open addressing)

在開放尋址法中,所有的元素都保存在散列表中,而不是像鏈接法,數(shù)據(jù)保存在外部的鏈表中,在開放尋址法中,由于數(shù)據(jù)全部存儲在散列表中,所以槽位一定會大于等于n,也就是說,裝載因子一定會小于等于1。

在開放尋址法中,當要插入一個元素時,我們將關(guān)鍵字和探查號(從0開始累加)作為輸入傳給散列函數(shù),散列函數(shù)返回對應(yīng)的槽位。插入的時候首先查找hash(key,0)這個槽,如果不為空則探查號+1,繼續(xù)查下一個槽,直到找到空槽,或者得知散列表已滿。查找的過程和插入類似,查找關(guān)鍵字的時候如果我們碰到了空槽,查找就結(jié)束,因為如果關(guān)鍵字存在的話,那么也應(yīng)該會出現(xiàn)在這個地方。

開放尋址法中比較特殊的是刪除操作,如果刪除數(shù)據(jù)置為null的話,那么就會有一個問題,比如我們插入過程中插入k的時候發(fā)現(xiàn)槽i已經(jīng)被占用,我們插到后面的槽中,如果刪除的時候我們簡單的將槽i置為null,那么查找的時候關(guān)鍵字k就不會被找到。這個問題我們可以用一個標志位來解決。具體的實現(xiàn)會在下面講到。

雙重散列

開放尋址法的探查方法有多種,在這里只講一下雙重探查,因為這種方法是最好的方法之一,而且它被用在Hashtable中。

這里和為輔助散列函數(shù),第一次為,后續(xù)的探查位置在的基礎(chǔ)上加上偏移量,然后對m進行模運算。這里需要提一下的是為了查找整個散列表,需要與槽的大小m互質(zhì),等下可以看到在Hashtable類中是如何滿足這個條件的。

在解釋了鏈接法和開放尋址法后,來講講Hashtable和Dictionary。

Hashtable這個類采用的是開放尋址法來解決碰撞的問題,下面來看看Hashtable的一個構(gòu)造函數(shù)

  
 
 
 
  1. this.loadFactor = 0.72f * loadFactor;    
  2.  double num = ((float) capacity) / this.loadFactor;    
  3.  if (num > 2147483647.0)    
  4.  {    
  5.    throw new ArgumentException(Environment.GetResourceString("Arg_HTCapacityOverflow"));    
  6. }    
  7.  int num2 = (num > 11.0) ? HashHelpers.GetPrime((int) num) : 11;    
  8.  this.buckets = new bucket[num2];    
  9.  this.loadsize = (int) (this.loadFactor * num2);    
  10.  this.isWriterInProgress = false;  

構(gòu)造函數(shù)會在傳入裝載因子的基礎(chǔ)上乘以0.72,這個值是微軟認為的比較理想的一個值。上面已經(jīng)說過了在雙重散列時需要保持和槽的大小m互質(zhì),我們只需要保證m為質(zhì)數(shù),而比m小,這樣就能保證他們總是互質(zhì)。在這里HashHelpers.GetPrime實現(xiàn)的就是傳回一個比num大的質(zhì)數(shù),這樣能保證num2這個量總為一個質(zhì)數(shù),然后把槽數(shù)組建立起來。

(this.GetHash(key) & 0x7fffffff)這個相當于雙散列公式中的,1 + ((uint) (((seed >> 5) + 1) % (hashsize - 1)));則相當于,

槽中的hash_coll用來存放key對應(yīng)的hashcode,最高位用來標識是否發(fā)生了碰撞,發(fā)生碰撞的槽的最高位會被置為1,搜索的時候,如果最高位為1那么搜尋函數(shù)會繼續(xù)搜索,注意contains方法中的while條件,

   
 
 
 
  1. do   
  2.  {    
  3.     bucket = buckets[index];    
  4.    if (bucket.key == null)    
  5.    {    
  6.       return false;    
  7.     }    
  8.     if (((bucket.hash_coll & 0x7fffffff) == num3) && this.KeyEquals(bucket.key, key))    
  9.     {    
  10.        return true;    
  11.    }    
  12.     index = (int) ((index + num2) % ((ulong) buckets.Length));    
  13.  }    
  14.  while ((bucket.hash_coll < 0) && (++num4 < buckets.Length));  

BTW,我當時看這個方法的時候覺得搜尋函數(shù)其實也可以通過跳過bucket.key == this.buckets的項來寫,因為在移除方法中如果bucket.hash_coll < 0的話,那么bucket.key = this.buckets, 后來想了一下,bucket.hash_coll < 0這樣效率更高,這里就不說為什么了,愛思考的朋友在后面寫下你的答案吧。

在Add方法里面需要對count進行檢查,如果達到了設(shè)定的值,這個時候需要對Hashtable進行擴容,擴大的容量是當前容量的2倍以上的一個質(zhì)數(shù),然后對里面已經(jīng)存在的元素重新進行hash操作,相當于重新插入新的槽數(shù)組中。對于Insert方法中的index這個變量的作用我在看代碼的時候還是有點疑問的,如果有知道的朋友麻煩在留言中告知。

Dictionary這個泛型類采用的是鏈接法來解決碰撞,其中的bucket存儲的是指向Entry的下標,Entry就相當于鏈表中的節(jié)點,Entry中存儲的又有指向下一個產(chǎn)生碰撞的元素的下標。稍有不同的是,這里的Entry是一個數(shù)組。

   
 
 
 
  1. public struct Entry    
  2. {    
  3.    public int hashCode;    
  4.    public int next;    
  5.   public TKey key;    
  6.    public TValue value;    
  7.  }  

Dictionary的Add操作首先計算元素的Hash值,然后根據(jù)Hash值尋找bucket,找到相應(yīng)的bucket后將值存入Entry中,并將bucket指向相應(yīng)的Entry.查詢操作邏輯是根據(jù)Hash值找到相應(yīng)的bucket然后通過bucket到Entry數(shù)組中進行尋找。

稍微需要提一下的是Remove方法,為了將刪除的節(jié)點的Entry進行重用,Dictionary中有一個freeList字段,刪除的節(jié)點的下標值,為賦給freeList,在Add操作的時候如果freeList>0則將數(shù)據(jù)插入到freeList指向的Entry中去。

原文鏈接:http://www.cnblogs.com/MichaelYin/archive/2011/02/14/1954724.html


當前名稱:淺談Hashtable與Dictionary的異同
網(wǎng)站鏈接:http://m.5511xx.com/article/coijpse.html