文章目录
- Java基础查找算法(2)——二分查找(折半查找)
- 1.二分查找简述
- 2.二分查找代码实现
- 2.1简介代码(无注释)
- 2.2 完整代码(含注释与运行实例)
- 3.运行实例
Java基础查找算法(2)——二分查找(折半查找)
1.二分查找简述
二分查找,又称折半查找.这个查找有个前提条件:所查数组已经有序
假设:
- 所查数组:arr
- 查询目标值:target
- 数组的最左下标 left
- 数组的最右下标 right
由上可取中间下标:mid=(left + right) / 2
可以使用递归来实现二分查找:
参数:所查数组:arr,查询目标值:target,数组的最左下标 left,数组的最右下标 right
sort(int[] arr, int left, int right, int target)
排序思路:找到数组arr中间的数(arr[mid])与目标值比较:
- 若中间值arr[mid]<目标值target,说明目标值只可能在数组右半边,递归右半边数组search(arr, mid + 1, right, target);
- 若中间值arr[mid]>目标值target,说明目标值只可能在数组左半边,递归左半边数组search(arr, left, mid - 1, target)
- 若中间值arr[mid]=目标值target,即可将下标添加到目标值下标集合中,扫描该坐标左右两边相邻数据,相等则添加到目标值下标集合中即可.
上面加粗只可能,是因为数组可能没有查询目标值.
2.二分查找代码实现
2.1简介代码(无注释)
private static List<Integer> result = new ArrayList<>();
public static List<Integer> search(int[] arr, int left, int right, int target) {
if (left > right) return result;
int mid = (left + right) / 2;
int midVal = arr[mid];
if (target > midVal) return search(arr, mid + 1, right, target);
else if (target < midVal) return search(arr, left, mid - 1, target);
else {
result.add(mid);
int temp = mid - 1;
while (true) {
if (temp < 0 || arr[temp] != target) break;
result.add(temp);
temp -= 1;
}
temp = mid + 1;
while (true) {
if (temp > arr.length - 1 || arr[temp] != target) break;
result.add(temp);
temp += 1;
}
return result;
}
}
2.2 完整代码(含注释与运行实例)
由于使用二分查找需要先排序好数组,为了代码简洁,我直接调用了之前写过得基数排序
package Algorithm.Search;
import Algorithm.Sort.RadixSort;
import Algorithm.Sort.Template;
import Utils.ArrUtil;
import java.util.ArrayList;
import java.util.List;
/**
* 查找(2)
* 二分查找(折半查找)
* 前提是数组本身是有序的
*/
public class BinarySearch {
private static List<Integer> result = new ArrayList<>();
/**
* 查找函数
*
* @param arr 需查找的数组
* @param left 数组的最左下标
* @param right 数组的最右下标
* @param target 需要查找的元素
* @return
*/
public static List<Integer> search(int[] arr, int left, int right, int target) {
//递归结束条件:left>right 但没有找到目标值
if (left > right) return result;
int mid = (left + right) / 2;
int midVal = arr[mid];//数组arr的中间值
if (target > midVal) return search(arr, mid + 1, right, target);//右侧递归
else if (target < midVal) return search(arr, left, mid - 1, target);//左侧递归
else {//return mid;//刚好是中间值
//重复目标值
result.add(mid);//添加中间值
//左边扫描 添加左边与之相同的值
int temp = mid - 1;
while (true) {
if (temp < 0 || arr[temp] != target) break;//下标越界或不为目标值
result.add(temp);//添加下标
temp -= 1;//左移
}
//右边扫描 添加右边与之相同的值
temp = mid + 1;
while (true) {
if (temp > arr.length - 1 || arr[temp] != target) break;//下标越界或不为目标值
result.add(temp);//添加下标
temp += 1;//右移
}
return result;//返回下标集合
} //else
}
public static void main(String[] args) {
int testSize = 20;
int[] arr = Template.getIntData(testSize);
//输出原数组
ArrUtil.show(arr);
RadixSort.sort(arr);//需要目标数组有序 调用基数排序
ArrUtil.show(arr);
int a = (int) (Math.random() * testSize);
System.out.println("二分查找" + a);
List<Integer> index = search(arr, 0, arr.length - 1, a);
System.out.println("下标" + index);
}
}
3.运行实例
12 7 15 16 17 0 9 16 10 14 15 3 18 6 12 17 6 0 17 11
0 0 3 6 6 7 9 10 11 12 12 14 15 15 16 16 17 17 17 18
二分查找12
下标[9, 10]