二分查找针对的是一个有序的数据集合,查找思想有点类似分治思想。每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为 0。O(logn) 惊人的查找速度。
我们二分查找可以分成两个情况,一种是不存在重复元素。另外一种是出现重复元素的情况。
/**
* 二分查找
*
* @param data
* @param value
*/
public static int BinarySearch(int[] data, int value) {
return binarySearch(data, 0, data.length - 1, value);
}
/**
* 通过二分查找进行查找元素
*
* @param data
* @param l
* @param r
* @param value
* @return 返回下标,如果没有找到就返回-1
*/
private static int binarySearch(int[] data, int l, int r, int value) {
while (l <= r) {
int mid = l + ((r - l) >> 1);
if (value == data[mid]) {
return mid;
} else if (value > data[mid]) {
l = mid + 1;
} else {
r = mid - 1;
}
}
return -1;
}
/**
* 递归实现
*
* @param data
* @param l
* @param r
* @param value
* @return
*/
private static int binarySearch2(int[] data, int l, int r, int value) {
if (r < l) return -1;
int mid = l + ((r - l) >> 1);
if (data[mid] > value) {
return binarySearch2(data, l, mid - 1, value);
} else if (data[mid] < value) {
return binarySearch2(data, mid + 1, r, value);
} else {
return mid;
}
}
/**
* 查找第一个等于某个元素的二分查找
*
* @param data
* @return
*/
public static int getBinarySearchFirst(int[] data, int value) {
int l = 0;
int r = data.length - 1;
while (l <= r) {
int mid = l + ((r - l) >> 1);
if (value < data[mid]) {
r = mid - 1;
} else if (value > data[mid]) {
l = mid + 1;
} else {
//如果是第一个元素 或者说是它前面的元素是一个不等于它的数。
if (mid == 0 || data[mid - 1] != value) {
return mid;
} else {
r = mid - 1;
}
}
}
return -1;
}
/**
* 查找最后一个元素等于某个元素的二分查找
*
* @param data
* @param value
* @return
*/
public static int getBinarySearchLast(int[] data, int value) {
int l = 0;
int r = data.length - 1;
while (l <= r) {
int mid = l + ((r - l) >> 1);
if (value < data[mid]) {
r = mid - 1;
} else if (value > data[mid]) {
l = mid + 1;
} else {
//如果是最右边的元素,或者右边的元素不等于value
if (mid == data.length - 1 || data[mid + 1] != value) {
return mid;
} else {
l = mid + 1;
}
}
}
return -1;
}
/**
* 查找第一个大于等于给定值的元素
*
* @param data
* @param value
* @return
*/
public static int getBinarySearcFirst2(int[] data, int value) {
int l = 0;
int r = data.length - 1;
while (l <= r) {
int mid = l + ((r - l) >> 1);
//如果这个数大于等于它的元素
if (value >= data[mid]) {
//如果mid 已经是最左边的元素了 或者说前面的元素已经下于某个元素了
if (mid == 0 || data[mid - 1] < value) return mid;
else {
l = mid + 1;
}
} else {
r = mid - 1;
}
}
return -1;
}
/**
* 查找最后一个小于等于给定值的元素
*
* @param data
* @param value
* @return
*/
public static int getBinarySearcLast2(int[] data, int value) {
int l = 0;
int r = data.length - 1;
while (l <= r) {
int mid = l + ((r - l) >> 1);
if(data[mid]<=value){ //表示的是找到的元素
if(mid==data.length-1||data[mid+1]>value){
return mid;
}
else{
l=mid+1;
}
}
}
return -1;
}
}
首先二分查找依赖的是顺序表结构,简单点说就是数组。
其次,二分查找针对的是有序数据。
最后,数据量太大也不适合二分查找