二分查找的递归和非递归算法(C语言实现)

二分查找的用途

二分查找又称折半查找,它用来解决“在一堆数中找出指定的数(也可能找了,发现没有)”这类问题。

二分查找的应用条件

要应用二分查找,这“一堆数”必须有以下特征:

  1. 存储在数组中
  2. 有序排列

所以,如果数是用链表存储的,那就无法在其上应用二分查找。
至于是升序排列还是降序排列、数组中是否存在相同的元素都不要紧。在本文的实验中,我们使数组递增排列,且数组中的元素互不相同。

二分查找的算法描述

在算法思想上,二分查找属于减治法。
假设含有n个元素的数组(下标从[0][n-1])中的元素已经按照升序排列。首先比较查找键值K和数组中间位置元素a[mid],如果它们相等,算法结束。否则,如果K<a[mid],则对数组前半部分(a[0]~a[mid-1])执行该操作;如果K>a[mid],则对数组的后半部分(a[mid+1]~a[n-1])执行该操作。

C语言实现

先贴出核心代码,在本文的最后会贴出包含注释的完整代码。

非递归解法

int binary_search(const int b[], int search_key, int low, int high)
{

   while (low <= high) {    
      int mid = (low + high) / 2;

      if (search_key == b[mid]) {                       
         return mid; //找到后返回下标                                       
      }  
      else if (search_key < b[mid]) {                    
         high = mid - 1;   
      }                                        
      else {                                                     
         low = mid + 1;       
      }                                            
   } 

   return -1; //没有找到
} 

要点分析:

  • while (low <= high)表示不断循环,直到lowhigh大。当low>high时表示查找区间为空,此时返回-1,表示没有找到。
  • int mid = (low + high) / 2;这句话可能会导致整数溢出,更好的写法是int mid = low + (high - low) / 2;

递归解法

int binary_search_recursive(const int b[], int search_key, int low, int high)  
{  
    if (low > high)  
        return -1;  

    int mid = low + (high - low) / 2;  //防止溢出

    if (search_key == b[mid])  
        return mid;     
    else if (search_key < b[mid])  
        return binary_search_recursive(b, search_key, low, mid - 1);    
    else  
        return binary_search_recursive(b, search_key, mid + 1, high);  
}  

完整代码及测试结果

【操作系统】: Ubuntu 14.04.3
【编译器】:gcc 4.8.4

#include <stdio.h>
#define SIZE 15

// function prototypes
void print_header(void);
void print_row(const int b[], int low, int mid, int high);
int binary_search(const int b[], int search_key, int low, int high);
int binary_search_recursive(const int b[], int search_key, int low, int high);  


int main(void)
{
    int a[SIZE]; // create array a

   // create data
    for (int i = 0; i < SIZE; ++i) {
        a[i] = 2 * i;
    }    

    printf("%s %d: ", "Enter a number between 0 and",a[SIZE-1]);
    int key; // value to locate in array a
    scanf("%d", &key);

    puts("\nNon-recursive solution");
#ifdef SHOW_PROCEDURE
    print_header(); //打印出查找的过程
#endif
    // Non-recursive solution

    int result = binary_search(a, key, 0, SIZE - 1);

    // display results
    (result == -1) ? printf("\n%d not found\n", key) : \
    printf("\n%d found at index %d\n", key, result);

    puts("\nRecursive solution");
#ifdef SHOW_PROCEDURE
    print_header();
#endif
    // Recursive solution
    result = binary_search_recursive(a, key, 0, SIZE - 1);

    // display results
    (result == -1) ? printf("\n%d not found\n", key) : \
    printf("\n%d found at index %d\n", key, result);

}

// function to perform binary search of an array
int binary_search(const int b[], int search_key, int low, int high)
{
   // loop until low index is greater than high index
    while (low <= high) {

        // determine mid element of subarray being searched
        int mid = (low + high) / 2;
#ifdef SHOW_PROCEDURE
        // display subarray used in this loop iteration
        print_row(b, low, mid, high);
#endif
        // if search_key matched mid element, return mid
        if (search_key == b[mid]) {                       
            return mid;                                       
        }                                           

        // if search_key is less than mid element, set new high
        else if (search_key < b[mid]) {                    
            high = mid - 1; // search low end of array      
        }                                     

        // if search_key is greater than mid element, set new low
        else {                                                     
            low = mid + 1; // search high end of array        
        }                                            
    } // end while

    return -1; // search_key not found
} 


int binary_search_recursive(const int b[], int search_key, int low, int high)  
{  
    if (low > high)  
        return -1;  

    int mid = low + (high - low) / 2;  //防止溢出

#ifdef SHOW_PROCEDURE
      // display subarray used in this loop iteration
      print_row(b, low, mid, high);
#endif

    if (search_key == b[mid])  
        return mid;  

    else if (search_key < b[mid])  
        return binary_search_recursive(b, search_key, low, mid - 1);  

    else  
        return binary_search_recursive(b, search_key, mid + 1, high);  

}  


// Print a header for the output
void print_header(void)
{
    puts("index:");

    // output column head
    for (int i = 0; i < SIZE; ++i) {
        printf("%3d ", i);
    } 

    puts(""); // start new line of output

    // output line of - characters  , 1个索引占4个“-”
    for (int i = 1; i <= 4 * SIZE; ++i) {
        printf("%s", "-");
    } 

    puts(""); // start new line of output
} 

// Print one row of output showing the current
// part of the array being processed.
void print_row(const int b[], int low, int mid, int high)
{
   // loop through entire array
    for (int i = 0; i < SIZE; ++i) {

        // display spaces if outside current subarray range
        if (i < low || i > high) {
            printf("%s", "    "); //4个空格
        }  
        else if (i == mid) { // display mid element
            printf("%3d*", b[i]); // mark mid value
        } 
        else { // display other elements in subarray
            printf("%3d ", b[i]);
        } 
    } 

    puts(""); // start new line of output
} 

编译上面的文件(假设文件名是binary_search.c

gcc binary_search.c -std=gnu99 -DSHOW_PROCEDURE

-DSHOW_PROCEDURE表示定义宏SHOW_PROCEDURE,相当于在源文件里面写#define SHOW_PROCEDURE.

main函数中生成数组的代码是:

    #define SIZE 15

    int a[SIZE]; 
    for (int i = 0; i < SIZE; ++i) {
        a[i] = 2 * i;
    }

由此可见,生成了一个以升序排列的数组——{0,2,4,6,8,...,26,28},共15个元素。

运行程序后,会让用户输入键值。*表示处于中间位置的元素a[mid]

这里写图片描述

这里写图片描述

这里写图片描述

【参考资料】
《C How to Program (8th Edition)》

  • 26
    点赞
  • 101
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值