Java HashMap:将存储桶实现更改为线性探测方法

时间:2018-07-04 18:10:03

标签: java hashmap

在此之前,我对我的经验不足深表歉意,这些都是难以理解的高级概念。据我了解,线性探测是循环的,直到找到一个空单元格它才会停止。

但是我不确定如何实现它。一些关于如何的示例将不胜感激。再次抱歉,我没有足够的经验,我不是经过审查的程序员,我的学习过程非常缓慢。

 public boolean ContainsElement(V element)
   {
        for(int i = 0; i < capacity; i++)
        {
            if(table[i] != null)
        {
            LinkedList<Entry<K, V>> bucketMethod = table[i];
            for(Entry<K, V> entry : bucketMethod)
            {
                if(entry.getElement().equals(element))
                {
                    return true;
                  }
              }
          }
      }

      return false;
   }

2 个答案:

答案 0 :(得分:1)

这是一个基于Wikipedia article for open addressing中的伪代码示例的工作哈希表。

我认为Wikipedia示例与我的示例之间的主要区别是:

  • 由于Java用负数对(hashCode())进行模数运算的方式,对%进行了一些处理。
  • 实现了简单的调整大小逻辑。
  • 稍微更改了remove方法中的逻辑,因为Java没有goto

否则,它或多或少只是直接翻译。

package mcve;

import java.util.*;
import java.util.stream.*;

public class OAHashTable {
    private Entry[] table = new Entry[16]; // Must be >= 4. See findSlot.
    private int     size  = 0;

    public int size() {
        return size;
    }

    private int hash(Object key) {
        int hashCode = Objects.hashCode(key)
            & 0x7F_FF_FF_FF; // <- This is like abs, but it works
                             //    for Integer.MIN_VALUE. We do this
                             //    so that hash(key) % table.length
                             //    is never negative.
        return hashCode;
    }

    private int findSlot(Object key) {
        int i = hash(key) % table.length;

        // Search until we either find the key, or find an empty slot.
        //
        // Note: this becomes an infinite loop if the key is not already
        //       in the table AND every element in the array is occupied.
        //       With the resizing logic (below), this will only happen
        //       if the table is smaller than length=4.
        while ((table[i] != null) && !Objects.equals(table[i].key, key)) {
            i = (i + 1) % table.length;
        }

        return i;
    }

    public Object get(Object key) {
        int i = findSlot(key);
        if (table[i] != null) { // Key is in table.
            return table[i].value;
        } else {                // Key is not in table
            return null;
        }
    }

    private boolean tableIsThreeQuartersFull() {
        return ((double) size / (double) table.length) >= 0.75;
    }

    private void resizeTableToTwiceAsLarge() {
        Entry[] old = table;

        table = new Entry[2 * old.length];
        size  = 0;

        for (Entry e : old) {
            if (e != null) {
                put(e.key, e.value);
            }
        }
    }

    public void put(Object key, Object value) {
        int i = findSlot(key);
        if (table[i] != null) { // We found our key.
            table[i].value = value;
            return;
        }
        if (tableIsThreeQuartersFull()) {
            resizeTableToTwiceAsLarge();
            i = findSlot(key);
        }
        table[i] = new Entry(key, value);
        ++size;
    }

    public void remove(Object key) {
        int i = findSlot(key);
        if (table[i] == null) {
            return; // Key is not in the table.
        }

        int j = i;
        table[i] = null;
        --size;

        while (true) {
            j = (j + 1) % table.length;
            if (table[j] == null) {
                break;
            }
            int k = hash(table[j].key) % table.length;
            // Determine if k lies cyclically in (i,j]
            // |    i.k.j |
            // |....j i.k.| or  |.k..j i...|
            if ( (i<=j) ? ((i<k)&&(k<=j)) : ((i<k)||(k<=j)) ) {
                continue;
            }
            table[i] = table[j];
            i = j;
            table[i] = null;
        }
    }

    public Stream<Entry> entries() {
        return Arrays.stream(table).filter(Objects::nonNull);
    }

    @Override
    public String toString() {
        return entries().map(e -> e.key + "=" + e.value)
                        .collect(Collectors.joining(", ", "{", "}"));
    }

    public static class Entry {
        private Object key;
        private Object value;

        private Entry(Object key, Object value) {
            this.key   = key;
            this.value = value;
        }

        public Object getKey()   { return key;   }
        public Object getValue() { return value; }
    }

    public static void main(String[] args) {
        OAHashTable t = new OAHashTable();

        t.put("A", 1);
        t.put("B", 2);
        t.put("C", 3);

        System.out.println("size = " + t.size());
        System.out.println(t);

        t.put("X", 4);
        t.put("Y", 5);
        t.put("Z", 6);
        t.remove("C");
        t.remove("B");
        t.remove("A");

        t.entries().map(e -> e.key)
                   .map(key -> key + ": " + t.get(key))
                   .forEach(System.out::println);
    }
}

答案 1 :(得分:-1)

java.util.Map的java.util.HashMap实现内部提供了线性探测,即HashMap可以解决哈希表中的冲突。