题目:假定有n个不同的整数n>=1,且它们
已经排序并存放在数组list中(这个是前提),要求判定某个整数searchnum是否在数组中,如果在,则返回下标i,使得list[i] = searchnum。如果不在,返回-1。
解法:设两个变量left和right分别表示被查找表的左边界和右边界,初始化时,left = 0, right = n-1。令middle = (left+right) / 2为list的中间位置。如果将list[middle]与searchnum比较,则会出现以下三种情况:
1)searchnum < list[middle],此时如果searchnum在数组中,则一定在0到middle-1之间。因此,把查找右边界right设为middle-1;
2)searchnum = list[middle],此时list[middle]就是要找的值,返回middle;
3)searchnum > list[middle],此时如果searchnum在数组中,则一定在middle+1到n-1之间。因此,把查找左边界left设为middle+1;
如果没有找到searchnum,且数组中还有没检查过的数,就重新计算middle的值,并继续查找。
代码如下:
代码如下:
#include <stdio.h>
#define N 10
#define COMPARE(x, y) (((x) < (y)) ? -1: ((x) == (y)) ? 0: 1) // 比较两个数的逻辑关系
int binSearch(int [], int, int, int);
int main(void)
{
int i, n;
int list[N] = {1, 1, 2, 3, 5, 8, 13, 21, 34, 55}; //已排好序的数组
printf("Enter you want searchnum: ");
scanf("%d", &n);
int left = 0, right = N-1;
int tmp = binSearch(list, n, left, right);
if(tmp == -1)
printf("Not find %d in list[]\n", n);
else
printf("list[%d]\n", tmp);
return 0;
}
int binSearch(int list[], int searchnum, int left, int right)
{
int middle;
while (left <= right)
{
middle = (left+right)/2;
switch(COMPARE(list[middle], searchnum)) // 调用宏来比较两个数大小,并返回结果
{
case -1: left = middle + 1; // -1 表示中间数比要查找的数小
break;
case 0: return middle; // 0 表示中间数和要查找的数这两个数相等
case 1: right = middle - 1; // 1 表示中间数比要查找的数大
}
}
return -1;
}
下面介绍二分查找的递归方法。通常认为递归只有在一些特定的问题上才会使用,比如计算阶乘或Ackermann 函数。这是很狭隘的认识。实际上,任何用赋值语句、if-else或while结构的函数都可用递归方式重写。通常,用递归函数要比其相应的迭代函数更容易理解。
如果确定在什么时候应该使用递归表述算法呢?一种情况是问题本身是递归定义的,阶乘和斐波那契数问题都属于这种情况。同样,二项式系数问题也属于此类。
为了把二分查找的迭代函数转换为一个递归函数,必须:
1)构造递归调用终止的边界条件;
2)实现递归调用,使得每次递归调用都能够向最终解逼近一步(要么查找成功,要么查找失败)。当函数查找成功结束时,不需要修改代码,对于查找失败,需要将其while语句替换为造价的if语句,并在其then语句中进行递归调用。
1)构造递归调用终止的边界条件;
2)实现递归调用,使得每次递归调用都能够向最终解逼近一步(要么查找成功,要么查找失败)。当函数查找成功结束时,不需要修改代码,对于查找失败,需要将其while语句替换为造价的if语句,并在其then语句中进行递归调用。
创建一个逐步逼近解的递归调用是很简单的,只需将新的left和right作为参数传递给下一次递归调用函数中即可。
递归代码:
#include <stdio.h>
#define COMPARE(x, y) (((x) < (y)) ? -1: ((x) == (y)) ? 0: 1)
#define N 10
int binSearchOfRecursion(int [], int, int, int);
int main(void)
{
int n;
int list[N] = {1, 1, 2, 3, 5, 8, 13, 21, 34, 55};
printf("Enter you want searchunm: ");
scanf("%d", &n);
int left = 0, right = N-1;
int tmp = binSearchOfRecursion(list, n, left, right);
if (tmp == -1)
printf("Not find %d in list[]\n", n);
else
printf("list[%d] \n", tmp);
return 0;
}
int binSearchOfRecursion(int list[], int searchnum, int left, int right)
{
int middle;
if (left <= right)
{
middle = (left+right)/2;
switch(COMPARE(list[middle], searchnum))
{
case -1: return binSearchOfRecursion(list, searchnum, middle+1, right);
case 0: return middle;
case 1: return binSearchOfRecursion(list, searchnum, left, middle-1);
}
}
return -1;
}
以上问题参考《Fundamentals of Data Structures in C》