二分查找算法

算法概述

  当数据量很大时适宜采用二分法查找,其是一种效率较高的查找方法,但前提条件是要查找的集合必须是有序的,或是升序排列或是降序排列都可以。二分法又称折半查找,故名思意就是就是从中间开始比较查找,其基本思路是:假设数据是按升序排序的,对于给定值 x,从序列的中间位置开始比较,如果当前位置值等于 x,则查找成功;若 x 小于当前位置值,则在数列的前半段中查找;若 x 大于当前位置值则在数列的后半段中继续查找,直到找到为止。所以二分法查找的速度比较快,次数比较少,性能比较好;因此相对来说其删除和插入操作就不是那么灵活了。

二分查找的优点和缺点

  虽然二分查找的效率高,但是要将表按关键字排序。而排序本身是一种很费时的运算。既使采用高效率的排序方法也要花费O(nlgn)的时间。
  二分查找只适用顺序存储结构。为保持表的有序性,在顺序结构里插入和删除都必须移动大量的结点。因此,二分查找特别适用于那种一经建立就很少改动、而又经常需要查找的线性表。
  对那些查找少而又经常需要改动的线性表,可采用链表作存储结构,进行顺序查找。链表上无法实现二分查找。

二分查找算法的效率(性能)

1000个数据,约10次找出, 100万个数据,约20次找出 10亿个数据,约30次找出 40亿个数据,约32次找出 2^n个数据,约n次找到

算法具体实现

比如有一组数,用二分法查找某个数。
1,3,11,18,19,22,25,33,34,38,44,55,56,58,60,63,66,70,77,87,90,91,92,95,97

下面PHP代码使用递归方式实现二分法查找:

<?php $a = array(1,3,11,18,19,22,25,33,34,38,44,55,56,58,60,63,66,70,77,87,90,91,92,95,97); $search1 = 33; //要查找的数据 $search2 = 59; $len = count($a); //从数组$arr中的位置$begin开始到位置$end之间找数据$target function binary_search($arr, $target, $begin, $end){ $mid = floor( ($begin + $end)/2 ); //定中间位置 $mid_value = $arr[$mid]; //取得中间项的值 if($target == $mid_value){ return true; }else if($target < $mid_value){ //目标值小于中间值 if($begin > $mid-1){ //如果开始位置都比结束位置大,表示肯定找不到了 return false; } $result = binary_search($arr, $target, $begin, $mid-1); //末尾索引,前移到$mid-1,右边不再找 }else{ //目标值大于中间值 if($mid+1 > $end){ //如果开始位置都比结束位置大,表示肯定找不到了 return false; } $result = binary_search($arr, $target, $mid+1, $end); //前端索引,后移到$mid+1,左边不再找 } return $result; } //使用binary_search()函数从 $a 中的 0 到 len-1 位置找 $search $v1 = binary_search($a, $search1, 0, $len-1); $v2 = binary_search($a, $search2, 0, $len-1); echo "search1的结果为:";var_dump($v1); echo "search2的结果为:";var_dump($v2); ?>

运行结果为:

search1的结果为:

boolean true

search2的结果为:

boolean false

使用非递归实现二分法

// 非递归算法
function binary_search(arr, key) {
    var low = 0,
        high = arr.length - 1;
    while(low <= high){
        var mid = parseInt((high + low) / 2);
        if(key == arr[mid]){
            return  mid;
        }else if(key > arr[mid]){
            low = mid + 1;
        }else if(key < arr[mid]){
            high = mid -1;
        }else{
            return -1;
        }
    }
};
var arr = [1,2,3,4,5,6,7,8,9,10,11,23,44,86];
var result = binary_search(arr,10);
alert(result); // 9 返回目标元素的索引值 

Java代码

使用递归实现二分法查找

class Program
   {
       static void Main(string[] args)
       {
           int[] ary = new int[] {1,3,4,6,11,20,24};
           int result = Find(ary,6);
           Console.WriteLine(result);
        }
       private static int Find(int []ary,int target)
       {
           int startIndex = 0;
           int endIndex = ary.Length - 1;
           int targetIndex = -1;
           //判断初始索引与结束索引的大小,若初始索引大于结束索引则说明数组中没有要查找的数
           //并且返回-1 
           while (true)
          {
               //求中值索引
               int MiddleIndex = (startIndex + endIndex) / 2;
               //定义中值并初始化为数组中索引为中值索引位置的上数
               int Middle = ary[MiddleIndex];
               //如果初始索引大于等于结束索引就立刻结束程序
               if (startIndex > endIndex)
               {
                   break;
               }
               //判断目标与中值的大小,如果目标等于中值,并得到索引为middleindex位置上的数后返回该索引
               if (target == Middle)
               {
                   targetIndex = MiddleIndex;

                   break;
               }
               //如果目标小于中值,那么一定意味着中值(包含中值)以后的数都比目标大,故缩小查找范围
               //将结束索引变为种植索引-1
               else if (target < Middle)
               {
                   endIndex = MiddleIndex - 1;
               }
               //如果目标大于中值,那么一定意味着中值(包含中值)以前的数都比目标大,故缩小查找范围
               //将初始索引变为种植索引+1
               else
               {
                   startIndex = MiddleIndex + 1;
               }
           }
           return targetIndex;
       }

使用循环语句实现二分法查找

class Program
   {
       static void Main(string[] args)
       {
           int[] ary = new int[] {1,3,4,6,11,20,24};
           int result = Find(ary,6);
           Console.WriteLine(result);
        }
       private static int Find(int []ary,int target)
       {
           int startIndex = 0;
           int endIndex = ary.Length - 1;
           int targetIndex = -1;
           //判断初始索引与结束索引的大小,若初始索引大于结束索引则说明数组中没有要查找的数
           //并且返回-1 
           while (true)
          {
               //求中值索引
               int MiddleIndex = (startIndex + endIndex) / 2;
               //定义中值并初始化为数组中索引为中值索引位置的上数
               int Middle = ary[MiddleIndex];
               //如果初始索引大于等于结束索引就立刻结束程序
               if (startIndex > endIndex)
               {
                   break;
               }
               //判断目标与中值的大小,如果目标等于中值,并得到索引为middleindex位置上的数后返回该索引
               if (target == Middle)
               {
                   targetIndex = MiddleIndex;

                   break;
               }
               //如果目标小于中值,那么一定意味着中值(包含中值)以后的数都比目标大,故缩小查找范围
               //将结束索引变为种植索引-1
               else if (target < Middle)
               {
                   endIndex = MiddleIndex - 1;
               }
               //如果目标大于中值,那么一定意味着中值(包含中值)以前的数都比目标大,故缩小查找范围
               //将初始索引变为种植索引+1
               else
               {
                   startIndex = MiddleIndex + 1;
               }
           }
           return targetIndex;
       }
    原文作者:查找算法
    原文地址: https://blog.csdn.net/yeoman92/article/details/52717001
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞