【问题标题】:Implementing a generic map using a hash table in Java在 Java 中使用哈希表实现通用映射
【发布时间】:2018-04-01 23:55:38
【问题描述】:

帖子详情
在数据结构课程中,我获得了“二次探测哈希表”类的 Java 源代码,并要求我实现一个通用映射(使用 getput 方法)和将键/定义对存储在哈希表中。我在阅读本书时理解了这些材料,但发现很难用编程语言 (Java) 实现。我认为部分问题在于准确理解问题的要求,部分是 Java 编程经验的不足。我希望收到一些关于如何解决此类问题并填补我所缺少的 Java 知识的建议。

我的一些问题
与我应该创建的通用映射相关的哈希表类的功能是什么?哈希表有几种方法包括getinsertremoverehash等……目的是什么哈希表生成一个哈希值用作映射类中的键?键和定义是存储在哈希表中还是将存储在映射中?如果哈希表已经完成了所有这些,那么制作地图有什么意义?

有人可以帮助我了解如何解决此类问题吗?有哪些参考资料可能对我有所帮助,无论是具体解决这个问题还是了解如何有效和有条不紊地完成此类练习?

我很感激我能得到的任何帮助。我包含了书中的代码来帮助说明问题。

从教科书二次探查哈希表代码

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;
    }
}

【问题讨论】:

    标签: java generics hashtable equals hashcode


    【解决方案1】:

    通常,您面临的问题是implementing 一个给定的interfaceMap 是接口 - HashTable 是实现它的方法,底层数据结构。

    但是,我理解您的困惑,因为您提供的 HashTable 的定义似乎不适合这项工作,因为它似乎没有使用自定义键的选项(而是始终依赖于对象的哈希计算哈希的代码)也没有自定义HashEntry的选项。由于指定了问题,我会说答案是“你不能”。通常,在HashTable 上实现Map 归结为处理冲突 - 一种不是很有效但通常有效的方法是,每当你发现冲突时(你有不同的键但哈希值相同的情况) ,您重新散列整个表,直到冲突不再存在。更普遍采用的答案是拥有一个多级哈希表,它基本上在每个级别上递归地存储一个哈希表(计算不同的哈希函数)。另一种方法是使用数组的哈希表——数组本身存储具有相同哈希的元素列表——如果冲突的数量太大,则重新哈希。不幸的是,这些解决方案都不能通过您提供的示例类直接实现。没有进一步的上下文,我真的不能说更多,但这似乎是一个设计糟糕的练习(这是来自偶尔用类似事情折磨学生的人)。

    在你的框架中解决这个问题的一种方法是创建一个Pair 类型,其hashCode 函数只计算key.hashCode()。这样,作为值,您可以存储一个数组(然后使用我上面提到的数组方法),或者您可以存储单个元素(然后使用 rehash 方法)。在任一解决方案中,解决冲突处理是最困难的元素(您必须处理 HashTable contains() 您的 Pair,但该对的 value 部分不 equals() 的元素你想插入。

    【讨论】:

      猜你喜欢
      • 2018-10-13
      • 1970-01-01
      • 2013-11-22
      • 2021-07-22
      • 2013-08-05
      • 2017-10-04
      • 1970-01-01
      • 1970-01-01
      • 2010-12-30
      相关资源
      最近更新 更多