折半查找应该算是算法中比较简单常见,但却很实用的方法之一了,又叫做二分搜索,其应用比较广泛,可以用于排序数组中元素的查找,复杂度仅为log(N),也可以用于有序数组中插入元素等等,一般而言针对排序数组的一些算法都会活多或少的用到折半查找活折半查找的思想,折半查找的实现主要分为两种方式,一种是遍历非递归形式,一种是采用递归的形式。
1、非递归形式,这种实现主要是通过每次调整中点的位置来实现。
int binsearch1(int arr[], int k, int l, int h){
if(l > h){
return -1;
}
int mid;
while(l <= h){
mid = (l + h) / 2;
if(k == arr[mid]){
return mid;
}else if(k > arr[mid]){
l = mid + 1;
}else{
h = mid - 1;
}
}
return -1;
}
2、递归的形式,这种形式比较简单,调整起点,中点,终点的位置,递归函数就可以实现
int binsearch2(int arr[], int k, int l, int h){
if(l > h){
return -1;
}
int mid = (l + h) / 2;
if(k == arr[mid]){
return mid;
}else if(k > arr[mid]){
binsearch2(arr, k, mid +1, h);
}else if(k < arr[mid]){
binsearch2(arr, k, l, mid - 1);
}
return -1;
}
二、现在考虑复杂一点的二分搜索的问题,当我们遇到这样的数 组a={1, 2, 3, 3, 5, 7, 8},存在重复的元素,需要从中找出3第一次出现的位置,这里3第一次出现的位置是2,《编程珠玑》里给出了很好的分析,二分搜索主要的精髓在于不变式的设计(就是上面的while循环条件式)。
int binsearch_first(int arr[], int k, int n){
int l = -1, h = n;
while(l + 1 != h){
int m = (l + h) / 2;
if(k > arr[m]){
l = m;
}else{
h = m;
}
}
int p = h;
if(p >= n || arr[p] != k){
return -1;
}
return h;
}
int binsearch_last(int arr[], int k, int n){
int l = -1, h = n;
while(l + 1 != h){
int m = (l + h) / 2;
if(k >= arr[m]){
l = m;
}else{
h = m;
}
}
int p = l;
if(p <= -1 || arr[p] != k){
return -1;
}
return p;
}
int split(int a[], int n)
{
for (int i=0; i
还有另外一种方法就是还按照一次二分查找的形式进行,可以这样考虑计算数组中点的时候,会将数组分为两个部分,一部分是有序的,或者两部分有序的,总之必然有一遍是有序的,那么就又可以按照二分的思想进行求解。
二分查找算法有两个关键点:1)数组有序;2)根据当前区间的中间元素与x的大小关系,确定下次二分查找在前半段区间还是后半段区间进行。
仔细分析该问题,可以发现,每次根据low和high求出mid后,mid左边([low, mid])和右边([mid, high])至少一个是有序的。
a[mid]分别与a[left]和a[right]比较,确定哪一段是有序的。
如果左边是有序的,若xa[left], 则right=mid-1;其他情况,left =mid+1;