SparseArray采用时间换取空间的方式来提升手机App的运行效率,这也是其与HashMap的区别;HashMap经过空间换取时间,查找迅速;HashMap中当table数组中内容达到总容量0.75时,则扩展为当前容量的两倍,关于HashMap可查看HashMap实现原理学习)android
下边对其源码进行简单学习。数组
// 构造方法 public SparseArray() { this(10); } // 构造方法 public SparseArray(int initialCapacity) { if (initialCapacity == 0) { mKeys = EmptyArray.INT; mValues = EmptyArray.OBJECT; } else { // key value各自为一个数组,默认长度为10 mValues = ArrayUtils.newUnpaddedObjectArray(initialCapacity); mKeys = new int[mValues.length]; } mSize = 0; }
ps:
SparseArray构造方法中,建立了两个数组mKeys、mValues分别存放int与Object,其默认长度为10学习
public void put(int key, E value) { // 二分查找,key在mKeys列表中对应的index int i = ContainerHelpers.binarySearch(mKeys, mSize, key); // 若是找到,则直接赋值 if (i >= 0) { mValues[i] = value; } // 找不到 else { // binarySearch方法中,找不到时,i取了其非,这里再次取非,则非非则正 i = ~i; // 若是该位置的数据正好被删除,则赋值 if (i < mSize && mValues[i] == DELETED) { mKeys[i] = key; mValues[i] = value; return; } // 若是有数据被删除了,则gc if (mGarbage && mSize >= mKeys.length) { gc(); // Search again because indices may have changed. i = ~ContainerHelpers.binarySearch(mKeys, mSize, key); } // 插入数据,增加mKeys与mValues列表 mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key); mValues = GrowingArrayUtils.insert(mValues, mSize, i, value); mSize++; } }
ps:this
// 经过key查找对应的value public E get(int key) { return get(key, null); } // 经过key查找对应的value public E get(int key, E valueIfKeyNotFound) { // mKeys数组中采用二分查找,找到key对应的index int i = ContainerHelpers.binarySearch(mKeys, mSize, key); // 没有找到,则返回空 if (i < 0 || mValues[i] == DELETED) { return valueIfKeyNotFound; } else { // 找到则返回对应的value return (E) mValues[i]; } }
ps:
每次调用get,则需通过一次mKeys数组的二分查找,所以mKeys数组越大则二分查找的时间就越长,所以SparseArray在大量数据,千以上时,会效率较低spa
// array为有序数组 // size数组中内容长度 // value要查找的值 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]; // 若是中间元素小于要查找元素,则midIndex赋值给 lo if (midVal < value) { lo = mid + 1; } // 若是中间元素大于要查找元素,则midIndex赋值给 hi else if (midVal > value) { hi = mid - 1; } // 找到则返回 else { return mid; // value found } } // 找不到,则lo 取非 return ~lo; // value not present }
ArrayMap和SparseArray有点相似;其中含有两个数组,一个是mHashes(key的hash值数组,为一个有序数组),另外一个数组存储的是key和value,其中key和value是成对出现的,key存储在数组的偶数位上,value存储在数组的奇数位上。.net
public SimpleArrayMap() { // key的hash值数组,为一个有序数组 mHashes = ContainerHelpers.EMPTY_INTS; // key 与 value数组 mArray = ContainerHelpers.EMPTY_OBJECTS; mSize = 0; }
ps:
构造方法中初始化了两个数组mHashes、mArray,其中mHashes为key的Hash值对应的数组code
public V put(K key, V value) { // key 对应的hash值 final int hash; // hash对应的mHashes列表的index int index; // key为空,hash为0 if (key == null) { hash = 0; index = indexOfNull(); } // else { // 计算key的hashcode hash = key.hashCode(); // 查找key对应mHashes中的index,大于0则找到了,不然为未找到 // 这里涉及到hash冲突,若是hash冲突,则在index的相邻位置插入数据 index = indexOf(key, hash); } // 找到key对应mHashes中的index if (index >= 0) { // 取出基数位置原有的Value index = (index<<1) + 1; final V old = (V)mArray[index]; // 将新数据放到基数index位置 mArray[index] = value; return old; } // indexOf中取了反,这里反反则正 index = ~index; // 若是满了就扩容 if (mSize >= mHashes.length) { final int n = mSize >= (BASE_SIZE*2) ? (mSize+(mSize>>1)) : (mSize >= BASE_SIZE ? (BASE_SIZE*2) : BASE_SIZE); final int[] ohashes = mHashes; final Object[] oarray = mArray; // 扩容 allocArrays(n); // 把原来的数据拷贝到扩容后的数组中 if (mHashes.length > 0) { if (DEBUG) Log.d(TAG, "put: copy 0-" + mSize + " to 0"); System.arraycopy(ohashes, 0, mHashes, 0, ohashes.length); System.arraycopy(oarray, 0, mArray, 0, oarray.length); } freeArrays(ohashes, oarray, mSize); } // 根据上面的二分法查找,若是index小于mSize,说明新的数据是插入到数组之间index位置,插入以前须要把后面的移位 if (index < mSize) { if (DEBUG) Log.d(TAG, "put: move " + index + "-" + (mSize-index) + " to " + (index+1)); System.arraycopy(mHashes, index, mHashes, index + 1, mSize - index); System.arraycopy(mArray, index << 1, mArray, (index + 1) << 1, (mSize - index) << 1); } // 保存数据 mHashes[index] = hash; mArray[index<<1] = key; mArray[(index<<1)+1] = value; mSize++; return null; }
// 根据key 与key的hash,查找key对应的index 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; } // 二分查找mHashes有序数组,查找hash对应的index int index = ContainerHelpers.binarySearch(mHashes, N, hash); // 没有找到 if (index < 0) { return index; } // 偶数位为对应的key,则找到了 if (key.equals(mArray[index<<1])) { return index; } // index以后查找 // 这里涉及到hash冲突,若是hash冲突,则在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; } // index以前查找 // 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; } // 没有找到 return ~end; }