Дважды в HashMap

Вам нужно будет вытолкнуть все из первого стека, чтобы получить нижний элемент. Затем поместите их все обратно во второй стек для каждой операции "удаления очереди".

19
задан David Waters 2 July 2009 в 14:46
поделиться

8 ответов

Краткий ответ: Не делайте этого

Длинный ответ: Вот как будет вычисляться ключ:

Фактический ключ будет java.lang.Double объект, поскольку ключи должны быть объектами. Вот его метод hashCode () :

public int hashCode() {
  long bits = doubleToLongBits(value);
  return (int)(bits ^ (bits >>> 32));
}

Метод doubleToLongBits () в основном принимает 8 байтов и представляет их такой же длины. Это означает, что небольшие изменения в вычислении числа double могут иметь большое значение, и у вас будут ключевые промахи.

Если вы можете согласиться на заданное количество точек после точки - умножьте на 10 ^ (количество цифр после точка) и преобразовать в int (например - для 2 цифр умножить на 100).

Так будет намного безопаснее.

16
ответ дан 30 November 2019 в 03:20
поделиться

I think you are right. Although the hash of the doubles are ints, the double could mess up the hash. That is why, as Josh Bloch mentions in Effective Java, when you use a double as an input to a hash function, you should use doubleToLongBits(). Similarly, use floatToIntBits for floats.

In particular, to use a double as your hash, following Josh Bloch's recipe, you would do:

public int hashCode() {
  int result = 17;
  long temp = Double.doubleToLongBits(the_double_field);
  result = 37 * result + ((int) (temp ^ (temp >>> 32)));
  return result;
}

This is from Item 8 of Effective Java, "Always override hashCode when you override equals". It can be found in this pdf of the chapter from the book.

Hope this helps.

8
ответ дан 30 November 2019 в 03:20
поделиться

Это зависит от того, как вы собираетесь его использовать.

Если вас устраивает только возможность найти значение на основе точно такого же битового шаблона ( или потенциально эквивалентный, такой как +/- 0 и различные NaN), тогда это может быть нормально.

В частности, все NaN будут считаться равными, но +0 и -0 будут считаться разными. Из документации для Double.equals :

Обратите внимание, что в большинстве случаев для двух экземпляры класса Double, d1 и d2, значение d1.equals (d2) истинно, если и только если

d1.doubleValue () == d2.doubleValue () также имеет значение правда. Однако есть два исключения:

  • Если d1 и d2 оба представляют Double.NaN, тогда метод equals возвращает истину, даже если Double.NaN == Double.NaN имеет значение ложь.
  • Если d1 представляет +0,0, а d2 представляет -0,0 или наоборот, равный тест имеет значение false, даже хотя +0.0 == - 0.0 имеет значение true.

Это определение позволяет хеш-таблицам

Скорее всего, вас интересуют «числа, очень близкие к ключу», что делает его намного менее жизнеспособным. В частности, если вы собираетесь выполнить один набор вычислений для получения ключа один раз, а затем другой набор вычислений для получения ключа во второй раз, у вас возникнут проблемы.

6
ответ дан 30 November 2019 в 03:20
поделиться

Краткий ответ: Вероятно, это не сработает.

Честный ответ: Все зависит от.

Более длинный ответ: проблема не в хеш-коде, а в природе равенства сравнения с плавающей запятой. Как отмечают Наландиал и комментаторы его поста, в конечном итоге любое совпадение с хеш-таблицей все равно заканчивается использованием равенства для выбора правильного значения.

Итак, вопрос в том, генерируются ли ваши двойники таким образом, чтобы вы знали, что равняется действительно означает равных? Если вы читаете или вычисляете значение, сохраняете его в хэш-таблице, а затем читаете или вычисляете значение, используя точно такое же вычисление, тогда Double.equals будет работать. Но в остальном это ненадежно: 1,2 + 2,3 не обязательно равно 3,5, это может быть 3,4999995 или что-то еще. (Не настоящий пример, я только что придумал, но такое бывает.

3
ответ дан 30 November 2019 в 03:20
поделиться

Проблема не в хеш-коде, а в точности значений типа double. Это вызовет странные результаты. Пример:

    double x = 371.4;
    double y = 61.9;
    double key = x + y;    // expected 433.3

    Map<Double, String> map = new HashMap<Double, String>();
    map.put(key, "Sum of " + x + " and " + y);

    System.out.println(map.get(433.3));  // prints null

Вычисленное значение (ключ) - «433.29999999999995», которое НЕ РАВНО 433,3, и поэтому вы не найдете запись на карте (возможно, хэш-код также отличается, но это не основная проблема) .

Если вы используете

map.get(key)

, он должен найти запись ... []]

5
ответ дан 30 November 2019 в 03:20
поделиться

Может быть BigDecimal доставит вас туда, куда вы хотите?

2
ответ дан 30 November 2019 в 03:20
поделиться

Это зависит от того, как вы храните карту и получаете к ней доступ, да, аналогичные значения могут в конечном итоге немного отличаться и, следовательно, не иметь одинакового значения хэша.

private static final double key1 = 1.1+1.3-1.6;
private static final double key2 = 123321;
...
map.get(key1);

было бы хорошо, однако

map.put(1.1+2.3, value);
...
map.get(5.0 - 1.6);

было бы опасно

0
ответ дан 30 November 2019 в 03:20
поделиться

The hash of the double is used, not the double itself.

Edit: Thanks, Jon, I actually didn't know that.

I'm not sure about this (you should just look at the source code of the Double object) but I would think any issues with floating point comparisons would be taken care of for you.

0
ответ дан 30 November 2019 в 03:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: