將元素的儲存位置和該元素的關鍵碼通過某種函式建立一一對應的關係,構造出來的儲存結構稱之為雜湊表,轉換時借助的函式稱之為雜湊函式,在理想情況下,根據關鍵碼搜尋元素時可以不經過任何比較,一次性從表中查詢到所要搜尋的元素
但是在通過雜湊函式進行元素儲存位置確立的時候會出現,不同元素的關鍵碼通過雜湊函式計算出來的儲存位置是相同的,這便是雜湊衝突
解決雜湊衝突有兩種方式:
當發生雜湊衝突時,如果雜湊表還允許做插入,就把該元素放到「下乙個」空位置上去,怎麼找「下乙個」位置,常見的有線性探測和二次探測,這兩種方式僅在插入元素發生衝突找「下乙個」儲存位置有區別
while
(發生雜湊衝突)
int i =1;
while
(發生雜湊衝突)
用閉雜湊的方式解決雜湊衝突後會出現乙個問題,當需要刪除元素時,該元素恰巧導致了雜湊衝突,如果直接刪除該元素,那麼因衝突重新確立儲存位置的元素將無法根據雜湊函式再次找到
定義乙個動態線性表來構造hash表,由於在表中刪除元素的時候不能直接刪除,所以每個儲存空間不止要存放元素的關鍵碼,還需要標記當前該儲存位置的狀態,需要定義乙個列舉常量來表示狀態,分三種:未存放、存在有效元素、刪除狀態;hash函式也以函式指標的形式新增在結構體中
typedef
int key;
typedef
int(
*hashfunc)
(key,
int)
;typedef
enum
state;
typedef
struct
element;
typedef
struct
ht;
根據要求的容量動態開闢空間,別忘了對開闢的每乙個空間狀態初始值的設定
void
htinit
(ht *pht,
int capacity, hashfunc hashfunc)
}void
htdestroy
(ht *pht)
根據元素的關鍵碼和雜湊計算出元素的儲存位置,判斷當前位置的狀態和關鍵碼是否都符合,否則根據探測原則持續向後查詢,如過遇到的儲存位置狀態為空表示查詢失敗
int
htsearch
(ht *pht, key key)
index =
(index +1)
% pht->capacity;
}return-1
;}
刪除其實上也是乙個查詢的過程,不同的是在進行刪除後,雜湊表中元素個數減1,刪除位置的狀態發生變化
int
htdelete
(ht *pht, key key)
index =
(index +1)
% pht->capacity;
}return-1
;}
插入元素的時需要考慮乙個問題,是否需要擴容,雖然雜湊衝突不可避免,但可以使用一些方法來降低雜湊衝突
負載因子 = pht->size / pht->capacity
根據經驗得知,將負載因子控制在0.8以下,可以有效降低雜湊衝突,超過0.8衝突將會呈指數曲線增長
以下採用控制負載因子,降低雜湊衝突
所以在插入元素之前先要判斷當前的雜湊表負載因子,決定需不需要擴容的問題
需要擴容時可以分為以下三步:申請新空間、搬移資料、釋放舊空間
擴容後的空間與舊空間容量發生變化,所以在資料搬移的過程中需要對元素的儲存位置重新做調整
void
i***pand
(ht *pht)
newcapacity = pht->capacity *2;
htinit
(&tht, newcapacity, pht->hashfunc)
;for
(; icapacity; i++)}
free
(pht->arr)
; pht->arr = tht.arr;
pht->capacity = tht.capacity;
}
插入之前先查詢一遍,如果需要插入元素已經存在,不再進行重複插入,如果不存在,狀態為empty或者delete的位置均可以做插入
int
htinsert
(ht *pht, key key)
i***pand
(pht)
; index = pht->
hashfunc
(key, pht->capacity)
;while
(pht->arr[index]
.state == exist)
pht->arr[index]
.key = key;
pht->arr[index]
.state = exist;
pht->size++
;return0;
}
開雜湊又稱雜湊桶,解決雜湊衝突的方式是構造乙個存放煉表頭指標的順序表,順序表的儲存位置是通過雜湊函式計算得出,也稱為桶號,每條鍊錶都是產生雜湊衝突的結點
;//刪除掉存放煉表頭指標的動態順序表
}
用雜湊函式計算出桶號後,在每乙個桶中去查詢元素,實際上是通過遍歷鍊錶的方式查詢
int
hbsearch
(hb *phb, key key)
cur = cur->next;
}return-1
;}
刪除的時候也是先做查詢,當需要刪除的元素是鍊錶的第乙個結點,直接讓桶裡的頭指標指向鍊錶的第二個結點,如果非第乙個結點,就需要借助prev指標來完成鍊錶的刪除
int
hbdelete
(hb *phb, key key)
else
free
(cur)
; phb->size--
;return0;
} prev = cur;
cur = cur->next;
}return-1
;}
插入之前同樣需要判斷是否擴容,擴容是借助另乙個擴容後的臨時桶來完成,因為需要進行資料的搬移,在搬移過程中由於桶的容量已經擴容,所以通過雜湊函式計算出的桶號已經發生變化,資料搬移結束後,釋放掉舊桶空間,啟用新桶即可
int
hbinsert
(hb *phb, key key)
;void
i***pandhb
(hb *phb)
newcapacity = phb->capacity *2;
hbinit
(&thb, newcapacity, phb->hashfunc)
;for
(; icapacity; i++)}
hbdestroy
(phb)
; phb->arr = thb.arr;
phb->capacity = thb.capacity;
}int
hbinsert
(hb *phb, key key)
i***pandhb
(phb)
; index = phb->
hashfunc
(key, phb->capacity)
; node =
(node *
)malloc
(sizeof
(node));
node->key = key;
node->next = phb->arr[index]
; phb->arr[index]
= node;
phb->size++
;return0;
}
資料結構 雜湊
裝填因子 key的個數與表長的比值。雜湊表查詢成功的平均查詢長度,查詢失敗的平均查詢長度都是期望,期望怎麼求,平均查詢長度就怎麼求。雜湊表這裡有兩種實現方式 線性開型定址雜湊,鍊錶雜湊。1.線性開型定址雜湊 陣列實現,資料個數不大於表長,放乙個元素時,若發生衝突,則順次線性掃瞄直到找到乙個空位。2....
資料結構 雜湊
關鍵 不比較關鍵碼,直接搜尋得到需要的數。特點 與搜尋樹不一樣,雜湊結構元素的儲存位置與關鍵碼直接對應,可以不用進行比較遍歷。如圖,建立乙個陣列,把a 4 中的資料按特定的規則儲存到相應的位置,比如a i n,到時候搜尋資料的時候可以按照同樣的規律直接找到這個位置,如果這個位置有數,則存在。比如按照...
資料結構 雜湊
目錄 5 雜湊 5.1 定義 5.2 分離鏈結法 5.3 開放定址法 5.3.1 線性探測法 5.3.2 平方探測法 5.3.3 雙雜湊 5.5 再雜湊 5.6 可擴散雜湊 思想 將每個關鍵字對映到從0到tablesize 1的範圍的某個數,並且被放到適當的單元中。難道 衝突的處理。將雜湊到同乙個值...