The difference between the implementation principles of HashMap and ArrayMap and their respective advantages

1. The composition principle of ArrayMap

1. The storage structure of arrayMap.

ArrayMap is a <key, value> mapping data structure. Its design is more concerned with memory optimization. Internally, two arrays are used for data storage. One array records the hash value of the key, and the other array records the Value value. Like SparseArray, it also uses the binary search method to sort keys from small to large. When adding, deleting, and searching data, the binary search method is first used to obtain the corresponding index, and then the index is used to add, search, delete, etc. Operation, therefore, the application scenario is the same as that of SparseArray. If the amount of data is relatively large, its performance will be degraded by at least 50%.

The main data stored in arrayMap are two data,

int[] mHashes;

Object[] mArray;

mHashs stores the hash value of each key, and the hash values ​​of these keys are sorted from small to large in the array.

The array length of mArray is twice that of mHashs. Each two elements are key and value. These two elements correspond to the hash value in mHashs. The structure of mArray is shown in the figure below.

ArrayMap method:

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)//获取下标

For example:

key2 and value2 are located at the 2nd and 3rd positions of the array respectively (counting from 0). The corresponding hash value is 2/2=1 bit of hash, which is mHashes[1];

2. The get method of arrayMap.

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

The get method is actually a process of calculating index. After calculation, if the index is greater than 0, it means it exists. Multiplying it directly by 2 is the value of the corresponding key. Multiplying by 2 plus 1 is the value of the corresponding value.

3.indexOf(Object key,int hash) method.

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. The respective advantages of HashMap and ArrayMap

1. Search efficiency

Because HashMap directly calculates the index based on the hashcode value, its search efficiency increases as the array length increases.

ArrayMap uses binary search, so every time the array length doubles, one more judgment is required and the efficiency decreases.

Therefore, when the number of Maps is relatively large, it is recommended to use

 

2. Expansion quantity

 

The initial length of HashMap is 16. Every time it is expanded, it directly applies for double the array space.

Every time ArrayMap is expanded, if the size length is greater than 8, apply for size*1.5 lengths, if it is greater than 4 and less than 8, apply for 8 lengths, and if it is less than 4, apply for 4 lengths.

In this comparison, ArrayMap actually applies for less memory space, but the frequency of expansion will be higher. Therefore, if the amount of data is relatively large, it is more appropriate to use HashMap, because its number of expansions is much less than that of ArrayMap.

 

3. Expansion efficiency

 

Each time HashMap is expanded, the position of each array member is recalculated and then placed at the new position.

ArrayMap uses System.arraycopy directly.

So ArrayMap is definitely more advantageous in terms of efficiency.

It needs to be explained here that there is a rumor on the Internet that ArrayMap uses System.arraycopy to save memory space. I really don’t see this. Arraycopy also assigns the objects of the old array to the new array one by one. Of course, arraycopy is definitely more efficient, because it is directly calling the c-layer code.

 

4. Memory consumption

ArrayMap adopts a unique way to reuse the array space left due to data expansion to facilitate the use of the next ArrayMap. HashMap does not have this design.

Since ArrayMap only caches the lengths of 4 and 8, if the Map is used frequently and the amount of data is relatively small, ArrayMap will undoubtedly save considerable memory.

 

5. Summary

In summary,

When the amount of data is relatively small and Maps need to be used frequently to store data, it is recommended to use ArrayMap.

When the amount of data is relatively large, it is recommended to use HashMap.

Guess you like

Origin blog.csdn.net/qq_28845393/article/details/87601753