equals和gethashcode
在了解hashset之前,先看看**實現。在hashset中,要用到兩個函式:equals和gethashcode。因為equals的實現,同時也要重寫gethashcode方法。
那麼,為什麼要重寫gethashcode函式呢?且看看官方警告:如果重寫 gethashcode 方法,您應重寫 equals, ,反之亦然。
如果被重寫 equals 方法將返回true兩個物件是否相等,被重寫的測試時gethashcode 方法必須返回兩個物件相同的值。這裡很明確說到,gethashcode就是為了能讓equals相同的兩個物件,有相同的hash值。
hashset儲存原理
hashset類中有多個成員變數,在儲存中需要我們值得注意的就是 int buckets、slot slots、int freeindex、int lastindex等,分別標記了對應雜湊值的index、hashset物件集合、空的位置和集合最後乙個位置。其中,slot是個結構體,包涵3個成員:int hashcode、t value、int next,分別是雜湊值、物件和下乙個(相同hash值)物件的位置。
當我們查詢乙個物件,是否在hashset中時,會利用該物件的gethashcode,通過計算得到對應的bucket值(bucket儲存插入操作最後乙個物件在slot中的位置,稍後描述),然後再利用equals來比較物件是否相等,不等則一直比較至next=0為止。
所以說,hashset是基於陣列和鍊錶管理的。
插入和刪除
插入的時候,先查詢集合中是否有相同變數(見儲存原理),若沒有,則開始插入新成員。首先看freeindex是否有值(該值僅在刪除操作後產生),若有就用這個位置,若沒有,則用lastindex(最後乙個位置,用完後+1)。因而,找到了插入位置後,開始計算該slot的值:hashcode由gethashcode產生,value就是新成員,而next則是用hashcode計算對應位置中的buckets值(儲存相同hashcode值的物件在slots中的位置),並重新整理bucket值為當前slot。因而我們知道,由於next的計算機制,新插入的物件,會覆蓋原來buckets的值。
刪除操作,同插入一樣,也要查詢到物件。如果是bucket中第乙個物件,在刪除物件同時,bucket修改為該物件next值,否則,則修改上乙個物件的next為該物件的next(相當於將上個物件指標直接指向下乙個物件)。然後,刪除的slot值需要修正:hashcode=-1,value=default,next=freelist。所以我們知道,空位置也形成了乙個鍊錶。
所以,可以看出hashcode管理起來,也需要一點時間的。但是,由於插入和刪除都用了陣列+鍊錶,故速度還是很快的。
遍歷
遍歷使用foreach。這裡要說一點,遍歷的順序和插入的順序可能會不相同(如,對插入第乙個資料刪除,再插入,則會得到該現象)。hashset實現了ienumerable介面,並通過version變數,確保資料在遍歷中不發生變化(操作會改變version值)。
相信大家都很了解ienumerable介面了吧。還有個泛型介面ienumerable。這裡說下current,在兩個介面中都要實現,而非泛型介面current是要用到的,需要完成「丟擲異常」功能(索引超出則丟擲異常),並呼叫了泛型介面current實現。
好,回歸遍歷:movenext 就是對slot進行順序遍歷了,如果hashcode>=0,則說明輸出有效。
總結
總的來說,hashset通過gethashcode值(hash相等才會再比較equal)和equal方法確定是否有相同變數,沒有則可以插入。儲存是通過陣列和鍊錶結合而完成的。
如果學過了演算法與資料結構應該很明白其原理了。當初我記得還有什麼二次雜湊演算法來者的,反正好久沒再接觸了。
本人小白,本文章僅作學習總結,也作交流使用。。
如有錯誤,歡迎指點,謝謝!
插入操作的源**
private bool addifnotpresent(t value)
int hashcode = this.internalgethashcode(value);
int index = hashcode % this.m_buckets.length;
int num3 = 0;
for (int i = this.m_buckets[hashcode % this.m_buckets.length] - 1; i >= 0; i = this.m_slots[i].next)
num3++;
}if (this.m_freelist >= 0)
else
freelist = this.m_lastindex;
this.m_lastindex++;
}this.m_slots[freelist].hashcode = hashcode;
this.m_slots[freelist].value = value;
this.m_slots[freelist].next = this.m_buckets[index] - 1;
this.m_buckets[index] = freelist + 1;
this.m_count++;
this.m_version++;
if ((num3 > 100) && hashhelpers.iswellknownequalitycomparer(this.m_comparer))
return true;
}
C 大會後的一些感想
過了這麼久才寫,實在是有夠懶 一共聽了幾場,分別是 direction for c 0x 遊戲的優化 什麼是高階c 面向目標 程式設計與c 的未來 c 異常處理得與失 多核技術與c 併發程式設計 基於c 的網遊伺服器中介軟體模型 問了許多問題,領回來2本書,呵呵,有夠high。最後一天,我想應該數我...
一些職場感想
不要相信領導給你畫的大餅 離開了,就不要回去 他說的為你好,都是套路而已 你會比你想象的更優秀 不要認為提增加工資不好意思,你不提,他永遠不會給你加工資 這就看你所處的隊友是怎麼樣的 如果隊友是乙個很拼的,可能你需要比他更拼才能出人頭地,當然也要注意方法,不是埋頭苦幹,隊友不知道,領導不知道 如果隊...
一些感想 2021
解決乙個問題,可以靠個人的能力,也可以靠組織的流程,組織的流程就是組織的能力。組織設計流程考慮的是可靠 可重用。論解決問題的效率,通過組織的流程大概率是不如靠個人能力的。但組織擁有很多個 個人 乙個流程可以由多個 個人 共同完成,對於每乙個參與的 個人 感受到的可能是 組織流程比個人能力解決問題更高...