1. 程式人生 > >java數據結構----哈希表

java數據結構----哈希表

一次 ima 沒有 隨著 可能 線性探測 死循環 stat hashtable

1.哈希表:它是一種數據結構,可以提供快速的插入操作和查找操作。如果哈希表中有多少數據項,插入和刪除操作只需要接近常量的時間。即O(1)的時間級。在計算機中如果需要一秒內查找上千條記錄,通常使用哈希表。哈希表的速度明顯比樹快,編程實現也相對容易。但哈希表是基於數組的,數組創建後難於擴展。某些哈希表被填基本填滿後性能下降的非常嚴重,所以程序員必須清除表中需要存儲多少數據,而且也沒有簡便的方式以任意一種順序(如由大到小)遍歷表中的數據項,如果需要這種能力,只能選擇其他數據結構。

2.哈希化:把關鍵字轉化成數組下標的過程稱為哈希化。在哈希表中這個轉換通過哈希函數來完成。而對於特定的關鍵字,並不需要哈希函數,關鍵字的值可以直接作為數組下標。

3.沖突:把巨大的數字空間壓縮成較小的數字空間必然要付出代價,即不能保證每個單詞都映射到數組的空白單元。假設要在數組中插入單詞cat,通過哈希函數得到它的數組下標後,發現那個單元已經有一個單詞了,對於特定大小的數組,這種情況稱為沖突。沖突使得哈希化的方案無法實施,解決的方案有兩種,一種是通過系統的方法找到數組的一個空位,並把單詞填入,而不再用哈希函數得到的下標,這種方法稱為開放地址法,第二種方案是創建一個存放單詞鏈表的數組,數組不直接用來存儲單詞,這樣發生沖突時,新的數據項就直接插入這個數組下標所指向的鏈表中,這種方法稱為鏈地址法。

  3-1.開放地址法的具體實現有三種不同方案,線性探測,二次探測和再哈希法。

    3-1-1.線性探測:在線性探測中,線性的查找空白單元,如果5421是要插入的數據位置,它已被占用,那麽就使用5422,然後是5423,依次類推,直到找到這個空位。

      3-1-1-1.存在的問題:會出現聚集情況。也叫原始聚集

    3-1-2.二次探測:二次探測是防止聚集產生的一種嘗試,思想是探測相隔較遠的單元。而不知和原始單元相鄰的單元。在二次探測中,探測的過程是x+1,x+4,x+9,x+16....

      3-1-2-1.問題:存在二次聚集。

    3-1-3.再哈希法:為了消除原始聚集和二次聚集,引入了再哈希法,二次聚集產生的原因是,二次探測的算法產生的探測序列步長總是固定的:1,4,9,16...現在需要一 種方法是依賴關鍵字的探測序列,方法是把關鍵字用相同的哈希函數再做一次哈希化,用這個結果作為步長,對指定的關鍵字步長在整個探測過程中是不變的,第二個哈希函數必須具備以下特點:a.和第一個哈希函數不同,b.不能輸出0(否則就沒有步長,將先入死循環)專家發現類似於stepsize = constant - (key % constant)的形式工作的很好,其中個constant是質數,且小於數組容量。(stepsize = 5 - (key % 5)),這種方案最為常用。

  3-2.鏈地址法圖示:技術分享圖片

    3-2-1.缺點:鏈地址法在概念上比開放地址法簡單,但是代碼可能要比其他的長,因為要包含鏈表機制,這就要求在程序中增加一個類。

4.再哈希法實現代碼:

  4.1.DataItem.java

技術分享圖片
 1 package com.cn.hashtable;
 2 /**
 3  * 再哈希法
 4  * @author Administrator
 5  *
 6  */
 7 public class DataItem {
 8 private int iData;
 9 public DataItem(int id){
10     iData = id;
11 }
12 public int getkey(){
13     return iData;
14 }
15 }
View Code

  4.2.HashTable.java

技術分享圖片
 1 package com.cn.hashtable;
 2 /**
 3  * 哈希表算法開放地址法---再哈希實現
 4  * @author Administrator
 5  *
 6  */
 7 public class HashTable {
 8 private DataItem[] hashArray;
 9 private int arraySize;
10 private DataItem nonItem;
11 HashTable(int size){
12     arraySize = size;
13     hashArray = new DataItem[arraySize];
14     nonItem = new DataItem(-1);
15 }
16 public void displayTable(){
17     System.out.print("Table:");
18     for (int i = 0; i < arraySize; i++) {
19         if (hashArray[i] != null)
20             System.out.print(hashArray[i].getkey()+"   ");
21         else
22             System.out.print("** ");
23     }
24     System.out.println("");
25 }
26 public int hashFunc1(int key){
27     return key % arraySize;
28 }
29 public int hashFunc2(int key){
30     return 5 - key % 5;
31 }
32 public void insert(int key,DataItem item){
33     int hashval = hashFunc1(key);
34     int stepsize = hashFunc2(key);
35     while (hashArray[hashval] != null && hashArray[hashval].getkey() != 1){
36         hashval += stepsize;
37         hashval %= arraySize;
38     }
39     hashArray[hashval] = item;
40 }
41 public DataItem delete(int key){
42     int hashval = hashFunc1(key);
43     int stepsize = hashFunc2(key);
44     while (hashArray[hashval] != null){
45         if (hashArray[hashval].getkey() == key){
46             DataItem temp = hashArray[hashval];
47             hashArray[hashval] = nonItem;
48             return temp;
49         }
50         hashval += stepsize;
51         hashval %= arraySize;
52     }
53     return null;
54 }
55 public DataItem find(int key){
56     int hashval = hashFunc1(key);
57     int stepsize = hashFunc2(key);
58     while (hashArray[hashval] != null){
59         if (hashArray[hashval].getkey() == key)
60             return hashArray[hashval];
61         hashval += stepsize;
62         hashval %= arraySize;
63     }
64     return null;
65 }
66 }
View Code

  4.3.HTTest.java

技術分享圖片
 1 package com.cn.hashtable;
 2 /**
 3  * 測試類
 4  * @author Administrator
 5  *
 6  */
 7 public class HTTest {
 8 public static void main(String[] args) {
 9 HashTable t = new HashTable(10);
10 t.insert(1, new DataItem(1));
11 t.insert(2, new DataItem(2));
12 t.insert(4, new DataItem(3));
13 t.insert(3, new DataItem(4));
14 t.insert(2, new DataItem(5));
15 t.insert(9, new DataItem(6));
16 t.displayTable();
17 t.delete(9);
18 System.out.println(t.find(9));
19 }
20 }
View Code

5.鏈地址法實現:

  5.1.Link.java

技術分享圖片
 1 package com.cn.hashtable;
 2 /**
 3  * 鏈地址法實現
 4  * @author Administrator
 5  *
 6  */
 7 public class Link {
 8 public int iData;
 9 public Link next;
10 public Link(int it){
11     iData = it;
12 }
13 public int getkey(){
14     return iData;
15 }
16 public void displayLink(){
17     System.out.print(iData+"   ");
18 }
19 }
View Code

  5.2.SortedList.java

技術分享圖片
 1 package com.cn.hashtable;
 2 
 3 public class SortedList {
 4 private Link first;
 5 public void insert(Link thelink){
 6     int key = thelink.getkey();
 7     Link previous = null;
 8     Link current = first;
 9     while (current != null && key > current.getkey()){
10         previous = current;
11         current = current.next;
12     }
13     if (previous == null)
14         first = thelink;
15     else
16         previous.next = thelink;
17     thelink.next = current;
18 }
19 public void delete(int key){
20     Link previous = null;
21     Link current = first;
22     while (current != null && key != current.getkey()){
23         previous = current;
24         current = current.next;
25     }
26     if (previous == null)
27         first = first.next;
28     else
29         previous.next = current.next;
30 }
31 public Link find(int key){
32     Link current = first;
33     while (current != null && current.getkey() <= key){
34         if (current.getkey() == key)
35             return current;
36         current = current.next;
37     }
38     return null;
39 }
40 public void displayList(){
41     System.out.print("list:first-->last: ");
42     Link current = first;
43     while (current != null){
44         current.displayLink();
45         current = current.next;
46     }
47     System.out.println("");
48 }
49 }
View Code

  5.3.LHashTable.java

技術分享圖片
 1 package com.cn.hashtable;
 2 /**
 3  * 鏈地址法實現哈希表類
 4  * @author Administrator
 5  *
 6  */
 7 public class LHashTable {
 8 private SortedList[] hashArray;
 9 private int arraySize;
10 public LHashTable(int size){
11     arraySize = size;
12     hashArray = new SortedList[arraySize];
13     for (int i = 0; i < arraySize; i++) {
14         hashArray[i] = new SortedList();
15     }
16 }
17 public void display(){
18     for (int i = 0; i < arraySize; i++) {
19         System.out.print(i+". ");
20         hashArray[i].displayList();
21     }
22     System.out.println("");
23 }
24 public int hashFunc(int key){
25     return key % arraySize;
26 }
27 public void insert(Link thelink){
28     int key = thelink.getkey();
29     int hashval = hashFunc(key);
30     hashArray[hashval].insert(thelink);
31 }
32 public void delete(int key){
33     int hashval = hashFunc(key);
34     hashArray[hashval].delete(key);
35 }
36 public Link find(int key){
37     int hashval = hashFunc(key);
38     Link thelink = hashArray[hashval].find(key);
39     return thelink;
40 }
41 }
View Code

  5.4.LHTTest.java

技術分享圖片
 1 package com.cn.hashtable;
 2 /**
 3  * 鏈地址法實現測試類
 4  * @author Administrator
 5  *
 6  */
 7 public class LHTTest {
 8 public static void main(String[] args) {
 9     LHashTable lt = new LHashTable(10);
10     for (int i = 0; i < 5; i++) {
11         lt.insert(new Link(i));
12     }
13     lt.display();
14 }
15 }
View Code

6.哈希化的效率:在哈希表中執行插入和搜索操作可以達到O(1)的時間級,如果沒有遇到沖突,就只需要使用一次哈希函數和數組的引用。這是最小的存取時間級。如果發生沖突,存取時間就依賴後邊的探測長度。因此,一次的查找或插入操作與探測長度成正比,平均探測長度取決於裝填因子(表中項數和表長的比率),隨著填裝因子變大,探測長度也越來越長。

  6.1.線性探測時,探測序列(p)和填裝因子(L)的關系:成功查找:P = (1 + 1/(1 - L)^2)/2;不成功查找:(1 + 1/(1 - L))/2,隨著裝填因子變小,存儲效率下降而速度上升。

  6.2.二次探測和再哈希法:對成功的搜索公式是:-log2(1 - loadfactor)/loadfactor;不成功的查找:1/(1-loadfactor)

  6.3.假設哈希表含有arraySize個數據項,每個數據項有一個鏈表,在表中有N個數據項:averageListLength = N/arraySize;成功查找:1+loadfactor/2;不成功的查找:1+loadfactor

java數據結構----哈希表