您的位置:首页 > 其它

SparseArray源码中的G点

2016-08-08 10:59 155 查看
通过上一章 小探Android中的SparseArray和HashMap了解了SparseArray和HashMap的一点区别,以及SparseArray的使用场景。这一章主要来记录一下查看SparseArray源码时,个人感觉源码中值得借鉴的地方:二分查找

代码如下:

// 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
}


以上二分查找需要传入三个参数:

array : 需要查找的数组对象

size : 查找数组的范围,一般情况下需要查找整个数组,因此传的是数组的长度

value : 查找的对象

具体思路就是:

先找到数组的0和最后一个下标的值,然后算出中间值

判断算出的中间值是否与value值相等,如果成立说明找到,则返回下标

如果中间值小于value,则将中间值+1重新置为hi值,再计算出新的mid值,重新执行步骤2

如果大于value,则将中间值-1重新置为low值,再计算出新的mid值,重新执行步骤2

如果循环执行完之后还是没有找到,则将low取反并返回

以上有计算机基础的应该都能想到,具体就不详说了, 此处想指出的是谷歌工程师写代码的习惯:

第7行计算中间值时并不是使用XXX / 2,而是使用 >>>向右移一位 吊!

第18行返回lo取反值,为什么要这么做呢?

举个很简单的例子,如下数字:

int[] arr = new int[]{1, 4, 8, 10, 15};


如果按照上述二分查找的方法查找20,则最后返回的是 -5. -5这个数很有意思,设想一下如果我们想往arr中新加一个元素,并且以升序的方式添加,那下一个被添加的元素下标正好是 5 !! 对的,我们只需要判断一下二分查找返回的值是否小于0, 如果小于0,则说明在arr中并没有找到20,因此我们只需要将20放置在返回值取反的位置即可,这样arr始终都是以升序的方式排列的。如果我们设想的没有错,那SparseArray存储方式应该与我们想的一致,如下代码:

/**
* 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) {
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++;
}
}


Bingo,果然如我们所料!!

注意:SparseArray时间与空间的取舍!

根据上一章的描述可以知道,SparseArray插入一个值时,首先找到要插入的下标,保证数组有序,这样就需要移动里面的元素,插入时key和value都要移动一次,时间复杂度是O(N),但是HashMap不需要做这个操作。SparseArray主要是减少了空的占用。时间和空间的关系往往就是牺牲时间换空间,或者牺牲空间换时间
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  二分查找 SparseArra