zoukankan      html  css  js  c++  java
  • 基础算法介绍 —— 二分查找算法

        不知不觉在目前的公司待满3年了,打算回家找份工作。面试中被问到关于算法的题目:有哪些常见的查找算法?下来就把我所掌握的查找算法分享给大家,本文主要介绍二分查找算法。

        算法定义(摘自百度):二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入删除困难。因此,折半查找方法适用于不经常变动而查找频繁的有序列表。首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。

        上述定义可以看到这种二分查找算法是基于一个有序序列的算法,因此仅适用于已经排好顺序的情况下使用,否则需要先对序列进行排序。

        下面用Java代码来描述两种形式的二分查找算法:

         一、递归二分查找算法

     1 package algorithm;
     2 
     3 /**
     4  * 题目: 现有一个int型数组,其元素顺序排列。现给出一个数字,返回其在数组中的下标,如不存在返回-1.
     5  *
     6  */
     7 public class BinarySearch {
     8 
     9     // 用来记录查找次数
    10     private static int count = 0;
    11 
    12     /**
    13      * 
    14      * @param number
    15      *            待查找数字
    16      * @param array
    17      *            待查找数组
    18      * @return 数组下标或-1
    19      */
    20     public static int getIndex(int number, int[] array) {
    21         count = 0;
    22         if (array == null || array.length == 0) { // 如果数组对象为空或者数组元素个数为0,直接返回-1
    23             count++;
    24             return -1;
    25         }
    26         return binarySearch(0, array.length - 1, array, number); // 调用递归方法
    27     }
    28 
    29     /**
    30      * 
    31      * @param startIndex
    32      *            起始下标
    33      * @param endIndex
    34      *            结束下标
    35      * @param array
    36      *            数组
    37      * @param number
    38      *            待查找数字
    39      * @return 数组下标或-1
    40      */
    41     private static int binarySearch(int startIndex, int endIndex, int[] array, int number) {
    42         count++;
    43         // startIndex大于endIndex,说明已查找完成但并未查找到number
    44         if (startIndex > endIndex) {
    45             return -1;
    46         }
    47         // 获取中间元素下标
    48         int index = (startIndex + endIndex) / 2;
    49         // 获取中间元素数值
    50         int _number = array[index];
    51         // 比较中间元素与待查找数字
    52         if (_number < number) {
    53             // 如果中间元素数值小与待查找数字,则将查找范围缩小至 起始下标+1~中间元素下标
    54             return binarySearch(index + 1, endIndex, array, number);
    55         } else if (_number > number) {
    56             // 如果中间元素数值大与待查找数字,则将查找范围缩小至 中间元素下标~中间元素下标-1
    57             return binarySearch(startIndex, index - 1, array, number);
    58         }
    59         return index;
    60     }
    61 
    62     public static int getCount() {
    63         return count;
    64     }
    65 
    66 }

        二、非递归二分查找算法:

     1 package algorithm;
     2 
     3 public class BinarySearchNonRecursive {
     4 
     5     // 记录循环次数
     6     private static int count = 0;
     7 
     8     public static int getIndex(int number, int[] array) {
     9 
    10         // 判断数组是否为空,判断数组长度
    11         if (array == null || array.length == 0) {
    12             return -1;
    13         }
    14 
    15         // 初始化起始下标、结束下标、返回值
    16         int startIndex = 0;
    17         int endIndex = array.length - 1;
    18 
    19         while (startIndex <= endIndex) {
    20             count++;
    21             int middleIndex = (startIndex + endIndex) / 2;
    22             int _number = array[middleIndex];
    23 
    24             if (_number < number) {
    25                 // _number小于number,下次循环查找的起始下标为middleIndex + 1;
    26                 startIndex = middleIndex + 1;
    27             } else if (_number > number) {
    28                 // _number大于number,下次循环查找的结束下标为middleIndex - 1;
    29                 endIndex = middleIndex - 1;
    30             } else {
    31                 // _number等于number,查找到数字,返回结果
    32                 return middleIndex;
    33             }
    34         }
    35 
    36         // 当startIndex > endIndex时,说明未查找到数字。结束循环,返回-1
    37         return -1;
    38 
    39     }
    40 
    41     public static int getCount() {
    42         return count;
    43     }
    44 
    45 }

        下面是测试代码:

     1 package algorithm;
     2 
     3 import org.junit.Before;
     4 import org.junit.Test;
     5 
     6 public class BinarySearchTest {
     7 
     8     private int[] array;
     9     private int[] testArray;
    10 
    11     @Before
    12     public void setUp() throws Exception {
    13         array = new int[] { 1, 2, 3, 9, 15, 26, 37, 48, 69, 110, 116, 117, 244, 374, 529 };
    14         testArray = new int[] { 1, 5, 3, 9, 37, 48, 22, 69, 244, 529, -888 };
    15     }
    16 
    17     @Test
    18     public void test() {
    19 
    20         System.out.println("====递归二分查找算法====");
    21         for (int i = 0; i < testArray.length; i++) {
    22             System.out.println("测试数值为 : " + testArray[i]);
    23 
    24             int result = BinarySearch.getIndex(testArray[i], array);
    25 
    26             System.out.println("查找结果为 : " + result);
    27             System.out.println("查询次数 : " + BinarySearch.getCount() + "
    ");
    28 
    29         }
    30         System.out.println("
    ====非递归二分查找算法====");
    31         for (int i = 0; i < testArray.length; i++) {
    32             System.out.println("测试数值为 : " + testArray[i]);
    33 
    34             int result = BinarySearchNonRecursive.getIndex(testArray[i], array);
    35 
    36             System.out.println("查找结果为 : " + result);
    37             System.out.println("循环次数 : " + BinarySearchNonRecursive.getCount() + "
    ");
    38 
    39         }
    40 
    41     }
    42 
    43 }

        输出测试结果:

    ====递归二分查找算法====
    测试数值为 : 1
    查找结果为 : 0
    查询次数 : 4
    
    测试数值为 : 5
    查找结果为 : -1
    查询次数 : 5
    
    测试数值为 : 3
    查找结果为 : 2
    查询次数 : 4
    
    测试数值为 : 9
    查找结果为 : 3
    查询次数 : 2
    
    测试数值为 : 37
    查找结果为 : 6
    查询次数 : 4
    
    测试数值为 : 48
    查找结果为 : 7
    查询次数 : 1
    
    测试数值为 : 22
    查找结果为 : -1
    查询次数 : 5
    
    测试数值为 : 69
    查找结果为 : 8
    查询次数 : 4
    
    测试数值为 : 244
    查找结果为 : 12
    查询次数 : 4
    
    测试数值为 : 529
    查找结果为 : 14
    查询次数 : 4
    
    测试数值为 : -888
    查找结果为 : -1
    查询次数 : 5
    
    
    ====非递归二分查找算法====
    测试数值为 : 1
    查找结果为 : 0
    循环次数 : 4
    
    测试数值为 : 5
    查找结果为 : -1
    循环次数 : 4
    
    测试数值为 : 3
    查找结果为 : 2
    循环次数 : 4
    
    测试数值为 : 9
    查找结果为 : 3
    循环次数 : 2
    
    测试数值为 : 37
    查找结果为 : 6
    循环次数 : 4
    
    测试数值为 : 48
    查找结果为 : 7
    循环次数 : 1
    
    测试数值为 : 22
    查找结果为 : -1
    循环次数 : 4
    
    测试数值为 : 69
    查找结果为 : 8
    循环次数 : 4
    
    测试数值为 : 244
    查找结果为 : 12
    循环次数 : 4
    
    测试数值为 : 529
    查找结果为 : 14
    循环次数 : 4
    
    测试数值为 : -888
    查找结果为 : -1
    循环次数 : 4

        从console内容可以看出,两种不同形式二分查找算法的结果是相同的。

        注:一些情况下同样的测试数据,递归二分查找和非递归二分查找的执行次数不一致,这是因为在非递归二分查找算法中,当startIndex>endIndex时,没有进入while语句中,count没有自增;而在递归二分查找算法中,startIndex>endIndex作为一个结束条件,是在递归函数内部判断的,因此记录调用递归函数次数的count自增。这里笔者没有对执行count++的位置进行特殊处理,是为了更好的体现出两种形式的算法的执行步骤。

        总结:两种形式的二分查找算法本质思想都是一样的,即每次将查找数据与中间元素对比大小,未匹配则缩小二分之一的查找范围,直到最终查找到元素或返回未查找到结果。

        最后,希望本文能帮助到有需要的朋友,同时也欢迎大家批评指正文中的不足之处。

  • 相关阅读:
    linux I2C 读写 tlv320dac3100
    ubuntu lfs
    安装和使用花生壳(linux)
    vim 配置
    vim
    gnome2 恢复默认 panel
    ubuntu 挂在 jffs2 文件
    gstreamer 播放
    gstreamer 环境变亮设置
    探讨【IGE】的源代码【五】。
  • 原文地址:https://www.cnblogs.com/zfLee/p/5654296.html
Copyright © 2011-2022 走看看