1.初次相识
二分查找又称折半查找,是一种在有序数组中查找特定元素的算法。二分查找的基本思想是:通过不断地二分数组的中间元素,缩小查找区间,直到找到目标元素或者确定目标元素不存在为止。
二分查找的时间复杂度为O(logn),比线性查找的时间复杂度O(n)要小很多,但是二分查找的前提是必须在有序数组中进行。
2.思想分析
- 1.确定该数组的中间下标 middle=(left+right)/2
- 2.需要查找的数index和array【middle】比较
- 2.1 index > array【middle】,说明要查找的数在middle的右边,递归向右查找
- 2.2 index < array【middle】,说明要查找的数在 middle的左边,递归向左查找
- 2.3 index == array【middle】,说明找到,返回
- 什么时候递归结束??
- 1.找到就结束
- 2.递归完整个数组,未找到,也许结束,条件: lift > rigtht
3.代码实现
public static int binarySearch(int[] arr, int left, int right, int index) {//直接结束递归if (left > right) {return -1;}int middle = (left + right) / 2;int middleVal = arr[middle];if (index > middleVal) {return binarySearch(arr, middle + 1, right, index);} else if (index < middleVal) {return binarySearch(arr, left, middle - 1, index);} else {return middle;}}
发现一个问题,如果有重复数字,也只能返回第一数字的下标
4.代码优化
思路:
- 1.再找到middle时,不要立马返回
- 2.向middle索引的左边扫描,将满足条件元素的下标,加入到ArrayList集合
- 3.向middle索引的右边扫描,将满足条件元素的下标,加入到ArrayList集合
- 4.将ArrayList返回
public static ArrayList<Integer> binarySearch(int[] arr, int left, int right, int index) {//直接结束递归if (left > right) {return new ArrayList<Integer>();}int middle = (left + right) / 2;int middleVal = arr[middle];if (index > middleVal) {return binarySearch(arr, middle + 1, right, index);} else if (index < middleVal) {return binarySearch(arr, left, middle - 1, index);} else {ArrayList<Integer> list = new ArrayList<>();int temp = middle - 1;//向左边查找的第一个元素while (true) {if (temp < 0 || arr[temp] != middleVal) {//退出条件break;}list.add(temp);//找到,放进集合temp--;//temp左移}list.add(middle);//中间的放进去temp = middle + 1;while (true) {if (temp > arr.length - 1 || arr[temp] != middleVal) {break;}list.add(temp);temp++;}return list;}}
5.测试一把
public static void main(String[] args) {int[] array = new int[]{1, 2, 3, 4, 5, 6, 6};Scanner scanner = new Scanner(System.in);System.out.println("请输入你要查找的数字:");int num = scanner.nextInt();ArrayList<Integer> lists = binarySearch(array, 0, array.length - 1, num);System.out.println("你查找的数字:" + num + ",下标:" + lists);}