Java查找算法之二分查找

  二分查找是一种查询效率非常高的查找算法。又称折半查找。

一、算法思想

  有序的序列,每次都是以序列的中间位置的数来与待查找的关键字进行比较,每次缩小一半的查找范围,直到匹配成功。

  一个情景:将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。

二、举例图示

  要查找的数为21。

  第一次将头指针和尾指针分别放置头尾,middle放在中间。将21与中间的56进行比较。21<56,应在左边。

  第二次将尾指针放在56得到前一位,middle放在中间。将21与中间的19进行比较。21>19,应在右边。

  第三次将头指针放在19的后一位,middle放在中间。将21与21比较,符合查找成功!

三、二分查找优缺点及使用条件

  优点是比较次数少,查找速度快,平均性能好;

  其缺点是要求待查表为有序表,且插入删除困难

  因此,折半查找方法适用于不经常变动而查找频繁的有序列表

  使用条件:查找序列是顺序结构,有序。

四、算法实现

 1 package recursion;
 2 
 3 /**
 4  * @author zsh
 5  * @company wlgzs
 6  * @create 2019-02-16 10:11
 7  * @Describe 二分查找的两种实现
 8  */
 9 public class BinarySearch {
10 
11     /**
12      * 循环实现二分查找
13      * @param arr 待查找的数组
14      * @param key 待查找的数
15      * @return key在数组中的索引位置
16      */
17     static int binary1(int[] arr,int key){
18         //头指针初始位置
19         int low = 0;
20         //尾指针初始位置
21         int high = arr.length -1;
22         //定义middle指针位置
23         int middle = 0;
24         //头尾交叉 || key大于最大值 || key小于最小值,说明未找到
25         if (low > high || key > arr[high] || key < arr[low]){
26             return -1;
27         }
28 
29         while (low <= high){
30             //防止数据溢出
31             middle = (low + high) >>> 1;
32             if (arr[middle] > key){
33                 //middle所对应的值比key大,key应该在左边区域
34                 high = middle -1;
35             }else if (arr[middle] < key){
36                 //middle所对应的值比key小,key应该在有边区域
37                 low = middle +1;
38             }else {
39                 return middle;
40             }
41 
42         }
43 
44         //最后仍然没有找到,则返回-1
45         return -1;
46     }
47 
48     /**
49      * 递归实现二分查找
50      * @param arr 待查找的数组
51      * @param low 头指针所在位置
52      * @param high 尾指针所在位置
53      * @param key 待查找的数
54      * @return key在数组中的索引位置
55      * 算法分析:
56      * 找重复:
57      * 找变化量:
58      * 找出口:头尾交叉 || key大于最大值 || key小于最小值
59      */
60     static int binary2(int[] arr,int low , int high ,int key){
61 
62         //头尾交叉 || key大于最大值 || key小于最小值,说明未找到
63         if (low > high || key > arr[high] || key < arr[low]){
64             return -1;
65         }
66         //定义middle指针位置,防止数据溢出
67         int middle = (low + high) >>> 1;
68 
69         //middle所对应的值比key大,key应该在左边区域
70         if (arr[middle] > key){
71             binary2(arr,low,middle-1,key);
72         }else if (arr[middle] < key){
73             //middle所对应的值比key小,key应该在有边区域
74             binary2(arr,low+1,high,key);
75         }else {
76             return middle;
77         }
78 
79         //最后仍然没有找到,则返回-1
80         return -1;
81     }
82 
83     public static void main(String[] args) {
84         int[] arr = new int[]{5,13,19,21,37,56,64,75,80,88,92};
85         System.out.println(binary1(arr,21));
86         System.out.println(binary1(arr,21));
87     }
88 
89 }

 五、时间复杂度和空间复杂度

  时间复杂度

    最坏的情况下两种方式时间复杂度一样:O(log2 N)

    最好情况下O(1)

  空间复杂度:算法的空间复杂度并不是计算实际占用的空间,而是计算整个算法的辅助空间单元的个数

    非递归方式

      由于辅助空间是常数级别的所以:空间复杂度是O(1);

    递归方式

       递归的次数和深度都是log2 N,每次所需要的辅助空间都是常数级别的:空间复杂度:O(log2N )

猜你喜欢

转载自www.cnblogs.com/zsh-blogs/p/10387028.html