(Java) Имеет ли смысл использовать один и тот же тип ключа и значения при использовании Карт? - PullRequest
1 голос
/ 24 марта 2011

Чтобы привести простой пример, рассмотрим класс Place:

public class Place {

    //fields
    private String name;

    private String state;

    private int population;

    private int squareMileage;

    private int elevation;

    //constructors
    public Place() {    
    }

    public Place(String name, String state) {
        this.name = name;
        this.state = state;
    }

    public Place(String name, String state, int population, int squareMileage, 
                    int elevation) {
        this.name = name;
        this.state = state;
        this.population = population;
        this.squareMileage = squareMileage;
        this.elevation = elevation;
    }

    //getters and setters
    public String getName() {
        return this.name;
    }

    public String getState() {
        return this.state;
    }
    //... (other getters and setters omitted)

    //do stuff
}

И класс Places (HashMap из Place объектов):

import java.util.*;

public class Places {
    private Map searchablePlaces;

    public Places() {
        searchablePlaces = new HashMap();
    }

    public void add(Place value) {
        Place key = new Place(value.getName(), value.getState());
        searchablePlaces.put(key, value);
    }

    public Place find(Place key) {
        return searchablePlaces.get(key);
    }

    //override hashCode, equals

    //do stuff
}

По сути, мой вопрос:

  1. Будет ли какая-либо эффективность в HashMap для поиска key, в отличие от поиска value непосредственно в, скажем, отсортированном ArrayList?
  2. Что если key был типа String равен name + state (или типа String[2])?

Ответы [ 5 ]

4 голосов
/ 24 марта 2011

Это сбивает с толку, ИМХО.Я бы определил класс PlaceKey, содержащий только имя и состояние и определяющий hashCode и равно.Место будет содержать PlaceKey и другие атрибуты.И я бы использовал Map<PlaceKey, Place>.

. Обратите внимание, что в вашем примере классу Place требуется equals и hashCode, а не класс Places.

Теперь, чтобы ответить на ваши 2 вопроса:

  1. хэш-карта O (1), а список O (n).Таким образом, карта, как правило, будет быстрее (за исключением, возможно, очень маленьких значений n)
  2. объединение - почти всегда плохая идея.Вы можете иметь name1 = aa, state1 = a, name2 = a и state2 = aa, что приведет к коллизии.Массив не переопределяет equals и hashCode с точки зрения их содержимого и не является подходящим классом ключа карты.
3 голосов
/ 24 марта 2011

Будет ли какая-либо эффективность в поиске ключа в HashMap, в отличие от поиска значения непосредственно, скажем, в отсортированном ArrayList?

Да. Сравнение строк намного медленнее, чем сравнение целых чисел (и, кроме того, редко сравнение строк).

Если вы используете пользовательский объект для ключей, вы должны тщательно реализовать hashCode с учетом наиболее часто используемых значений. Вы также должны иметь оптимизированный equals.

Преимущество пользовательского класса по сравнению с name + state заключается в том, что вы можете учитывать возможные значения.

0 голосов
/ 24 марта 2011
  1. Это зависит от того, как вы ищете HashMap. Например, если вы используете containsKey(), карта будет на порядок быстрее, чем поиск по списку. В типичном случае проверка ключа в хеш-таблице происходит за постоянное время (O(1)). Поиск в отсортированном массиве по ключу можно выполнить за O(log n) раз, если вы используете бинарный поиск. Однако если вы выполняете поиск ключа путем итерации набора ключей (который не гарантируется для сортировки в любом порядке), то у вас есть операция O(n), которая медленнее, чем поиск в отсортированном списке.

    короткая версия? Использование containsKey() даст лучшую производительность.

  2. Вы могли бы сделать это, но тогда зачем использовать Map? Почему не List или Set? Смысл Map заключается в том, чтобы связать ключ со значением. Если вы этого не делаете (а пример кода на самом деле не так), то вы используете неправильную структуру данных для своей задачи.

0 голосов
/ 24 марта 2011

Использование другого (не полностью заполненного) Поместить объект в качестве ключа - это как минимум пустая трата памяти.Обычно вы ищете по уникальному идентификатору.Есть несколько возможностей получить один из них:

  1. Используйте (имя + SEPARATOR + состояние) в качестве ключа, если вы хотите искать, используя их оба.
  2. Используйте несколько карт, по одной длякаждое (доступное для поиска) свойство - если оно не уникально, вы подключаете к нему список.
  3. Используйте (криптографический) хеш объекта в качестве ключа ...
0 голосов
/ 24 марта 2011

Доступ к объектам с помощью ArrayList намного быстрее, чем с помощью ключа HashMap, но указатели на эти объекты должны храниться в памяти в непрерывном блоке, что замедляет удаление и помещение объекта в ArrayList. Поэтому решение о том, какой тип лучше, будет зависеть от операций, которые вы будете выполнять во время выполнения вашей программы.

Например, если вам нужно много раз размещать и / или удалять места, будет лучше использовать HashMap, так как ArrayList менее эффективен. Если ваши места более или менее фиксированы и вам приходится перемещать их редко, то ArrayList даст вам большую производительность.

Если вы определенно используете HashMap, будет быстрее использовать уникальную строку в качестве ключа.

...