一.SparseArray概述
SparseArray是Android特有的API,Java中没有此类,此类为Java容器中HashMap
二.SparseArray与HashMap的数据结构对比
1.HashMap:
是数组和链表或者红黑树的结合体(至于具体什么时候是链表什么时候是红黑树以及HashMap的具体原理,这里就不再展开),下图是HashMap的数据结构:
2.SparseArray:
是单纯的数组组合,通过key来映射数组下标index,再通过数组下标在value数组里查找,下图是SparseArray的数据结构:
下面来看看SparseArray的源码:
数据结构
private int[] mKeys;
private Object[] mValues;
private int mSize;
二分查找函数
// 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
}
put函数
/**
* Adds a mapping from the specified key to the specified value,
* replacing the previous mapping from the specified key if there
* was one.
*/
public void put(int key, E value) {
// 使用二分查找相应的key,成功返回数组的下标,失败返回查找的最后一个位置的index再取反,之后插入新的数据是根据次数插入
int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
if (i >= 0) {
// 如果index大于0,表示查找成功,则更新相应的value
mValues[i] = value;
} else {
i = ~i;
// 特殊的case,直接存
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++;
}
}
get函数
/**
* Gets the Object mapped from the specified key, or null
* if no such mapping has been made.
*/
public E get(int key) {
return get(key, null);
}
/**
* Gets the Object mapped from the specified key, or the specified Object
* if no such mapping has been made.
*/
@SuppressWarnings("unchecked")
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];
}
}
delete函数
/**
* Removes the mapping from the specified key, if there was any.
*/
public void delete(int key) {
int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
if (i >= 0) {
// 标记i的值为 DELETED
if (mValues[i] != DELETED) {
mValues[i] = DELETED;
// 设置gc标记为true
mGarbage = true;
}
}
}
gc函数
// 遍历一遍数组,将非DELETED资源全部移动到数组前面
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的实现主要是使用两个数组,一个来存储key,另一个存储value,两者之间是通过index值来映射;增删查改操作主要都是使用复杂度为O(logn)的二分查找来找到对应的index再进行相应的操作。