您的位置:首页 > 其它

逻辑清晰、简单的二分查找

2014-03-05 10:43 176 查看
本文实现了以下功能,并作了简单的分析,逻辑清晰,简单,各个代码维护了一个相似的结构。

1)二分查找元素key的下标,如无 return -1

2)二分查找返回key(可能有重复)第一次出现的下标,如无return -1

3)二分查找返回key(可能有重复)最后一次出现的下标,如无return -1

4)二分查找返回刚好小于key的元素下标,如无return -1
5)二分查找返回刚好大于key的元素下标,如无return -1

测试代码来自   二分查找,你真的会吗?
#include<stdio.h>
#include<stdlib.h>

/* bisearch 寻找key下标,不存在 return -1 */
int bisearch(int *arr, int b, int e, int v)
{
int min=b,max=e,mid;
while(min<=max) {
mid = min + (max-min) /2;
if (arr[mid] == v)
return mid;
else if(arr[mid]<v)
min = mid +1;
else
max = mid -1;
}
return -1;
}

/* bisearch_min 返回key(可能有重复)第一次出现的下标,如无return -1*/
/* 分析
实际上循环过程维持[0,min-1]<v;[max+1, n-1]>=v.
在退出循环时,必然为min=max+1;如下图
a[1],a[2],a[3],....a[i-1],a[i],a[i+1],...,a

^     ^
|     |
max  min
所以循环退出后arr[min]为数组中>=v的第一个元素,判断其是否等于v即可。
但需要注意,当v大于数组中的最大值时,当退出循环时,min>e,需判断这一情况。
*/
int bisearch_min(int *arr, int b, int e, int v)
{
int min=b,max=e,mid;
while(min<=max) {
mid = min + (max-min) /2;
if (arr[mid] < v)
min = mid +1;
else
max = mid -1;
}
if (!(min > e) && (arr[min]==v))  // when arr[b]>v, max = b-1;
return min;
else
return -1;
}

/* bisearch_max 返回key(可能有重复)最后一次出现的下标,如无return -1*/
/* 分析
实际上循环过程维持[0,min-1]<=v;[max+1, n-1]>v.
在退出循环时,必然为min=max+1;如下图
a[1],a[2],a[3],....a[i-1],a[i],a[i+1],...,a

^     ^
|     |
max  min
所以循环退出后arr[max]为数组中<=v的最大元素,判断其是否等于v即可。
但需要注意,当v小于数组中的最小值时,当退出循环时,max<b,需判断这一情况。
*/
int bisearch_max(int *arr, int b, int e, int v)
{
int min=b,max=e,mid;
while(min<=max) {
mid = min + (max-min) /2;
if (arr[mid] <= v)
min = mid +1;
else
max = mid -1;
}
if (!(max < b) && (arr[max]==v))  // when arr[b]>v, max = b-1;
return max;
else
return -1;
}

/* bisearch_justsmall 返回刚好小于key的元素下标,如无return -1*/
/* 分析
实际上循环过程维持[0,min-1]<v;[max+1, n-1]>=v.
在退出循环时,必然为min=max+1;如下图
a[1],a[2],a[3],....a[i-1],a[i],a[i+1],...,a

^     ^
|     |
max   min
所以循环退出后arr[max]为数组中刚好小于v的第一个元素。
但需要注意,当v小于数组中的最小值时,当退出循环时,max<b,需判断这一情况。
*/
int bisearch_justsmall(int *arr, int b, int e, int v)
{
int min=b,max=e,mid;
while(min<=max) {
mid = min + (max-min) /2;
if (arr[mid] < v)
min = mid +1;
else
max = mid -1;
}
if (!(max < b))
return max;
else
return -1;
}

/* bisearch_justgreat 返回刚好大于key的元素下标,如无return -1 */
/* 分析
实际上循环过程维持[0,min-1]<=v;[max+1, n-1]>v.
在退出循环时,必然为min=max+1;如下图
a[1],a[2],a[3],....a[i-1],a[i],a[i+1],...,a

^     ^
|     |
max  min
所以循环退出后arr[min]为数组中刚好大于v的第一个元素。
但需要注意,当v大于数组中的最大值时,当退出循环时,min>e,需判断这一情况。
*/
int bisearch_justgreat(int *arr, int b, int e, int v)
{
int min=b,max=e,mid;
while(min<=max) {
mid = min + (max-min) /2;
if (arr[mid] <= v)
min = mid +1;
else
max = mid -1;
}
if (!(min > e))
return min;
else
return -1;
}


测试代码如下:
#define N 20  // 测试数组大小

void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}

void my_qsort(int *arr, int left, int right)
{
int i;
int temp;

if(left >= right)
return;

temp = left;
for (i= left+1; i<=right; i++) {
if (arr[i]<arr[left])
swap(&arr[++temp], &arr[i]);
}
swap(&arr[temp], &arr[left]);
my_qsort(arr, left, temp-1);
my_qsort(arr, temp+1, right);
}

void outputarr(int * arr, int len)
{
int i;
for(i = 0; i < len; ++i)
printf("%2d ", arr[i]);
printf("\n");
}

void main()
{
int testcase = 0;
int * arr = malloc(sizeof(int)*N);
int i,key;
printf("input test times:\n");
scanf("%d", &testcase);

srand(1); // 设置随机种子

while(testcase--)
{
for(i = 0; i < N; ++i)  // 随机生成数组
{
arr[i] = rand() % (N);
}
key = rand() % (N);
outputarr(arr,N);
my_qsort(arr, 0, N-1);      // 排序
outputarr(arr,N);

for(i = 0; i < N; ++i)
printf("%2d ", i);
printf("\n");

printf("binsearch:           key-%d %d\n", key, bisearch(arr,0,N-1,key));
printf("binsearch_min:       key-%d %d\n", key, bisearch_min(arr,0,N-1,key));
printf("binsearch_max:       key-%d %d\n", key, bisearch_max(arr,0,N-1,key));
printf("binsearch_justsmall: key-%d %d\n", key, bisearch_justsmall(arr,0,N-1,key));
printf("binsearch_jus
4000
tgreat: key-%d %d\n", key, bisearch_justgreat(arr,0,N-1,key));
}

free(arr);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息