SparseArray 源码解析

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相差不多。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值