1.基础版
public class erfenchazhao {
public int test(int arr[],int target){
int i = 0; //定义左指针
int j = arr.length-1;//定义右指针
int m; //定义中间值
while(i<=j){ //判断条件
m = (i+j)>>>1;
if(target < arr[m]){ //目标值在左边
j = m - 1;
}else if ( arr[m] < target ){ //目标值在右边
i = m + 1;
}else { //找到目标值
return m;
}
}
return -1;
}
}
注意:
(1)i<=j 最后一次比较当i=j时,它们所指向的元素也会参与比较
(2)m=(i+j)/2有问题,当值达到上界时,m会变为负数, m = (i+j)>>>1避开了该问题,其值为(i+j)/2向下取整
(3)该数组必须是有序的,比较中都使用小于号,方便观察算法
时间复杂度:
最坏情况:O(logn)
最好情况:如果待查找元素恰好在数组中央,只需要循环一次O(1)
空间复杂度:
需要常数个指针i,j,m,因此额外占用的空间是O(1)
2.改动版
public class erfenchazhao {
public int test(int arr[],int target){
int i = 0;
int j = arr.length; //第一处
int m;
while(i < j){ //第二处
m = (i+j)>>>1;
if(target < arr[m]){
j = m; //第三处
}else if ( arr[m] < target ){
i = m + 1;
}else {
return m;
}
}
return -1;
}
}
注:改良版的j指向数组外,则j所指位置的值一定不是目标值;
改良版的i<j,若是<=,则查找不存在的值时,会陷入死循环。
3.平衡版
public class ddd {
public int search(int a[],int target){
int i = 0,j = a.length;
while (1 < j - i){
int m = (i + j) >>> 1;
if (target < a[m]){
j = m;
} else {
i = m;
}
}
if (a[i] == target){
return i;
}else {
return -1;
}
}
}
优点:循环内的平均比较次数减少了
缺点:必须在循环结束后才能进行 i 指针所指元素与目标元素的比较,时间复杂度都是O(logn)
4.java版
在java可以直接调用该方法,查找数组中某个值的位置(仅适用于有序数组)
若是没有找到,返回 -(low+1) (即负数表示没找到),则low代表该值 若是插入数组 应插入的位置,+1是排除该值插入0号位置的情况
扩展:将目标值插入数组
5.LeftRightmost(有重复元素的数组)
适用于有序数组
(1)寻找目标值最左边的位置
public class erfenchazhao {
public int test1(int arr[],int target){
int i = 0, j = arr.length-1;
int candidate = -1;
while(i<=j){
int m = (i+j)>>>1;
if(target < arr[m]){
j = m - 1;
}else if (arr[m] < target){
i = m + 1;
}else {
//记录候选位置
candidate = m;
j = m - 1;
}
}
return candidate;
}
}
(2)寻找目标值最右边的位置
public class erfenchazhao {
public int test1(int arr[],int target){
int i = 0, j = arr.length-1;
int candidate = -1;
while(i<=j){
int m = (i+j)>>>1;
if(target < arr[m]){
j = m - 1;
}else if (arr[m] < target){
i = m + 1;
}else {
//记录候选位置
candidate = m;
i = m + 1;
}
}
return candidate;
}
}
6.LeftRightmost优化
(1)靠左
public class erfenchazhao {
public int test1(int arr[],int target){
int i = 0, j = arr.length-1;
while(i<=j){
int m = (i+j)>>>1;
if(target <= arr[m]){
j = m - 1;
}else {
i = m + 1;
}
}
return i;
}
}
返回值含义:返回 >= target 的最靠左索引
(2)靠右
public class erfenchazhao {
public int test1(int arr[],int target){
int i = 0, j = arr.length-1;
while(i<=j){
int m = (i+j)>>>1;
if(target < arr[m]){
j = m - 1;
}else{
i = m + 1;
}
}
return i - 1;
}
}
返回值含义:返回 <= target 的最靠右索引