* 二分搜索
* b表示超始位置
* e表示结束位置
* 搜索范围[b, e)
* v表示要找的值
* 返回元素指针位置,如果没有找到,返回NULL
* pos指向刚好比v大的位置条件是: 如果: notFound(v) && 且 *b < *v && *v < *(e-1)
*/
int *binarySearch(int *b, int *e, int *v, int **less) {
int *m = *less = NULL;
while (b < e) {
m = b + ((e-b) >> 1);
if (*m == *v) return m;
if (*m > *v) e = m;
else b = m + 1;
}
while (*m < *v && m < e) ++m;
*less = m;
return NULL;
}
int findKthItem(int *a, int *ae, int *b, int *be, int k) {
* 如果b数组长于a数组,交换之
* 取长数组的中值在短数组的中二分查找,速度更快
*/
if ((be-b) > (ae-a)) {
return findKthItem(b, be, a, ae, k);
}
assert(0 < k && k <= ((ae-a) + (be-b)));
assert(((ae-a) + (be-b)) > 0);
if (b == be) {
return a[k-1];
}
if (a == ae) {
return b[k-1];
}
if (1 == k) {
return a[0] < b[0] ? a[0] : b[0];
}
if (k == ((ae-a) + (be-b))) {
return *(ae-1) > *(be-1) ? *(ae-1) : *(be-1);
}
int *amid = a + ((ae - a)>>1);
int *less = NULL;
int *pos = binarySearch(b, be, amid, &less);
* 如果amid不存在于B数组中,但是范围落在里面,照样可以把
* B数组切成两半,这个时候的处理情况与找到的处理是一样的
* 都是把两个数组切分成了2份。
*/
if (less && (*b < *amid && *amid < b[be-b-1])) {
pos = less;
}
* 如果找到A数组的中间元素, 或者
* pos可以把数组B成功切分成为两半:看pos = less
*/
if (pos) {
* 这个时候数组被切分为两部分
* 数组A [a, amid), [amid, ae)
* 数组B [b, pos), [pos, be)
* 看一下k所在的范围
*/
int frontLength = (amid-a) + (pos-b);
if (frontLength == k) {
* 相等:
* 元素个数刚好与k相等, 只需要取最后一个元素
*/
int aLast = amid - a - 1;
int bLast = pos - b - 1;
return a[aLast] > b[bLast] ? a[aLast] : b[bLast];
} else if (frontLength > k) {
return findKthItem(a, amid, b, pos, k);
} else {
return findKthItem(amid, ae, pos, be, k - frontLength);
}
assert(1 == 0);
} else {
* 找不到,可能有三种情况,
* 1. 比数组B所有元素小
* 2. 比数组B所有元素大
* 3. 介于数组B之间
*/
if (*amid < *b) {
* 情况1:amid < b数组中所有元素
* [a, amid), [amid, ae)
* [b, be)
*/
int frontLength = amid - a;
if (frontLength == k) {
int aLast = amid - a - 1;
return a[aLast];
} else if (frontLength > k) {
return a[k-1];
} else {
return findKthItem(amid, ae, b, be, k - frontLength);
}
assert(1 == 0);
} else if (*amid > b[be-b-1]) {
* 情况2: amid > b数组中所有元素
* [a, amid), [amid, ae)
* [b, be)
*/
assert(*amid > b[be-b-1]);
int frontLength = amid - a + be - b;
if (frontLength == k) {
int aLast = amid - a - 1;
int bLast = be - b - 1;
return a[aLast] > b[bLast] ? a[aLast] : b[bLast];
} else if (frontLength > k) {
return findKthItem(a, amid, b, be, k);
} else {
return amid[k - frontLength - 1];
}
assert(1 == 0);
} else {
* amid 落在B组数区间中,但是不存在
* 数组被切分为[a, amid), [amid, ae)
* [b, less), [less, be)
* 这种情况与找到的情况是一样的处理方法,前面已经pos = less
*/
assert(1 == 0);
}
assert(1 == 0);
}
assert(1 == 0);
}