Разница между принципами реализации HashMap и ArrayMap и их соответствующими преимуществами

1. Принцип композиции ArrayMap

1. Структура хранения arrayMap.

ArrayMap — это структура данных сопоставления <ключ, значение>. Ее конструкция больше ориентирована на оптимизацию памяти. Внутри для хранения данных используются два массива. Один массив записывает хеш-значение ключа, а другой массив записывает значение значения. Как и SparseArray, он также использует метод двоичного поиска для сортировки ключей от меньшего к большему.При добавлении, удалении и поиске данных метод двоичного поиска сначала используется для получения соответствующего индекса, а затем индекс используется для добавления, поиска , удаление и т. д. Таким образом, сценарий применения такой же, как и у SparseArray, если объем данных относительно велик, его производительность ухудшится как минимум на 50%.

Основными данными, хранящимися в arrayMap, являются два данных:

int[] mHashes;

Объект[] mArray;

mHashs хранит хеш-значение каждого ключа, а хеш-значения этих ключей сортируются в массиве от меньшего к большему.

Длина массива mArray в два раза больше, чем у mHashs. Каждые два элемента являются ключом и значением. Эти два элемента соответствуют хеш-значению в mHashs. Структура mArray показана на рисунке ниже.

Метод АррайМап:

public V put(K key, V value)//添加键值对

public V get(Objectkey)//获取数据

public V remove(Objectkey)//删除数据

public K keyAt(int index) //获取相应的key

public V valueAt(int index)//获取相应的value

public int indexOfKey(Object key)//获取下标

Например:

key2 и value2 расположены на 2-й и 3-й позициях массива соответственно (считая от 0). Соответствующее значение хеш-функции составляет 2/2=1 бит хеша, то есть mHashes[1];

2. Метод get массива arrayMap.

@Override
public V get(Object key) {
    final int index = indexOfKey(key);
    return index >= 0 ? (V)mArray[(index<<1)+1] : null;
}

Метод get на самом деле представляет собой процесс вычисления индекса. Если после расчета индекс больше 0, это означает, что он существует. Умножение его непосредственно на 2 — это значение соответствующего ключа. Умножение на 2 плюс 1 — это значение соответствующее значение.

3.indexOf(ключ объекта, хэш int).

int indexOf(Object key, int hash) {
    final int N = mSize;

    // Important fast case: if nothing is in here, nothing to look for.
    if (N == 0) {
        return ~0;
    }

    int index = ContainerHelpers.binarySearch(mHashes, N, hash);

    // If the hash code wasn't found, then we have no entry for this key.
    if (index < 0) {
        return index;
    }

    // If the key at the returned index matches, that's what we want.
    if (key.equals(mArray[index<<1])) {
        return index;
    }

    // Search for a matching key after the index.
    int end;
    for (end = index + 1; end < N && mHashes[end] == hash; end++) {
        if (key.equals(mArray[end << 1])) return end;
    }

    // Search for a matching key before the index.
    for (int i = index - 1; i >= 0 && mHashes[i] == hash; i--) {
        if (key.equals(mArray[i << 1])) return i;
    }

    // Key not found -- return negative value indicating where a
    // new entry for this key should go.  We use the end of the
    // hash chain to reduce the number of array entries that will
    // need to be copied when inserting.
    return ~end;
}

2. Соответствующие преимущества HashMap и ArrayMap.

1. Эффективность поиска

Поскольку HashMap напрямую вычисляет индекс на основе значения хеш-кода, эффективность его поиска возрастает по мере увеличения длины массива.

ArrayMap использует двоичный поиск, поэтому каждый раз, когда длина массива удваивается, требуется еще одно решение, и эффективность снижается.

Поэтому, когда количество карт относительно велико, рекомендуется использовать

 

2. Количество расширения

 

Начальная длина HashMap равна 16. Каждый раз, когда он расширяется, он напрямую увеличивает пространство массива в два раза.

Каждый раз при расширении ArrayMap, если длина размера больше 8, применяется для длины размера * 1,5, если она больше 4 и меньше 8, применяется к 8 длинам, а если меньше 4, применяется к 4 длинам .

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

 

3. Эффективность расширения

 

Каждый раз, когда HashMap расширяется, позиция каждого члена массива пересчитывается, а затем помещается в новую позицию.

ArrayMap напрямую использует System.arraycopy.

Так что ArrayMap определенно более выгоден с точки зрения эффективности.

Здесь нужно пояснить, что в Интернете ходит слух, что ArrayMap использует System.arraycopy для экономии места в памяти, я правда этого не вижу. Arraycopy также присваивает объекты старого массива новому массиву один за другим. Конечно, arraycopy определенно более эффективен, поскольку он напрямую вызывает код c-уровня.

 

4. Потребление памяти

ArrayMap использует уникальный способ повторного использования пространства массива, оставшегося из-за расширения данных, чтобы облегчить использование следующего ArrayMap. HashMap не имеет такого дизайна.

Поскольку ArrayMap кэширует только длины 4 и 8, если Map используется часто и объем данных относительно невелик, ArrayMap, несомненно, сэкономит значительную память.

 

5. Резюме

В итоге,

Если объем данных относительно невелик и для хранения данных необходимо часто использовать Карты, рекомендуется использовать ArrayMap.

Когда объем данных относительно велик, рекомендуется использовать HashMap.

Supongo que te gusta

Origin blog.csdn.net/qq_28845393/article/details/87601753
Recomendado
Clasificación