2017-10-20 203 views
0

帖子詳細
在數據結構課程的通用地圖,我獲得了Java源代碼的「二次探測哈希表」級,並要求實現一個通用的地圖(與得到方法)並將密鑰/定義對存儲在散列表中。我在閱讀本書時理解這些內容,但發現很難用編程語言(Java)來實現。我認爲問題的一部分是確切地理解問題的要求,部分是Java編程體驗的不足之處。我希望能得到一些關於如何處理這類問題的建議,並填寫我錯過的任何Java知識。實現使用哈希表中的Java

一些問題我已經
什麼是哈希表類相對於一般的地圖我應該創建函數?哈希表有幾種方法,包括得到插入刪除翻版等...是哈希表來生成一個散列值作爲地圖類要使用的密鑰的目的是什麼?密鑰和定義存儲在散列表中還是將它們存儲在地圖中?如果哈希表已經完成了所有這些,那麼製作一張地圖有什麼意義呢?

有人可以幫我理解如何解決這樣的問題嗎?什麼是一些可能對我有幫助的參考,或者是專門針對這個問題,或者是對如何有效和有條理地完成這種練習的理解?

我很感激我能得到的任何幫助。我包括書中的代碼以幫助說明問題。

二次探查哈希表碼課本

public class QuadraticProbingHashTable<AnyType> { 

    public QuadraticProbingHashTable() { 
     this(DEFAULT_TABLE_SIZE); 
    } 

    public QuadraticProbingHashTable(int size) { 
     allocateArray(size); 
     doClear(); 
    } 

    public boolean insert(AnyType x) { 
     int currentPos = findPos(x); 
     if(isActive(currentPos)) return false; 

     array[currentPos] = new HashEntry<>(x, true); 
     theSize++; 

     if(++occupied > array.length/2) rehash(); 

     return true; 
    } 

    private void rehash() { 
     HashEntry<AnyType>[] oldArray = array; 

     allocateArray(2 * oldArray.length); 
     occupied = 0; 
     theSize = 0; 

     for(HashEntry<AnyType> entry : oldArray) 
      if(entry != null && entry.isActive) insert(entry.element); 
    } 

    private int findPos(AnyType x) { 
     int offset = 1; 
     int currentPos = myhash(x); 

     while(array[currentPos] != null && !array[currentPos].element.equals(x)) { 
      currentPos += offset; 
      offset += 2; 
      if(currentPos >= array.length) currentPos -= array.length; 
     } 

     return currentPos; 
    } 

    public boolean remove(AnyType x) { 
     int currentPos = findPos(x); 
     if(isActive(currentPos)) { 
      array[currentPos].isActive = false; 
      theSize--; 
      return true; 
     } else return false; 
    } 

    public int size() { 
     return theSize; 
    } 

    public int capacity() { 
     return array.length; 
    } 

    public boolean contains(AnyType x) { 
     int currentPos = findPos(x); 
     return isActive(currentPos); 
    } 

    public AnyType get(AnyType x) { 
     int currentPos = findPos(x); 
     if(isActive(currentPos)) return array[currentPos].element; 
     else return null; 
    } 

    private boolean isActive(int currentPos) { 
     return array[currentPos] != null && array[currentPos].isActive; 
    } 

    public void makeEmpty() { 
     doClear(); 
    } 

    private void doClear() { 
     occupied = 0; 
     for(int i = 0; i < array.length; i++) array[i] = null; 
    } 

    private int myhash(AnyType x) { 
     int hashVal = x.hashCode(); 

     hashVal %= array.length; 
     if(hashVal < 0) hashVal += array.length; 

     return hashVal; 
    } 

    private static class HashEntry<AnyType> { 
     public AnyType element; 
     public boolean isActive; 

     public HashEntry(AnyType e) { 
      this(e, true); 
     } 

     public HashEntry(AnyType e, boolean i) { 
      element = e; 
      isActive = i; 
     } 
    } 

    private static final int DEFAULT_TABLE_SIZE = 101; 

    private HashEntry<AnyType>[] array; 
    private int occupied; 
    private int theSize; 

    private void allocateArray(int arraySize) { 
     array = new HashEntry[nextPrime(arraySize)]; 
    } 

    private static int nextPrime(int n) { 
     if(n % 2 == 0) n++; 

     for(; !isPrime(n); n += 2) ; 

     return n; 
    } 

    private static boolean isPrime(int n) { 
     if(n == 2 || n == 3) return true; 

     if(n == 1 || n % 2 == 0) return false; 

     for(int i = 3; i * i <= n; i += 2) 
      if(n % i == 0) return false; 

     return true; 
    } 
} 

地圖骨架課本

class Map<KeyType,ValueType> { 
    public Map() 

    public void put(KeyType key, ValueType val) 
    public ValueType get(KeyType key) 
    public boolean isEmpty() 
    public void makeEmpty() 

    private QuadraticProbingHashTable<Entry<KeyType,ValueType>> items; 

    private static class Entry<KeyType,ValueType> { 
     KeyType key; 
     ValueType value; 
    } 
} 

回答

0

一般情況下,你面對的是什麼implementing給定interface問題。 Map是接口 - HashTable是實現它的一種方式,即底層數據結構。

但是,我理解你的困惑,因爲你提供的HashTable的定義似乎不適合這項工作,因爲它似乎沒有選擇使用自定義鍵(而是始終依賴於對象的散列碼用於計算散列),也沒有選項可以自定義HashEntry。正如問題所指出的那樣,我會說答案是「你不能」。通常,在HashTable上實現Map可以歸結爲處理衝突 - 一種方法不是非常有效但通常可行,只要發現衝突(在不同密鑰但相同哈希的情況下),就可以重新哈希整個表,直到碰撞不再存在。更常用的答案是有一個多層次的散列表,它基本上遞歸地在每個層次上存儲散列表(計算不同的散列函數)。另一種方法是使用數組的哈希表 - 數組本身存儲具有相同哈希的元素列表 - 如果碰撞數量過大,則重新哈希表。不幸的是,這些解決方案都不能直接用您提供的樣本類來實現。沒有進一步的背景,我不能再多說了,但這似乎是一個設計得很差的練習(這個練習偶爾會對有類似事情的學生施加酷刑)。

在您的框架中黑客攻擊的一種方法是創建一個Pair類型,其hashCode函數僅計算key.hashCode()。這樣,作爲一個值你可以存儲一個數組(然後使用上面提到的數組方法),或者你可以存儲一個元素(然後使用rehash方法)。在這兩種解決方案,解決衝突處理是最困難的元素(你必須處理情況下HashTablePair,但對的value部分不equals()要插入的元素。