数据结构——二分查找算法

1、算法描述

二分查找算法:需求:在有序数组A内,查找值target,如果找到则返回目标值的索引号,否则返回-1

算法描述
前提 给定一个内含有n个元素的有序数组A,满足A0<=A1<=A2<=···<=An-1,一个待查找的值target
1 设置i=0,j=n-1
2 如果i>j,结束查找,没有找到
3 设置m=floor((i+j)/2),m为中间索引,floor为向下取整(也就是小于等于(i+j)/2的最大整数)
4 如果target<Am,设置j=m-1,跳转到第2步
5 如果target>Am,设置i=m+1,跳转到第2步
6 r如果Am=target,结束查找,找到目标值

2、算法实现

//Java写一个方法,传入一个数组和要查找的目标值
public static int erfenSearch(int[] a,int target){
   
       int i=0,j=a.length-1;      //设置两个指针的初值
       while(i<=j){               //在i到j范围内查找
             int m=(i+j)>>>1;
             if(target<a[m]){     //目标在左边
                j=m-1;            

            }else if(a[m]<target){ //目标在右边
                   i=m+1;
            }else{                  //找到了
                   return m;
            }
             
             reutrn -1;

       }

}

3、存在的问题

1、为什么循环中写i<=j,而不是i<j?

回答:如果只是写i<j,那么只有索引为m的参与比较,i和j为索引的元素就不会参与比较,比如查找到最后一个元素时i=j了,但是此时就不会进入循环去求m,从而就没办法比较i==j时的那个元素是否是目标值,而i==j就意味着i,j指向的元素也会参与比较

2、(i+j)/2为什么写成>>>1?

回答:如果i 和 j 变成了两个很大的正整数相加,那么得到的结果就有可能为负数,在二进制中,同一个二进制数,如果把最高位视为符号位,那么得到的结果就是负的,如果不视为符号位,那么得到的结果就是正常的,改变:使用无符号右移运算符来代替除2的过程。

右移:7的二进制数8位表示为0000 0111,右移之后变成0000 0011,也就是变成了3

16的二进制0001 0000,右移之后变成0000 1000 也就是变成了8

而这就能看成除2取整,(7除2取整就是3),同一个二进制可能表现出正整数,也会表现出负数,但是通过让其右移的方式,最终得到的结果都是正确的,此外,通过这种右移的方式还能适应其他语言

=(mi+j)>>>1;

3、为什么代码中都写成小于号,有什么好处?

回答:与数组的排序有关,数组属于升序还是排序,属于升序的就写小于号,能给人一种更加直观的感觉,写出来的代码与我们的思维更加一致,不过当然你不想这样写那也没关系,自己能够看得懂就行啦。

4、改版后的二分查找算法

//改写后的二分查找算法
public static int erfenSearch(int[] a,int target){
   
       int i=0,j=a.length;         //不进行减一
       while(i<j){                 //没有等于
             int m=(i+j)>>>1;
             if(target<a[m]){     
                j=m;               //直接等于m

            }else if(a[m]<target){ 
                   i=m+1;
            }else{              
                   return m;
            }
             
             reutrn -1;
       }
}

此时 j 所指向的位置不会参与运算,可以取一个递增的数组来做示范,这两种版本的二分法都需要掌握

注意:在改版后的不能在循环条件中添加等于号,否则当查找一个不存在的目标值时会陷入死循环中

猜你喜欢

转载自blog.csdn.net/MayMarch/article/details/130021648