Изменение размера HashMap с квадратичным зондированием (реализация резервного массива)
После того, как я проверил, сигнализирует ли коэффициент нагрузки размер базового массива об изменении размера, как я на самом деле делаю изменение размера с квадратичным зондированием?
Вот код Это только часть класса. Кроме того, не могли бы вы проверить, правильно ли я реализую метод add?
import java.util.*;
public class HashMap<K, V> implements HashMapInterface<K, V> {
// Do not make any new instance variables.
private MapEntry<K, V>[] table;
private int size;
/**
* Create a hash map with no entries.
*/
public HashMap() {
table = new MapEntry[STARTING_SIZE];
size = 0;
}
@Override
public V add(K key, V value) {
if (key == null || value == null) {
throw new IllegalArgumentException("Passed in null arguments.");
}
if (getNextLoadFactor() > MAX_LOAD_FACTOR) {
resize();
}
MapEntry<K, V> entry = new MapEntry<>(key, value);
V val = null;
int index = Math.abs(key.hashCode()) % table.length;
int temp = index;
int q = 1;
do {
if (table[index] == null) {
table[index] = entry;
} else if (table[index].getKey().equals(key)) {
val = table[index].getValue();
table[index].setValue(value);
}
index = index + q*q % table.length;
q++;
} while (temp != index);
size++;
return val;
}
private double getNextLoadFactor() {
return (double) size / (double) table.length;
}
private void resize() {
MapEntry<K, V>[] temp = table;
table = new MapEntry[table.length * 2 + 1];
for (int i = 0; i < table.length; i++) {
}
}
1 ответ
Следуя следующему из вики:
1. Get the key k
2. Set counter j = 0
3. Compute hash function h[k] = k % SIZE
4. If hashtable[h[k]] is empty
(4.1) Insert key k at hashtable[h[k]]
(4.2) Stop
Else
(4.3) The key space at hashtable[h[k]] is occupied, so we need to find the next available key space
(4.4) Increment j
(4.5) Compute new hash function h[k] = ( k + j * j ) % SIZE
(4.6) Repeat Step 4 till j is equal to the SIZE of hash table
5. The hash table is full
6. Stop
Исходя из вышеизложенного, мне кажется, что в вашем add
метод. Обратите внимание на шаги (4.1) и (4.2): если table[index] == null
, позиция для ключа была найдена, и вы можете остановиться. Ваш do
будет выполняться снова, потому что сразу после вставки вы обновляете индекс, таким образом temp != index
будет правдой.
Вы также неправильно рассчитываете следующий индекс, измените
index = index + q*q % table.length;
в
index = (Math.abs(key.hashCode()) + q*q) % table.length;
add
таким образом изменится на:
MapEntry<K, V> entry = new MapEntry<>(key, value);
V val = null;
int index = Math.abs(key.hashCode()) % table.length;
int q = 0;
while (table[(index = (Math.abs(key.hashCode()) + q*q++) % table.length)] != null);
table[index] = entry;
size++;
return val;
Можно доказать, что если размер таблицы b
за b > 3
первый b/2
позиции будут уникальными, поэтому можно предположить, что если таблица заполнена менее чем на половину (b/2 - 1)
, вы найдете пустую позицию. Это зависит от вашего MAX_LOAD_FACTOR
,
Для изменения размера вам нужно будет перефразировать каждое значение в новую таблицу. Это связано с тем, что ваша хеш-функция использует размер таблицы в качестве модуля. Ваша хеш-функция в основном изменилась, поэтому вам нужно создать новый массив size + 1
и прочитал каждый элемент в новый массив.
private void resize() {
MapEntry<K, V>[] temp = table;
table = new MapEntry[table.length * 2 + 1];
for (MapEntry<K, V> entry:temp) {
this.add(entry.getKey(), entry.getValue());
}
}
Примечание: я не проверял это, а использовал теорию динамического зондирования и хеш-таблицы для отладки вашего кода. Надеюсь, поможет!