您的位置:首页 > 其它

binary search

2015-08-03 14:59 281 查看
一.定义

二分法检索(binary search)又称折半检索,二分法检索的基本思想是设字典中的元素从小到大有序地存放在数组array)中,

首先将给定值key与字典中间位置上元素的关键码(key)比较,如果相等,则检索成功;

否则,若key小,则在字典前半部分中继续进行二分法检索;

若key大,则在字典后半部分中继续进行二分法检索。

这样,经过一次比较就缩小一半的检索区间,如此进行下去,直到检索成功或检索失败。

偶数个取中间2个其中任何一个作为中间元素

二分法检索是一种效率较高的检索方法,要求字典在顺序表中按关键码排序。

二.应用

There are two sorted arrays nums1 and nums2 of
size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

针对这个问题,可以考虑对数组1和数组2分别进行一次切割,但是要保证数组1和数组2切割后左边元素之和等于右边元素之和,这样才可以保证最后我们求得的是median。

为了更好的切割,需解决以下问题:

1.数组个数为奇数和偶数的问题:

偶数的话很好理解,以A[]={1,2,3,4}为例,切割为A={1,2/3,4},其中切割左边L=2,右边R=3;

奇数的话,可以这样理解,A={1,2,3},切割为A={1,2/2,3},其中切割左边为L=2,右边R=2;

共有的特征是:L=A[(N-1)/2],R=A[N/2]。

2.保证数组1和数组2切割后左边元素之和等于右边元素之和的问题:

由于切割可以选在数组的最开始和最末尾,为了分析方便,我们可以将数组进行扩展。

A[]={1,2,3,4}扩展为A[]={#1#2#3#4#},其中N1=4,Npos1=4*2+1=9。

B[]={2,3,5}扩展成B[]={#2#3#5#},其中N2=3,Npos2=7。

所以总共有2*N1+2*N2+2,如果进行切割,两个切割占2个位置,剩下2*N1+2*N2个位置,左右相等的话,左右各有N1+N2个位置。

如果我们选择B的切割位置在C2=2(0 based),切割后为:B[]={#2/3#5#},那么A的切割位置就在C1=N1+N1-C2处,即C1=5。

那么A进行切割后为:A[]={#1#2#3/3#4#}
4000
,可以看到分割后左边和为7(算上#,不算切割位置),右边和为7,。

切割完成后,找出满足要求的切割,这就需要用到二分法检索。用二分法检索前,思考下面问题:

1.如果L1>R2,说明数组1左边大的元素比较多,数组1的切割需要往左边移动,相应的数组2的切割就会往右边移动。

2.如果L2>R1,说明数组2左边大的元素比较多,数组2的切割需要往左边移动,相应的数组1的切割就会往右边移动。

3.如果L1<=R2与L2<=R1(注:由于数组已排序,故不需要考虑L1<R1,L2<R2),说明两个切割位置都是合理的,返回值为:

return double(max(L1,L2)+min(R1,R2))/2;

算法复杂度为o(log(min(m,n)))。

double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int N1 = nums1.size();
int N2 = nums2.size();
if (N1 < N2) return findMedianSortedArrays(nums2, nums1);   // Make sure A2 is the shorter one.

if (N2 == 0) return ((double)nums1[(N1-1)/2] + (double)nums1[N1/2])/2;  // If A2 is empty

int lo = 0, hi = N2 * 2;
while (lo <= hi) {
int mid2 = (lo + hi) / 2;   // Try Cut 2
int mid1 = N1 + N2 - mid2;  // Calculate Cut 1 accordingly

double L1 = (mid1 == 0) ? INT_MIN : nums1[(mid1-1)/2];  // Get L1, R1, L2, R2 respectively
double L2 = (mid2 == 0) ? INT_MIN : nums2[(mid2-1)/2];
double R1 = (mid1 == N1 * 2) ? INT_MAX : nums1[(mid1)/2];
double R2 = (mid2 == N2 * 2) ? INT_MAX : nums2[(mid2)/2];

if (L1 > R2) lo = mid2 + 1;     // A1's lower half is too big; need to move C1 left (C2 right)
else if (L2 > R1) hi = mid2 - 1;    // A2's lower half too big; need to move C2 left.
else return (max(L1,L2) + min(R1, R2)) / 2; // Otherwise, that's the right cut.
}
return -1;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: