Почему эта реализация Quadratic Probing терпит неудачу, когда не переопределяет значения при столкновении?
Моя текущая реализация Quadratic Probing заменяет элемент, сохраняемый в текущем индексе, новым элементом при возникновении коллизии. Я вставляю три объекта Person, которые хранятся с использованием их фамилии в качестве ключа. Чтобы проверить разрешение столкновения реализации, у них всех есть та же самая фамилия, которая является "Ветряной мельницей".
Мне нужна реализация, чтобы сохранить все объекты person, но просто переместить их в другой индекс, а не переопределять их.
Размер списка был установлен равным 7, он хранится в переменной "M", используемой по модулю в функции вставки.
Вставить функцию
@Override
public void put(String key, Person value) {
int tmp = hash(key);
int i, h = 0;
for (i = tmp; keys[i] != null; i = (i + h * h++) % M) {
collisionCount++;
if (keys[i].equals(key)) {
values[i] = value;
return;
}
}
keys[i] = key;
values[i] = value;
N++;
}
Хэш-функция
private int hash(String key) {
return (key.hashCode() & 0x7fffffff) % M;
}
получить функцию
@Override
public List<Person> get(String key) {
List<Person> results = new ArrayList<>();
int tmp = hash(key);
int i = hash(key), h = 0;
while (keys[i] != null)
{
if (keys[i].equals(key))
results.add(values[i]);
i = (i + h * h++) % M;
}
return results;
}
Когда я удаляю фрагмент кода, который переопределяет предыдущие значения, индекс int переполняется и превращается в отрицательное число, вызывая сбой программы.
2 ответа
Я думаю, что есть два вопроса с вашим кодом:
Вы не проверяете, заполнена ли (мульти) карта. На практике вы хотите сделать 2 проверки:
- проверить, если
N==M
(или, возможно, какой-то меньший порог, как 90%M
) - делать
collisionCount
локальная переменная и когда она достигаетN
(к сожалению, эта проверка также необходима, чтобы избежать некоторых патологических случаев)
- проверить, если
в обоих случаях вы должны расширить область хранения и скопировать в нее старые данные (заново вставить). Это само по себе должно исправить вашу ошибку для небольших значений M
но для действительно больших размеров карты вам все еще нужно следующее.
- Вы не учли, как мод (
%
Операция работает в Java. Особенно для отрицательного значенияa
значениеa % b
тоже отрицательно. Поэтому, когда вы вставляете много значений и проверяете следующий индекс,i + h^2
может переполнитьсяInteger.MAX_VALUE
и стать отрицательным. Чтобы это исправить, вы можете использовать такой метод:
static int safeMod(int a, int b) {
int m = a % b;
return (m >= 0) ? m : (m+b);
}
Вы получаете переполнение, потому что вы делаете % M
после некоторых операций с int, которые вызывают переполнение. Вам нужно заменить i = (i + h * h++) % M
с некоторыми дополнительными операциями, основанными на свойствах операций по модулю ( https://en.wikipedia.org/wiki/Modulo_operation):
- (a + b) mod n = [(a mod n) + (b mod n)] mod n.
- ab mod n = [(a mod n) (b mod n)] mod n.