二分查找
在工作中,很多小伙伴应该会遇到这样的需求,在有序的数组中查找指定元素,比如数组 nums = [1, 3, 5, 7, 8, 11, 19, 23, 27, 33, 45, 55, 67, 98] 中查找 目标数据 8,如果找到就返回该目标数据在数组中的下标索引的位置。
算法描述
二分查找的思想也比较简单,判断数组中的中间元素和目标数据进行比较,如果相等,也就返回数组中的中间元素,如果小于中间元素的话,也就说明需要查找的元素在数组中的前半部分,如果大于中间元素的话,说明在需要查找的元素在数组中的后半部分。
以上描述的是不是有点饶头,那么我们可以通过以下的图示表示二分查找的整个过程。
算法实现while 以及 递归 实现
package com.sh.study.search;
/**
* 二分查找,查找指定数据,并返回目标数据在数据中的位置,-1 表示数组中没有指定的数据
*
* @Author zhouwenchen
* @Data 2020/8/13/15
**/
public class BinarySearch {
/**
* 二分查找 指定目标的数据
* 使用 while 循环实现
*
* @param nums
* @param target
* @return
*/
public static int binarySearch(int[] nums, int target) {
if (nums == null) {
return -1;
}
int low = 0;
int high = nums.length - 1;
while (low <= high) { // 这边注意要写成 <= ,不然的话,单个元素会匹配不成功的
int mid = (low + high) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] < target) {
low = mid + 1;
} else {
high = mid - 1; // 之前错误的写成了 high = high - 1;
}
}
return -1;
}
/**
* 使用递归实现
*
* @param nums
* @param target
* @return
*/
public static int binarySearch0(int[] nums, int start, int end, int target) {
if (nums == null || start > end) {
return -1;
}
int mid = (start + end) >> 1;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] > target) {
return binarySearch0(nums, start, mid - 1, target);
} else {
return binarySearch0(nums, mid + 1, end, target);
}
}
public static void main(String[] args) {
int[] nums = {1, 3, 5, 7, 8, 11, 19, 23, 27, 33, 45, 55, 67, 98};
int target = 27;
System.out.println("location is " + binarySearch(nums, target));
System.out.println("location is " + binarySearch0(nums, 0, nums.length - 1, target));
}
}
算法时间复杂度分析
我们每次都可以将目标数组缩短为原数组的一半,
假设目标数组的大小是n,也就是 n ,n/2,n/4…n/2^k 求和可以得到
其中 n/2k=1 时,k 的值就是总共缩小的次数
我们可以求得 k=log2n,所以时间复杂度就是 O(logn)
算法的应用场景
1:有序数组
二分查找,主要用于有序数组中查找指定的数据。所以,二分查找需要在有序的数组中查找。
换句话,如果数据是无序的 ,或者不是以数组存储的有序数据也是不特别适用的
2:数据量适中
如果数据量太少的情况,可以直接使用遍历就好了,没必要使用二分查找,
如果数据量比较大的话,也不适用,因为二分查找主要底层使用数组存储,数组需要使用一段连续的内存空间,如果数据量太大的话,内存中可能没有那么大的连续内存。基于此,那么是否有小伙伴想着说,那我们用链表存储,就不需要连续的内存空间了嘛?但是如果使用链表存储的话,那么每次遍历的时间复杂度就变成了O(n),相比于数组的查找数据的时间复杂度O(1)相比来说,不合适