⑴ 數據結構 哈希表建立
國防部和發簡訊
⑵ 哈希表—什麼是哈希表
哈希表是一種數據結構~
哈希表可以存儲各種類型的數據,當我們從哈希表中查找所需要的數據時,理想情況是不經過任何比較,一次存取便能得到所查記錄, 那就必須在記錄的存儲位置和它的關鍵字之間建立一個確定的對應關系 f,使每個關鍵字和結構中一個唯一的存儲位置相對應。 (關鍵字就是所要存儲的數據,存儲位置相當於數組的索引)
當然,可以把哈希表理解為一個數組,每個索引對應一個存儲位置,哈希表的索引並不像普通數組的索引那樣,從0到length-1,而是由關鍵字(數據本身)通過哈希函數得到
eg1. 將26個小寫字母存儲到數組 int [26] a。
a對應a[0],b對應a[1],c對應a[3]……以此類推。
那麼,數組 int [26] a 就是一個哈希表!
例1中,關鍵字(小寫字母)是如何得到自己對應的索引(存儲位置)的呢?
關鍵字的ASCII值減去a的ASCII值!
上面說過,關鍵字通過哈希函數得到索引,所以,f(ch)就是本例題的哈希函數。
這樣,我們就在關鍵字和數字(存儲位置)之間建立了一個確定的對應關系f。
關鍵字與數字是一一對應的,由於數組本身支持隨機訪問,所以,當查找關鍵字時,只需要O(1)的查找操作,也就是實現了不經過任何比較,一次便能得到所查記錄。
哈希表中 哈希函數的設計 是相當重要的,這也是建哈希表過程中的關鍵問題之一。
假如,我們所要存儲的數據其關鍵字是一個人的身份證號(18位數字),這個時候我們該怎麼計算關鍵字對應的索引呢?
比如一個人的身份證號是 411697199702076425,我們很難像例1那樣直接讓關鍵字與數字建立一一對應的關系,並且保證數字適合作為數組的索引。
在這種情況下,通過哈希函數計算出的索引,即使關鍵字不同,索引也會有可能相同。這就是 哈希沖突
當索引相同時,我們該怎麼存儲數據呢?如何解決哈希沖突,是我們建哈希表的另一個關鍵問題。
哈希表充分體現了空間換時間這種經典的演算法思想。
關鍵字是大整數時,比如上面我們舉的身份證號例子,411697199702076425
假如我們能開辟一個 999999999999999999 大的空間,這樣就能直接把身份證號作為關鍵字存儲到數組中,這樣可以用O(1)時間完成各項操作
假如我們只有 1 的空間,我們需要把所有信息存儲到這個空間中(也就是所有數據都會產生哈希沖突),我們只能用O(n)時間完成各項操作
事實上,我們不可能開辟一個如此大的空間,也不可會開辟如此小的空間
無限空間時,時間為O(1)
1的空間時,時間為O(n)
而哈希表就是在二者之間產生一個平衡,即 空間和時間的平衡 。
1.哈希函數的設計
2.解決哈希沖突
3.哈希表實現時間和空間的平衡
後續會詳細說明這三個關鍵問題~
⑶ java中hashtable怎樣存儲數據和讀取數據
Hashtable-哈希表類
以哈希表的形式存儲數據,數據的形式是鍵值對.
特點:
查找速度快,遍歷相對慢
鍵值不能有空指針和重復數據
創建
Hashtable<Integer,String> ht=new
Hashtable<Integer,String>();
添值
ht.put(1,"Andy");
ht.put(2,"Bill");
ht.put(3,"Cindy");
ht.put(4,"Dell");
ht.put(5,"Felex");
ht.put(6,"Edinburg");
ht.put(7,"Green");
取值
String str=ht.get(1);
System.out.println(str);// Andy
對鍵進行遍歷
Iterator it = ht.keySet().iterator();
while (it.hasNext()) {
Integer key = (Integer)it.next();
System.out.println(key);
}
對值進行遍歷
Iterator it = ht.values().iterator();
while (it.hasNext()) {
String value =(String) it.next();
System.out.println(value);
}
取Hashtable記錄數
Hashtable<Integer,String> ht=new Hashtable<Integer,String>();
ht.put(1,"Andy");
ht.put(2,"Bill");
ht.put(3,"Cindy");
ht.put(4,"Dell");
ht.put(5,"Felex");
ht.put(6,"Edinburg");
ht.put(7,"Green");
int i=ht.size();// 7
刪除元素
Hashtable<Integer,String> ht=new Hashtable<Integer,String>();
ht.put(1,"Andy");
ht.put(2,"Bill");
ht.put(3,"Cindy");
ht.put(4,"Dell");
ht.put(5,"Felex");
ht.put(6,"Edinburg");
ht.put(7,"Green");
ht.remove(1);
ht.remove(2);
ht.remove(3);
ht.remove(4);
System.out.println(ht.size());// 3
Iterator it = ht.values().iterator();
while (it.hasNext()) {
// Get value
String value =(String)
it.next();
System.out.println(value);
}
⑷ 哈希值是什麼
哈希表類Hashtable
哈希表是一種重要的存儲方式,也是一種常見的檢索方法。其基本思想是將關系碼的值作為自變數,通過一定的函數關系計算出對應的函數值,把這個數值解釋為結點的存儲地址,將結點存入計算得到存儲地址所對應的存儲單元。檢索時採用檢索關鍵碼的方法。現在哈希表有一套完整的演算法來進行插入、刪除和解決沖突。在Java中哈希表用於存儲對象,實現快速檢索。
Java.util.Hashtable提供了種方法讓用戶使用哈希表,而不需要考慮其哈希表真正如何工作。
哈希表類中提供了三種構造方法,分別是:
public Hashtable()
public Hashtable(int initialcapacity)
public Hashtable(int initialCapacity,float loadFactor)
參數initialCapacity是Hashtable的初始容量,它的值應大於0。loadFactor又稱裝載因子,是一個0.0到1之間的float型的浮點數。它是一個百分比,表明了哈希表何時需要擴充,例如,有一哈希表,容量為100,而裝載因子為0.9,那麼當哈希表90%的容量已被使用時,此哈希表會自動擴充成一個更大的哈希表。如果用戶不賦這些參數,系統會自動進行處理,而不需要用戶操心。
Hashtable提供了基本的插入、檢索等方法。
■插入
public synchronized void put(Object key,Object value)
給對象value設定一關鍵字key,並將其加到Hashtable中。若此關鍵字已經存在,則將此關鍵字對應的舊對象更新為新的對象Value。這表明在哈希表中相同的關鍵字不可能對應不同的對象(從哈希表的基本思想來看,這也是顯而易見的)。
■檢索
public synchronized Object get(Object key)
根據給定關鍵字key獲取相對應的對象。
public synchronized boolean containsKey(Object key)
判斷哈希表中是否包含關鍵字key。
public synchronized boolean contains(Object value)
判斷value是否是哈希表中的一個元素。
■刪除
public synchronized object remove(object key)
從哈希表中刪除關鍵字key所對應的對象。
public synchronized void clear()
清除哈希表
另外,Hashtalbe還提供方法獲取相對應的枚舉集合:
public synchronized Enumeration keys()
返回關鍵字對應的枚舉對象。
public synchronized Enumeration elements()
返回元素對應的枚舉對象。
例1.5 Hashtable.java給出了使用Hashtable的例子。
例1.5 Hashtalbe.java。
//import java.lang.*;
import java.util.Hashtable;
import java.util.Enumeration;
public class HashApp{
public static void main(String args[]){
Hashtable hash=new Hashtable(2,(float)0.8);
//創建了一個哈希表的對象hash,初始容量為2,裝載因子為0.8
hash.put("Jiangsu","Nanjing");
//將字元串對象「Jiangsu」給定一關鍵字「Nanjing」,並將它加入hash
hash.put("Beijing","Beijing");
hash.put("Zhejiang","Hangzhou");
System.out.println("The hashtable hash1 is: "+hash);
System.out.println("The size of this hash table is "+hash.size());
//列印hash的內容和大小
Enumeration enum1=hash.elements();
System.out.print("The element of hash is: ");
while(enum1.hasMoreElements())
System.out.print(enum1.nextElement()+" ");
System.out.println();
//依次列印hash中的內容
if(hash.containsKey("Jiangsu"))
System.out.println("The capatial of Jiangsu is "+hash.get("Jiangsu"));
hash.remove("Beijing");
//刪除關鍵字Beijing對應對象
System.out.println("The hashtable hash2 is: "+hash);
System.out.println("The size of this hash table is "+hash.size());
}
}
運行結果:
The hashtable hash1 is: {Beijing=Beijing, Zhejiang=Hangzhou, Jiangsu=Nanjing}
The size of this hash table is 3
The element of hash is: Beijing Hangzhou Nanjing
The capatial of Jiangsu is Nanjing
The hashtable hash2 is: {Zhejiang=Hangzhou, Jiangsu=Nanjing}
The size of this hash table is 2
Hashtable是Dictionary(字典)類的子類。在字典類中就把關鍵字對應到數據值。字典類是一個抽象類。在java.util中還有一個類Properties,它是Hashtable的子類。用它可以進行與對象屬性相關的操作。
⑸ 哈希函數的哈希表的概念及作用
哈希表中元素是由哈希函數確定的。將數據元素的關鍵字K作為自變數,通過一定的函數關系(稱為哈希函數),計算出的值,即為該元素的存儲地址。表示為:
Addr = H(key)
為此在建立一個哈希表之前需要解決兩個主要問題:
⑴構造一個合適的哈希函數
均勻性 H(key)的值均勻分布在哈希表中;
簡單以提高地址計算的速度
⑵沖突的處理
沖突:在哈希表中,不同的關鍵字值對應到同一個存儲位置的現象。即關鍵字K1≠K2,但H(K1)= H(K2)。均勻的哈希函數可以減少沖突,但不能避免沖突。發生沖突後,必須解決;也即必須尋找下一個可用地址。
解決沖突的方法:
⑴鏈接法(拉鏈法)。將具有同一散列地址的記錄存儲在一條線性鏈表中。例,除留余數法中,設關鍵字為 (18,14,01,68,27,55,79),除數為13。散列地址為 (5,1,1,3,1,3,1),哈希散列表如圖。
⑵開放定址法。如果h(k)已經被佔用,按如下序列探查:(h(k)+p⑴)%TSize,(h(k)+p⑵)%TSize,…,(h(k)+p(i))%TSize,…
其中,h(k)為哈希函數,TSize為哈希表長,p(i)為探查函數。在 h(k)+p(i-1))%TSize的基礎上,若發現沖突,則使用增量 p(i) 進行新的探測,直至無沖突出現為止。其中,根據探查函數p(i)的不同,開放定址法又分為線性探查法(p(i) = i : 1,2,3,…),二次探查法(p(i)=(-1)^(i-1)*((i+1)/2)^2,探查序列依次為:1, -1,4, -4, 9 …),隨機探查法(p(i): 隨機數),雙散列函數法(雙散列函數h(key) ,hp (key)若h(key)出現沖突,則再使用hp (key)求取散列地址。探查序列為:h(k),h(k)+ hp(k),…,h(k)+ i*hp(k))。
⑶桶定址法。桶:一片足夠大的存儲空間。桶定址:為表中的每個地址關聯一個桶。如果桶已經滿了,可以使用開放定址法來處理。例如,插入A5,A2,A3,B5,A9,B2,B9,C2,採用線性探查法解決沖突。如圖。
⑹ 哈希表詳解
哈希表:即散列存儲結構。
散列法存儲的基本思想:建立記錄關鍵碼字與其存儲位置的對應關系,或者說,由關鍵碼的值決定數據的存儲地址。
這樣,不經過比較,一次存取就能得到所查元素的查找方法
優點:查找速度極快(O(1)),查找效率與元素個數n無關!
哈希方法(雜湊法)
選取某個函數,依該函數按關鍵字計算元素的存儲位置並按此存放;查找時也由同一個函數對給定值k計算地址,將k與地址中內容進行比較,確定查找是否成功。
哈希函數(雜湊函數)
哈希方法中使用的轉換函數稱為哈希函數(雜湊函數).在記錄的關鍵碼與記錄的存儲地址之間建立的一種對應關系
有數據元素序列(14,23,39,9,25,11),若規定每個元素k的存儲地址H(k)=k , H(k)稱為散列函數,畫出存儲結構圖。
根據散列函數H(k)=k ,可知元素14應當存入地址為14的單元,元素23應當存入地址為23的單元,……,
根據存儲時用到的散列函數H(k)表達式,迅即可查到結果!
例如,查找key=9,則訪問H(9)=9號地址,若內容為9則成功;
若查不到,應當設法返回一個特殊值,例如空指針或空記錄。
很顯然這種搜索方式空間效率過低。
哈希函數可寫成:addr(ai)=H(ki)
選取某個函數,依該函數按關鍵字計算元素的存儲位置並按此存放;查找時也由同一個函數對給定值k計算地址,將k與地址中內容進行比較,確定查找是否成功。哈希方法中使用的轉換函數稱為哈希函數(雜湊函數).在記錄的關鍵碼與記錄的存儲地址之間建立的一種對應關系。
通常關鍵碼的集合比哈希地址集合大得多,因而經過哈希函數變換後,可能將不同的關鍵碼映射到同一個哈希地址上,這種現象稱為沖突。
有6個元素的關鍵碼分別為:(14,23,39,9,25,11)。
選取關鍵碼與元素位置間的函數為H(k)=k mod 7
根據哈希函數算出來發現同一個地址放了多個關鍵碼,也就是沖突了。
在哈希查找方法中,沖突是不可能避免的,只能盡可能減少。
所以,哈希方法必須解決以下兩個問題:
1)構造好的哈希函數
(a)所選函數盡可能簡單,以便提高轉換速度;
(b)所選函數對關鍵碼計算出的地址,應在哈希地址內集中並大致均勻分布,以減少空間浪費。
2)制定一個好的解決沖突的方案
查找時,如果從哈希函數計算出的地址中查不到關鍵碼,則應當依據解決沖突的規則,有規律地查詢其它相關單元。
從上面兩個例子可以得出如下結論:
哈希函數只是一種映象,所以哈希函數的設定很靈活,只要使任何關鍵碼的哈希函數值都落在表長允許的范圍之內即可
沖突:key1≠key2,但H(key1)=H(key2)
同義詞:具有相同函數值的兩個關鍵碼
哈希函數沖突不可避免,只能盡量減少。所以,哈希方法解決兩個問題:
構造好的哈希函數;
制定解決沖突基本要求:
要求一:n個數據原僅佔用n個地址,雖然散列查找是以空間換時間,但仍希望散列的地址空間盡量小。
要求二:無論用什麼方法存儲,目的都是盡量均勻地存放元素,以避免沖突。
Hash(key) = a·key + b (a、b為常數)
優點:以關鍵碼key的某個線性函數值為哈希地址,不會產生沖突.
缺點:要佔用連續地址空間,空間效率低。
例.關鍵碼集合為{100,300,500,700,800,900},
選取哈希函數為Hash(key)=key/100,
則存儲結構(哈希表)如下:
Hash(key)=key mod p (p是一個整數)
特點:以關鍵碼除以p的余數作為哈希地址。
關鍵:如何選取合適的p?p選的不好,容易產生同義詞
技巧:若設計的哈希表長為m,則一般取p≤m且為質數
(也可以是合數,但不能包含小於20的質因子)。
Hash(key)= ⎣ B ( A key mod 1 ) ⎦
(A、B均為常數,且0<A<1,B為整數)
特點:以關鍵碼key乘以A,取其小數部分,然後再放大B倍並取整,作為哈希地址。
例:欲以學號最後兩位作為地址,則哈希函數應為:
H(k)=100 (0.01 k % 1 )
其實也可以用法2實現: H(k)=k % 100
特點:選用關鍵字的某幾位組合成哈希地址。選用原則應當是:各種符號在該位上出現的頻率大致相同。
例:有一組(例如80個)關鍵碼,其樣式如下:
討論:
① 第1、2位均是「3和4」,第3位也只有「 7、8、9」,因此,這幾位不能用,餘下四位分布較均勻,可作為哈希地址選用。
② 若哈希地址取兩位(因元素僅80個),則可取這四位中的任意兩位組合成哈希地址,也可以取其中兩位與其它兩位疊加求和後,取低兩位作哈希地址。
特點:對關鍵碼平方後,按哈希表大小,取中間的若干位作為哈希地址。(適於不知道全部關鍵碼情況)
理由:因為中間幾位與數據的每一位都相關。
例:2589的平方值為6702921,可以取中間的029為地址。
特點:將關鍵碼自左到右分成位數相等的幾部分(最後一部分位數可以短些),然後將這幾部分疊加求和,並按哈希表表長,取後幾位作為哈希地址。
適用於:關鍵碼位數很多,且每一位上各符號出現概率大致相同的情況。
法1:移位法 ── 將各部分的最後一位對齊相加。
法2:間界疊加法──從一端向另一端沿分割界來回折疊後,最後一位對齊相加。
例:元素42751896,
用法1: 427+518+96=1041
用法2: 427 518 96—> 724+518+69 =1311
7、隨機數法
Hash(key) = random ( key ) (random為偽隨機函數)
適用於:關鍵字長度不等的情況。造表和查找都很方便。
小結:構造哈希函數的原則:
① 執行速度(即計算哈希函數所需時間);
② 關鍵字的長度;
③ 哈希表的大小;
④ 關鍵字的分布情況;
⑤ 查找頻率。
設計思路:有沖突時就去尋找下一個空的哈希地址,只要哈希表足夠大,空的哈希地址總能找到,並將數據元素存入。
1)線性探測法
Hi=(Hash(key)+di) mod m ( 1≤i < m )
其中:
Hash(key)為哈希函數
m為哈希表長度
di 為增量序列 1,2,…m-1,且di=i
關鍵碼集為 {47,7,29,11,16,92,22,8,3},
設:哈希表表長為m=11;
哈希函數為Hash(key)=key mod 11;
擬用線性探測法處理沖突。建哈希表如下:
解釋:
① 47、7是由哈希函數得到的沒有沖突的哈希地址;
② Hash(29)=7,哈希地址有沖突,需尋找下一個空的哈希地址:由H1=(Hash(29)+1) mod 11=8,哈希地址8為空,因此將29存入。
③ 另外,22、8、3同樣在哈希地址上有沖突,也是由H1找到空的哈希地址的。
其中3 還連續移動了(二次聚集)
線性探測法的優點:只要哈希表未被填滿,保證能找到一個空地址單元存放有沖突的元素;
線性探測法的缺點:可能使第i個哈希地址的同義詞存入第i+1個哈希地址,這樣本應存入第i+1個哈希地址的元素變成了第i+2個哈希地址的同義詞,……,
因此,可能出現很多元素在相鄰的哈希地址上「堆積」起來,大大降低了查找效率。
解決方案:可採用二次探測法或偽隨機探測法,以改善「堆積」問題。
2) 二次探測法
仍舉上例,改用二次探測法處理沖突,建表如下:
Hi=(Hash(key)±di) mod m
其中:Hash(key)為哈希函數
m為哈希表長度,m要求是某個4k+3的質數;
di為增量序列 1^2,-1 ^2,2 ^2,-2 ^2,…,q ^2
註:只有3這個關鍵碼的沖突處理與上例不同,
Hash(3)=3,哈希地址上沖突,由
H1=(Hash(3)+1 ^2) mod 11=4,仍然沖突;
H2=(Hash(3)-1 ^2) mod 11=2,找到空的哈希地址,存入。
3) 若di=偽隨機序列,就稱為偽隨機探測法
基本思想:將具有相同哈希地址的記錄(所有關鍵碼為同義詞)鏈成一個單鏈表,m個哈希地址就設m個單鏈表,然後用一個數組將m個單鏈表的表頭指針存儲起來,形成一個動態的結構。
設{ 47, 7, 29, 11, 16, 92, 22, 8, 3, 50, 37, 89 }的哈希函數為:
Hash(key)=key mod 11,
用拉鏈法處理沖突,則建表如圖所示。
Hi=RHi(key) i=1, 2, …,k
RHi均是不同的哈希函數,當產生沖突時就計算另一個哈希函數,直到沖突不再發生。
優點:不易產生聚集;
缺點:增加了計算時間。
思路:除設立哈希基本表外,另設立一個溢出向量表。
所有關鍵字和基本表中關鍵字為同義詞的記錄,不管它們由哈希函數得到的地址是什麼,一旦發生沖突,都填入溢出表。
明確:散列函數沒有「萬能」通式(雜湊法),要根據元素集合的特性而分別構造。
討論:哈希查找的速度是否為真正的O(1)?
不是。由於沖突的產生,使得哈希表的查找過程仍然要進行比較,仍然要以平均查找長度ASL來衡量。
一般地,ASL依賴於哈希表的裝填因子α,它標志著哈希表的裝滿程度。
0≤α≤1
α 越大,表中記錄數越多,說明表裝得越滿,發生沖突的可能性就越大,查找時比較次數就越多。
例 已知一組關鍵字(19,14,23,1,68,20,84,27,55,11,10,79)
哈希函數為:H(key)=key MOD 13, 哈希表長為m=16,
設每個記錄的查找概率相等
(1) 用線性探測再散列處理沖突,即Hi=(H(key)+di) MOD m
(2) 用二次探測再散列處理沖突,即Hi=(H(key)+di) MOD m
(3) 用鏈地址法處理沖突
1) 散列存儲的查找效率到底是多少?
答:ASL與裝填因子α有關!既不是嚴格的O(1),也不是O(n)
2)「沖突」是不是特別討厭?
答:不一定!正因為有沖突,使得文件加密後無法破譯!(單向散列函數不可逆,常用於數字簽名和間接加密)。
利用了哈希表性質:源文件稍稍改動,會導致哈希表變動很大。
⑺ 哈希表存儲元素大於函數怎麼辦
首先什麼是 哈希表,哈希表(英文名字為Hash table,也有一些演算法書籍翻譯為散列表,大家看到這兩個名稱知道都是指hash table就可以了)。
哈希表是根據關鍵碼的值而直接進行訪問的數據結構。
在討論哈希表之前,我們先大概了解下其他數據結構在新增,查找等基礎操作執行性能
數組:採用一段連續的存儲單元來存儲數據。對於指定下標的查找,時間復雜度為O(1);通過給定值進行查找,需要遍歷數組,逐一比對給定關鍵字和數組元素,時間復雜度為O(n),當然,對於有序數組,則可採用二分查找,插值查找,斐波那契查找等方式,可將查找復雜度提高為O(logn);對於一般的插入刪除操作,涉及到數組元素的移動,其平均復雜度也為O(n)
線性鏈表:對於鏈表的新增,刪除等操作(在找到指定操作位置後),僅需處理結點間的引用即可,時間復雜度為O(1),而查找操作需要遍歷鏈表逐一進行比對,復雜度為O(n)
二叉樹:對一棵相對平衡的有序二叉樹,對其進行插入,查找,刪除等操作,平均復雜度均為O(logn)。
哈希表:相比上述幾種數據結構,在哈希表中進行添加,刪除,查找等操作,性能十分之高,不考慮哈希沖突的情況下(後面會探討下哈希沖突的情況),僅需一次定位即可完成,時間復雜度為O(1),接下來我們就來看看哈希表是如何實現達到驚艷的常數階O(1)的。
我們知道,數據結構的物理存儲結構只有兩種:順序存儲結構和鏈式存儲結構(像棧,隊列,樹,圖等是從邏輯結構去抽象的,映射到內存中,也這兩種物理組織形式),而在上面我們提到過,在數組中根據下標查找某個元素,一次定位就可以達到,哈希表利用了這種特性,哈希表的主幹就是數組。
比如我們要新增或查找某個元素,我們通過把當前元素的關鍵字 通過某個函數映射到數組中的某個位置,通過數組下標一次定位就可完成操作。
這個函數可以簡單描述為:存儲位置 = f(關鍵字) ,這個函數f一般稱為哈希函數,這個函數的設計好壞會直接影響到哈希表的優劣
其實直白來講其實數組就是一張哈希表。
哈希表中關鍵碼就是數組的索引下標,然後通過下標直接訪問數組中的元素,如下圖所示:
那麼哈希表能解決什麼問題呢,一般哈希表都是用來快速判斷一個元素是否出現集合里。
例如要查詢一個名字是否在這所學校里。
要枚舉的話時間復雜度是O(n),但如果使用哈希表的話, 只需要O(1)
⑻ 哈希表概念以及哈希沖突的處理
哈希表(散列表 Hash)是相對於線性表、樹形結構的一種數據結構,它能在元素的存儲位置和其關鍵字直接建立某種之間關系,那麼在進行查找時,就無需做或者做很少次的比較,就能通過這個關系直接由關鍵字找到對對應的記錄。這就是散列查找法(Hase Search)的思想,它通過對元素的關鍵字值進行某種運算,直接求出元素的地址。即使用關鍵字到地址的直接轉換方法,而不需要反復比較。因此,散列查找法又叫雜湊法或者散列法。
選擇一個好的散列函數可以在一定程度上減少沖突,但在實際應用中,很難完全避免發生沖突,所以選擇一個有效的處理沖突的方法是散列表的另一個關鍵問題。
處理沖突的方法與散列表本身的組織形式有關。按組織形式的不同,通常分為兩大類:開放地址法和鏈地址法。
開放地址法的基本思想是:把記錄都存儲在散列表數組中,當某一記錄關鍵字key的初始散列地址H0=H(key)發生沖突時,以H0為基礎,採取合適方法計算得到另一地址H1,如果H1仍然發生沖突,已H1位基礎再求下一個地址H2,若H2仍然沖突,再求得H3,以此類推,直至Hk不發生沖突為止,則Hk為該記錄在表中的散列地址。
根據計算方法,可以分為以下三種探測方法:
線性探測法會在出現在處理過程中發生沖突的發生第一個散列地址不同的記錄爭奪同一個後繼散列地址的現象,稱為二次聚集或者堆積。即在處理同義詞的沖突過程中,又添加了非同義詞的沖突。
它的優點是,只要散列表未滿,就一定能找到一個不發生沖突的地址
而二次探測法和偽隨機數探測法可以避免出現二次聚集現象,但是不保證一定能找到不發生沖突的地址。
鏈地址法的基本思想是:把具有相同散列地址的記錄放在同一個單鏈表中,稱為同義詞鏈表。有m個散列地址就有m個單鏈表,同時用數組HT[0..m-1]存放各個鏈表的頭指針,凡是散列地址為i的記錄都以結點的方式插入已HT[i]為頭結點的單鏈表中。
⑼ 請問怎麼用Hashset存儲多種數據.
這些數據應該是相關的吧,所以應該用個對象存儲起來,比如城市降雨量對象,它有三個屬性:年份,城市,每月降雨量。
然後用hashset來存儲這個對象。
至於查找,可以轉化為迭代器,對當前對象進行判斷,直到找到滿足條件的即可;如果數據在資料庫中,直接通過SQL來查找。
⑽ 數據結構——哈希表
哈希表(hash table)又稱為散列表,或者散列映射、映射、字典和關聯數組等。是一種根據鍵(key)直接訪問在內存存儲位置的數據結構,也就是我們常說的鍵值對。
在之前我們講過數組,鏈表,棧,這些數據結構,都是不包含默認邏輯的,可以直接反應數據在內存中的存儲位置以及狀態。而相較於其他的數據結構,哈希表是一種包含默認邏輯的數據結構,默認邏輯即為需要使用散列函數才能夠確定鍵對應的元素的地址。
而什麼是散列表呢?
散列表是一個數組,其中儲存有通過散列函數返回的結果。如圖,需要保證的是不同的輸入返回不同的索引,同樣的輸入返回相同的索引。
如果出現兩個key返回同樣的地址,就是所謂的沖突。一般我們使用語言都有很好的解決,並不需要我們自己來設計,不需要過多關注,如果有興趣的話無非就是考慮一下降低填裝因子和使用更加優良的散列函數。