当前位置:   article > 正文

HashMap 优化: SparseArray / ArrayMap_sparsearray hasnmap优点

sparsearray hasnmap优点

HashMap

参考:

HashMap详解以及源码分析

链表实战(带图分析)

我画了近百张图来理解红黑树

Hash算法解决冲突的四种方法

SparseArray

参考: SparseArray详解及源码简析

  • 其内部主要通过 2 个数组来存储 key 和 value,分别是 int[] 和 Object[]。这也限定了其 key 只能为 int 类型,且 key 不能重复,否则会发生覆盖。

  • 一切操作都是基于二分查找算法,将 key 以升序的方法 “紧凑” 的排列在一起,从而提高内存的利用率以及访问的效率。相比较 HashMap 而言,这是典型的时间换空间的策略。

  • 删除操作并不是真的删除,而只是标记为 DELETE,以便下次能够直接复用。

SparseArray是android里为<Interger,Object>这样的Hashmap而专门写的类,目的是提高内存效率,其核心是折半二分查找函数(binarySearch)。

注意内存二字很重要,因为它仅仅提高内存效率,而不是提高执行效率,
它只适用于android系统(内存对android项目有多重要,地球人都知道)。

SparseArray有两个优点:

  • 1.避免了自动装箱(auto-boxing),
  • 2.数据结构不会依赖于外部对象映射。

我们知道HashMap 采用一种所谓的“Hash 算法”来决定每个元素的存储位置,存放的都是数组元素的引用,通过每个对象的hash值来映射对象。而SparseArray则是用数组数据结构来保存映射,然后通过折半查找来找到对象。但其实一般来说,SparseArray执行效率比HashMap要慢一点,因为查找需要折半查找,而添加删除则需要在数组中执行,而HashMap都是通过外部映射。但相对来说影响不大,最主要是SparseArray不需要开辟内存空间来额外存储外部映射,从而节省内存。

//SparseArray
public class SparseArray<E> implements Cloneable {

    private int[] mKeys;
    private Object[] mValues;
    private int mSize;

    public E get(int key, E valueIfKeyNotFound) {
        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);

        if (i < 0 || mValues[i] == DELETED) {
            return valueIfKeyNotFound;
        } else {
            return (E) mValues[i];
        }
    }
}    



//SparseBooleanArray
public class SparseBooleanArray implements Cloneable {

    private int[] mKeys;
    private boolean[] mValues;
    private int mSize;

    public boolean get(int key, boolean valueIfKeyNotFound) {
        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);

        if (i < 0) {
            return valueIfKeyNotFound;
        } else {
            return mValues[i];
        }
    }
}



//SparseIntArray
public class SparseIntArray implements Cloneable {
    private int[] mKeys;
    private int[] mValues;
    private int mSize;

    public int get(int key, int valueIfKeyNotFound) {
        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);

        if (i < 0) {
            return valueIfKeyNotFound;
        } else {
            return mValues[i];
        }
    }
}


//SparseLongArray
public class SparseLongArray implements Cloneable {
    private int[] mKeys;
    private long[] mValues;
    private int mSize;

    public long get(int key, long valueIfKeyNotFound) {
        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);

        if (i < 0) {
            return valueIfKeyNotFound;
        } else {
            return mValues[i];
        }
    }
}   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74

ArrayMap

参考: ArrayMap详解及源码分析

  • mHashs 数组以升序的方式保存了所有的 hash code,在查找数据时则通过二分查找 hash code 所对应的 index。这也是它的 get() 比 HashMap 慢的根据原因所在。

  • 通过 hash code 在 mHashs 数组里的 index 值来确定 key 以及 value 在 mArrays 数组中的存储位置。一般来说分别就是 index << 1 以及 index << 1 + 1。再简单点说就是 index * 2 以及 index * 2 + 1。

  • hashCode 必然可能存在冲突,这里是怎么解决的呢?简单点说就是,在 mHashs 中相邻地存多份 hash code,而在 mArray 中分别以它们的 index 来计算 key-value 的存储位置。

  • 当进行 remove 操作时,在一定条件下,可能会发生数据的压缩,从而节省内存的使用。

public final class ArrayMap<K, V> implements Map<K, V> {

    int[] mHashes;
    Object[] mArray;
    int mSize;

    private static int binarySearchHashes(int[] hashes, int N, int hash) {
        try {
            return ContainerHelpers.binarySearch(hashes, N, hash);
        } catch (ArrayIndexOutOfBoundsException e) {
            if (CONCURRENT_MODIFICATION_EXCEPTIONS) {
                throw new ConcurrentModificationException();
            } else {
                throw e; // the cache is poisoned at this point, there's not much we can do
            }
        }
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

ContainerHelpers

package android.util;

class ContainerHelpers {

    // This is Arrays.binarySearch(), but doesn't do any argument validation.
    static int binarySearch(int[] array, int size, int value) {
        int lo = 0;
        int hi = size - 1;

        while (lo <= hi) {
            final int mid = (lo + hi) >>> 1;
            final int midVal = array[mid];

            if (midVal < value) {
                lo = mid + 1;
            } else if (midVal > value) {
                hi = mid - 1;
            } else {
                return mid;  // value found
            }
        }
        return ~lo;  // value not present
    }

    static int binarySearch(long[] array, int size, long value) {
        int lo = 0;
        int hi = size - 1;

        while (lo <= hi) {
            final int mid = (lo + hi) >>> 1;
            final long midVal = array[mid];

            if (midVal < value) {
                lo = mid + 1;
            } else if (midVal > value) {
                hi = mid - 1;
            } else {
                return mid;  // value found
            }
        }
        return ~lo;  // value not present
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

什么时候使用SparseArray/ArrayMap

1、如果key的类型已经确定为int类型,那么使用SparseArray,因为它避免了自动装箱的过程,
如果key为long类型,它还提供了一个LongSparseArray来确保key为long类型时的使用

2、如果key类型为其它的类型,则使用ArrayMap

demo

        //1、适用于键为int的map数据结构类型
        //key为int的时候才能使用,注意是int而不是Integer,
        // 这也是sparseArray效率提升的一个点,去掉了装箱的操作
        //2、适用于小规模数据存储
        //3、内部使用二分查找进行数据查询,查询效率高
        //4、不需要单独开辟内存来映射对象,节约内存
        SparseArray<String> intSparseArray = new SparseArray<>();
        intSparseArray.put(1, "java");
        intSparseArray.put(2, "js");
        intSparseArray.put(3, "kotlin");
        intSparseArray.put(4, "flutter");

        ArrayMap<String, String> arrayMap = new ArrayMap<>();
        arrayMap.put("1", "java");
        arrayMap.put("2", "js");
        arrayMap.put("3", "kotlin");
        arrayMap.put("4", "flutter");

        HashMap<String, String> hashMap = new HashMap<>();
        hashMap.put("1", "java");
        hashMap.put("2", "js");
        hashMap.put("3", "kotlin");
        hashMap.put("4", "flutter");

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/666325
推荐阅读
相关标签
  

闽ICP备14008679号