文章目录
- 一.二分查找
- 1.1 概述
- 1.2 基本版实现
- 1.3 变动版
一.二分查找
1.1 概述
也叫折半查找
每次排除一半的查找范围
前提条件:元素必须是有序的,从小到大,或者从大到小都是可以的。
如果是无序的,也可以先进行排序。但是排序之后,会改变原有数据的顺序,查找出来元素位置跟原来的元素可能是不一样的,所以排序之后再查找只能判断当前数据是否在容器当中,返回的索引无实际的意义。
基本思想:也称为是折半查找,属于有序查找算法。用给定值先与中间结点比较。
1.2 基本版实现
public class Test01 {public static void main(String[] args) {// 基础版:二分查找算法int[] arr = { 1,2, 6,66};int i = binarySearch(arr, 6);System.out.println(i);//1}// 定义方法,查找目标数字的索引,、// 找到返回对应的索引// 没有找到返回-1public static int binarySearch(int[] arr, int target){// 起始索引int start = 0;// 末尾索引int end = arr.length-1;// start索引和end索范围内有东西执行查找while (start <= end){// 定义中间索引int mid = (start +end)/2;// int mid = (start +end)>>>1;// 目标函数 小于 中间值if (target <arr[mid]){end = mid - 1;}else if (arr[mid] < target){start = mid + 1;}else {return mid;}}return -1;}// BinarySearch() 结束
}
-
问题1: 为什么是 i<=j 意味着区间内有未比较的元素, 而不是 i<j ?
i==j 意味着 i,j 它们指向的元素也会参与比较
i<j 只意味着 m 指向的元素参与比较 -
问题2: (start + end) / 2 有没有问题?
如果 int end = Integer.MAX_VALUE-1;在运行(start + end)会出现内存溢出。
同一个二进制数:1011-111-1111-1111-1111-1111-1111-1110
不把高位视为符号位,代表:3221225470
把最高位视为符号位,代表:-1073741826
解决办法:
采用右移一位,右移一位的效果相当于除以2向下取整。
只需将 int mid = (start + end) / 2 改成 int mid = (start + end) >>> 1
1.3 变动版
public class Test02 {public static void main(String[] args) {// 变动版:二分查找算法int[] arr = {1,2, 6,66};int i = binarySearch(arr, 6);System.out.println(i);//1}// 定义方法,查找目标数字的索引,、// 找到返回对应的索引// 没有找到返回-1public static int binarySearch(int[] arr, int target){// 起始索引int start = 0;// 末尾索引;// 第一处变动,end指针不参与运算,只作为边界int end = arr.length;// start索引和end索范围内有东西执行查找// 第二处变动 <= 变为 <while (start < end){// 定义中间索引// int mid = (start +end)/2;int mid = (start +end) >>> 1;// 目标函数 小于 中间值if (target <arr[mid] ){//第三变动,end = mid;}else if (arr[mid] < target){start = mid + 1;}else {return mid;}}return -1;}// BinarySearch() 结束
}