二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。
基本思路: 首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
简单来说: 就是递归的把序列分成前后两部分进行查找。
举例:
有一序列1, 8, 10, 89, 1000,1234要求查找序列中是否含有89
时间: 二分查找要递归的进行折半,所以根据折半的递归树可得二分查找的时间复杂度为O( l o g 2 n {log_2{n}} log2n)。
空间: 二分查找是在原序列上进行递归折半,无需额外开辟空间,所以空间复杂度为O(1)。
算法 | 平均时间 | 最好情形 | 最差情形 | 空间复杂度 | 备注 |
---|---|---|---|---|---|
二分查找 | O( l o g 2 n {log_2{n}} log2n) | O( l o g 2 n {log_2{n}} log2n) | O( l o g 2 n {log_2{n}} log2n) | O(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
测试结果: