二分查找

  • 一、基本思路
  • 二、算法分析
  • 三、代码实现


一、基本思路

二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。

基本思路: 首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。

简单来说: 就是递归的把序列分成前后两部分进行查找。

举例:
有一序列1, 8, 10, 89, 1000,1234要求查找序列中是否含有89

  1. 计算有序序列的mid=10,由于89>10,所以在序列89,1000,1234中查找
  2. 计算有序序列的mid=1000,由于89<1000,所以在序列89中查找
  3. 计算有序序列的mid=89,由于89=89,所以序列含有待查找的值89

二、算法分析

时间: 二分查找要递归的进行折半,所以根据折半的递归树可得二分查找的时间复杂度为O(java 折半查找方法 java实现折半查找_java)。
空间: 二分查找是在原序列上进行递归折半,无需额外开辟空间,所以空间复杂度为O(1)。

算法

平均时间

最好情形

最差情形

空间复杂度

备注

二分查找

O()

O()

O()

O(1)

待查表是有序表时才可以使用

三、代码实现

二分查找通常有递归实现以及非递归实现两种。下面将分别进行代码实现:

  1. 递归实现:这里利用二分查找给出了两个方法,一个是仅仅查找序列中是否存在指定元素,一个是将序列中所以满足条件的元素的下标都进行返回。
import java.util.ArrayList;
import java.util.List;

/**
 * 二分查找(数组必须是有序的)
 * @author dankejun
 * @create 2020-05-03 11:38
 */
public class BinarySearch {
    public static void main(String[] args) {
        int[] arr = {1, 8, 10, 89, 1000,1000,1000,1234};

        System.out.println("序列中是否含有元素:" + binarySearch(arr, 0, arr.length - 1, 1000));
        System.out.println("序列中指定元素的下标:" + binarySearch2(arr, 0, arr.length-1, 1000));

    }

    /**
     *
     * @param arr   数组
     * @param left  左边索引
     * @param right 右边索引
     * @param value 要查找的值
     * @return  如果找到就返回true,如果没有找到,就返回false
     */
    public static boolean binarySearch(int[] arr, int left, int right, int value) {
        if (left > right) {
            return false;
        }
        int mid = (left + right) / 2;
        int midVal = arr[mid];
        if (value > midVal) {//向右递归
            return binarySearch(arr, mid + 1, right, value);
        } else if (value < midVal) {//向左递归
            return binarySearch(arr, left, mid, value);
        } else {
            return true;
        }
    }

	  /**
     * 
     * @param arr 数组
     * @param left  左边索引
     * @param right 右边索引
     * @param value 要查找的值
     * @return 返回满足条件的元素的所有下标
     */
    public static List<Integer> binarySearch2(int[] arr, int left, int right, int value) {
        if (left > right) {
            return new ArrayList<Integer>();
        }
        int mid = (left + right) / 2;
        int midVal = arr[mid];
        if (value > midVal) {//向右递归
            return binarySearch2(arr, mid + 1, right, value);
        } else if (value < midVal) {//向左递归
            return binarySearch2(arr, left, mid, value);
        } else {
            List<Integer> list = new ArrayList<>();
            int temp = mid - 1;//向左边查找
            while (true) {
                if (temp < 0 || arr[temp] != value) {//未找到
                    break;
                }
                list.add(temp);
                temp -= 1;
            }
            list.add(mid);

            temp = mid + 1;//向右边查找
            while (true) {
                if (temp > arr.length - 1 || arr[temp] != value) {
                    break;
                }
                list.add(temp);
                temp += 1;
            }
            return list;
        }
    }
}

测试序列: int arr[] = {1, 8, 10, 89, 1000,1000,1000,1234};查找是否含有元素1000

测试结果:

java 折半查找方法 java实现折半查找_二分查找_05

  1. 非递归实现:
/**
 * @author dankejun
 * @create 2020/9/189:30
 */
public class BinarySearchNoRecur {
    public static void main(String[] args) {
        int[] arr = {1, 3, 8, 10, 11, 67, 100};
        int index = binarySearch(arr, 8);
        System.out.println("index=" + index);
    }


    /**
     * 二分查找的非递归实现
     * @param arr   待查找的数组,升序排列
     * @param target    待查找的目标数
     * @return  返回目标数的下标,-1表示未找到
     */
    public static int binarySearch(int[] arr, int target) {
        int left = 0;
        int right = arr.length - 1;
        while (left <= right) {//可以继续查找
            int mid = (left + right) / 2;
            if (arr[mid] == target) {
                return mid;
            } else if (arr[mid] > target) {
                right = mid - 1;//需要向左边查找
            } else {
                left = mid + 1;//需要向右边查找
            }
        }
        return -1;
    }
}

测试序列:int[] arr = {1, 3, 8, 10, 11, 67, 100},查找是否含有元素8

测试结果:

java 折半查找方法 java实现折半查找_java 折半查找方法_06