SparseArray 源码解析

来源:互联网 发布:ubuntu强制关闭程序 编辑:程序博客网 时间:2024/06/11 11:54

SparseArray,即稀疏数组,作为一种数据结构,拥有比HashMap更高的执行效率(HashMap的装箱操作使其比SpaseArray慢,如果不考虑装箱拆箱,HashMap效率会比SparseArray高),且SparseArray对内存的使用比HashMap要少,在某些情况下,SparseArray是一种较优选择。SparseArray源码:

    private int[] mKeys;    private Object[] mValues;    private int mSize;      public SparseArray() {        this(10);    }     public SparseArray(int initialCapacity){}

SparseArray维护两个数组,一个int[]保存key,Object[]保存value,key数组对应的i位置也就是对的value值在所value数据的i位置。SparseArray默认构造大小为10,也支持自定义大小的初始化。

    private static final Object DELETED = new Object();    private boolean mGarbage = false;    public void remove(int key) {        delete(key);    }    public void delete(int key) {        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);        if (i >= 0) {            if (mValues[i] != DELETED) {                mValues[i] = DELETED;                mGarbage = true;            }        }    }

先看的是SparseArray的delete和remove操作,在根据key移除相应value的时候,value[]数组并没有将对应的value彻底删除,而是将其引用DELETED , 表示此位置有空位,可以插入新值。 并将mGarbarge 置为true,用以提示数组存在是空间,以便之后的gc()使用。 而根据key的位置删除value,需要先定位key的位置,SparseArray的key值保证升序排序,因此定位使用二分查找

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    }

经典的二分查找,不多做说明

 private void gc() {        // Log.e("SparseArray", "gc start with " + mSize);        int n = mSize;        int o = 0;        int[] keys = mKeys;        Object[] values = mValues;        for (int i = 0; i < n; i++) {            Object val = values[i];            if (val != DELETED) {                if (i != o) {                    keys[o] = keys[i];                    values[o] = val;                    values[i] = null;                }                o++;            }        }        mGarbage = false;        mSize = o;        // Log.e("SparseArray", "gc end with " + mSize);    }

SparseArray的gc()操作,即将value数组和key数组变得紧凑

。。。。。。。

箭头为mSize的最大索引位置,在gc后将mGarbage设置为false

    public void put(int key, E value) {        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);        if (i >= 0) {            mValues[i] = value;        } else {            i = ~i;            if (i < mSize && mValues[i] == DELETED) {                mKeys[i] = key;                mValues[i] = value;                return;            }            if (mGarbage && mSize >= mKeys.length) {                gc();                // Search again because indices may have changed.                i = ~ContainerHelpers.binarySearch(mKeys, mSize, key);            }            mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);            mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);            mSize++;        }

put()首先使用二分查找定位i的位置,如果定位得到 i 且 i>=0 ,说明存在key值,此时直接更新此key对应的value值。 如果定位不到 i 的位置,将 i 取反, 看看 i 是否小于mSize 并且 key[i] 对应的 value[i] 对应的值已失效,如果满足条件,则更新 i 位置的 key 值和 value值 (和前面的差别为,前者相当于更新,更新了value,后者相当于重置,重置了key和value。且此处的更新key并不会破坏key[]的递增) ; 如果 mGarbage && mSize >= mKeys.length , 即存在失效值,且当前容量mSize超过了数组最大容量, 调用gc()是数组紧凑,并释放失效值, 此时需要再次定位 i , 因为数值位于数组中的位置已经改变。 之后使用 GrowingArrayUtils.insert(),将数组扩容,并将key和value插入相应位置。

 public int size() {        if (mGarbage) {            gc();        }        return mSize;    }

返回当前容量,如果需要,则gc()

 public int keyAt(int index) {        if (mGarbage) {            gc();        }        return mKeys[index];    } public E valueAt(int index) {        if (mGarbage) {            gc();        }        return (E) mValues[index];    }

根据索引值返回相应key或value,此索引前如果有需要则gc

    public void append(int key, E value) {        if (mSize != 0 && key <= mKeys[mSize - 1]) {            put(key, value);            return;        }        if (mGarbage && mSize >= mKeys.length) {            gc();        }        mKeys = GrowingArrayUtils.append(mKeys, mSize, key);        mValues = GrowingArrayUtils.append(mValues, mSize, value);        mSize++;    }

和put相差不多。

以上为全部内容,有些简陋,忘见谅(待理解更深再来改进)
此博客仅供个人笔记,如有错误之处,欢迎指出

原创粉丝点击