二分查找的解释
二分查找又叫做折半查找,其作用有两个,一是可以高效的查询有序的数列中是否存在要查询的元素以及元素的位置,二是如果要往有序的数列中插入一个数,可以高效的查找到添加位置(但是由于其存储结构是顺序的,因此插入时效率低),由于其查找原理的好处使得二分查找的最坏情况的时间复杂度也为O(log2n),要优于顺序查找,其查找原理稍后用实例解释。
需要满足的条件
- 二分查找是针对大小有序的数列来说的,不管是从大到小还是从小到大
- 要查找的数据必须是一种顺序的存储结构
先看一个java实例
该例中我封装了一个二分查找的方法,进行了一次模拟调用,先尝试看懂代码,在程序运行截图后面我描述了整个运行过程,可以帮助理解,中间的输出语句是输出区间范围的,已经注释掉了。
public class Binary {
public static void main(String[] args) {
int arr[] = { 3, 7, 8, 11, 45, 56, 66, 68, 79, 82, 99 };
Binary bi = new Binary();
int location = bi.getLocation(66, arr);
if (location > 0) {//location表示查找返回的位置,没有找到返回0
System.out.println("该数出现在第" + location + "位置");
} else {
System.out.println("无此数");
}
}
/**
* 该方法内封装了二分查找
*
* @param data
* 传入一个int型数据
* @param arr
* 传入一个int型数组
* @return 返回元素位置,没查到返回0
*/
public int getLocation(int data, int arr[]) {
// 采用二分查找每次都要缩小查找区间范围,begin是区间首位数字下标,end相反
int begin = 0, end = arr.length - 1;
// 用于记录 要查找数字存在的位置
int location = 0;
// 保证要查找的数字在该数组的区间范围内
if (data >= arr[0] && data <= arr[arr.length - 1]){
while (end - 1 > begin) { //当区间元素相邻则退出循环
int mid = (begin + end) / 2; //mid是取区间的中间数,与data比较之后可以缩小比较的区间范围
if (data > arr[mid]) {
begin = mid; //在满足data比中间数大的时候,则把中间数下标赋值给begin,因此缩小了比较区间
//System.out.println("中间值为"+mid+" 重新确定区间为" + arr[begin] + " " + arr[end]);
} else if (data < arr[mid]) {
end = mid;
//System.out.println("中间值为"+mid+" 重新确定区间为" + arr[begin] + " " + arr[end]);
} else {
//System.out.println("中间值为"+mid);
location = mid + 1;
break;//当遇到相同元素记录该下标并强制退出循环
}
}
}
if(location==0){//上述循环完成后有可能漏掉begin和end下标表示的元素,因此在比较一下
if (arr[begin] == data)
location = begin + 1;
if (arr[end] == data)
location = end + 1;
}
return location;
}
}
运行结果为
运行过程描述如下
从截图可以看出,在进行二分查找的过程中,两次重新确定该值的区间,在 3, 7, 8, 11, 45, 56, 66, 68, 79, 82, 99中查找66
- 第一遍下标begin=0,end=10,mid=5,因此mid下标指示的数字是56,66>56因此区间改变,begin=mid=5
- 第二遍下标begin=5,end=10,mid=7,因此mid下标指示的数字是68,66<68因此区间改变,end=mid=7
- 第三遍下标begin=5,end=7,mid=6,因此mid下标指示的数字是66,因此确定了位置,循环强制退出