二分查找

二分查找

普通二分查找

描述:求解递增序列array的sta位置到end位置中间满足等于val值的位置。

适用范围:有序序列。

优势:如果数组长度为n,其算法复杂度为o(log(n)),每次查找能够将数组范围缩小到数组当前长度的一半。

求解:

1.  判断sta位置是否在end位置后面。

  •  sta<=end,跳转到步骤2。
  •  sta>end,找不到满足等于val值的位置,退出循环,返回-1,表示没有找到。

2.  计算sta位置到end的中间位置mid,mid=(sta+end)/2。计算机采用整数除法,即向下取整。跳转到步骤3。

3.  比较val与mid位置对应数值的大小。

  • array[mid]>val,则满足等于val值的位置在sta和mid-1之间,将end赋值为mid-1,查找空间变为[sta,mid-1]。因为(sta+end)/2<=end,所以mid-1一定比end小,空间[sta,end]变为[sta,mid-1],空间一定缩小。跳转到步骤1,继续循环查找。
  • array[mid]<val,则满足等于val值的位置在mid+1和end之间,将sta赋值为mid+1,查找空间变为[mid+1,end]。因为(sta+end)/2>=sta,所以mid+1一定比sta大,空间[sta,end]变为[mid+1,end],空间一定缩小。跳转到步骤1,继续循环查找。
  • array[mid]=val,则找到满足等于val值的位置,即mid,退出循环,返回mid值。

Java源码:

public static int binSearch(int[] array,int val){

    int sta=0;

    int end=array,length-1;

    int mid;

    while(sta<=end){

      //防止sta和end都在很大的时候,两者之和溢出

        mid=sta+(end-sta)/2;

        if(array[mid]>val)

            end=mid-1;

        else if(array[mid]<val)

            sta=mid+1;

        else

            return mid;

    }

    return -1;

}

测试程序:

public static boolean testBinSearch(int count,int size){

   boolean flag=true;

   int[] array;

   int length;

   int rightResult, computeResult;

   Random random=new Random();

   int errorCount=0;

   array=new int[0];

   rightResult=-1;

   computeResult=binSearch(array,-1);

   if(rightResult!=computeResult){

       PrintError(array,computeResult,rightResult,errorCount++);

       flag=false;

   }

   while(count>0){

       count--;

       length=random.nextInt(size)+1;

       rightResult=random.nextInt(length);

       array=new int[length];

       for(int i=0;i<length;i++){

           if(i==0)

               array[i]=random.nextInt(30);

           else

              array[i]=array[i-1]+random.nextInt(5);

       }

       computeResult=binSearch(array,array[rightResult]);

       if(array[rightResult]!=array[computeResult]){

           PrintError(array,computeResult,rightResult,errorCount++);

           flag=false;

       }

       rightResult=-1;

       computeResult=binSearch(array,-1);

       if(rightResult!=computeResult){

           PrintError(array,computeResult,rightResult,errorCount++);

           flag=false;

       }

   }

   returnflag;

}

测试报告:

执行testBinSearch(1000,100),即测试1000次,测试数组长度为1到100之间,测试结果正确。


二分查找变型1--查找第一个值等于val的位置

解析:递增序列array可以同一个值出现多次,求解该问题主要在array[mid]=val时的处理和退出循环判断条件问题。

1.  当array[mid]=val,满足第一个值等于val的值一定在sta和mid之间,在sta和mid-1之间如果没有等于val的值时,mid就是第一个位置,所以此刻范围只能缩小到sta和mid之间。

2.  退出循环判断条件问题。array[mid]=val, 则满足第一个值等于val值的位置在sta和mid之间,查找空间变为[sta,mid]。当sta=end时,mid与end相等,空间[sta,end]变为[sta,mid],空间大小没有改变,会产生死循环。所以循环条件要变为sta<end.因为循环条件变为sta<end,所以在sta=end时没有和val比较,故退出循环通过比较sta位置的值判断是否寻找满足第一个值等于val的值的位置。

Java源码:

public static int binSearchFirst(int[] array,int val){

    int sta=0;

    int end=array.length-1;

    int mid;

    while(sta<end){

        mid=sta+(end-sta)/2;

        if(array[mid]>val)

            end=mid-1;

        else if(array[mid]<val)

            sta=mid+1;

        else

            end=mid;

    }

    if(array[sta]==val)

        return sta;

    return -1;

}

测试程序:

public static boolean testBinSearchFirst(int count,int size){

    boolean flag=true;

    int[] array;

    int length;

    int rightResult,computeResult;

    Random random=new Random();

    int errorCount=0;

    array=new int[0];

    rightResult=-1;

    computeResult=binSearch(array,-1);

    if(rightResult!=computeResult){

        PrintError(array,computeResult,rightResult,errorCount++);

        flag=false;

    }

    while(count>0){

        count--;

        length=random.nextInt(size)+1;

        rightResult=random.nextInt(length);

        array=new int[length];

        for(int i=0;i<length;i++){

            if(i==0)

                array[i]=random.nextInt(30);

            else if(i==rightResult)

               array[i]=array[i-1]+random.nextInt(5)+1;

            else

               array[i]=array[i-1]+random.nextInt(5);

        }

        computeResult=binSearch(array,array[rightResult]);

        if(array[rightResult]!=array[computeResult]){

            PrintError(array,computeResult,rightResult,errorCount++);

            flag=false;

        }

        rightResult=-1;

        computeResult=binSearch(array,-1);

        if(rightResult!=computeResult){

            PrintError(array,computeResult,rightResult,errorCount++);

            flag=false;

        }

    }

    returnflag;

 }

测试报告:

执行testBinSearchFirst(1000,100),即测试1000次,测试数组长度为1到100之间,测试结果正确。

 

二分查找变型2--查找最后一个值等于val的位置

解析:求解该问题主要在array[mid]与val的比较处理和退出循环判断条件问题。

1.  当array[mid]=val,满足最后一个值等于val的值一定在mid和end之间,在mid+1和end之间如果没有等于val的值时,mid就是最后一个位置,所以此刻范围只能缩小到mid和sta之间。

2.  退出循环判断条件问题。array[mid]=val, 则满足最后一个值等于val值的位置在mid和end之间,查找空间变为[mid,end]。当sta=end或者sta=end-1时,(sta+end)/2等于sta,mid与sta相等,空间[sta,end]变为[mid,end],空间大小没有改变,会产生死循环。所以循环条件要变为sta<end-1.因为循环条件变为sta<end-1,所以在sta和end-1时没有和val比较,故退出循环通过比较sta和end-1位置的值判断是否寻找满足最后一个值等于val的值的位置。

Java源码:

public static int binSearchLast(int[] array,int val){

    int sta= 0;

    int end= array.length - 1;

    int mid;

    while (sta< end - 1) {

        mid = sta + (end - sta) / 2;

        if(array[mid] > val)

            end = mid - 1;

        else if(array[mid] < val)

            sta = mid + 1;

        else

            sta = mid;

    }

    if (sta== end - 1 && array[end] == val)

        return end;

    if (sta== end - 1 && array[sta] == val)

        return sta;

    if (sta== end && array[sta] == val)

        return sta;

    return -1;

}

测试程序:

public static boolean testBinSearchLast(int count,intsize) {

    boolean flag= true;

    int[] array;

    int length;

    int rightResult, computeResult;

    Random random = new Random();

    int errorCount = 0;

    array = new int[0];

    rightResult = -1;

    computeResult = binSearchLast(array,-1);

    if(rightResult != computeResult) {

        PrintError(array, computeResult,rightResult, errorCount++);

        flag = false;

    }

    while(count > 0) {

        count--;

        length = random.nextInt(size) + 1;

        rightResult = random.nextInt(length);

        array = new int[length];

        for (int i =0; i < length; i++) {

            if (i== rightResult) {

                // 构建多个相同的值

                intsameLength = random.nextInt(30) + 1;

                int tmp;

                if (i== 0)

                    tmp = random.nextInt(30);

                else

                    tmp = array[i - 1] +random.nextInt(5) + 1;

                while(sameLength > 0 && i < length)

                    array[i++] = tmp;

                if(i<length)

                    array[i] = tmp + 2;

                rightResult = i - 1;

            } else {

                if (i== 0)

                    array[i] =random.nextInt(30);

                else

                    array[i] = array[i - 1] + random.nextInt(5);

            }

        }

        computeResult = binSearchLast(array,array[rightResult]);

        if(rightResult != computeResult) {

            PrintError(array,computeResult, rightResult, errorCount++);

            flag = false;

        }

        rightResult = -1;

        computeResult = binSearchLast(array,-1);

        if(rightResult != computeResult) {

            PrintError(array,computeResult, rightResult, errorCount++);

            flag = false;

        }

    }

    return flag;

}

测试报告:

执行testBinSearchLast(1000,100),即测试1000次,测试数组长度为1到100之间,测试结果正确。

 

二分查找变型3--查找最接近val并且小于val的位置

解析:求解该问题主要在array[mid]与val比较处理和退出循环判断条件问题。

1.  array[mid]>val,则满足最接近val并且小于val值的位置在sta和mid-1之间, 即[sta,mid-1]。继续循环查找。

2.  array[mid]<val,则满足等于最接近val并且小于val值的位置在mid和end之间,查找空间变为[mid,end]。当sta=end或者sta=end-1时,(sta+end)/2等于sta,mid与sta相等,空间[sta,end]变为[mid,end],空间大小没有改变,会产生死循环。所以循环条件要变为sta<end-1.因为循环条件变为sta<end-1,所以在sta和end-1时没有和val比较,故退出循环通过比较sta和end-1位置的值判断是否寻找满足最后一个值等于val的值的位置。

3.  array[mid]=val,则满足等于最接近val并且小于val值的位置在sta和mid-1之间,即[sta,mid-1]。继续循环查找。

Java源码:

public static int binSearchLess(int[] array,int val){

    int sta= 0;

    int end= array.length - 1;

    int mid;

    while (sta< end - 1) {

        mid = sta + (end - sta) / 2;

        if(array[mid] > val)

            end = mid - 1;

        else if(array[mid] < val)

            sta = mid;

        else

            end = mid - 1;

    }

    if (sta== end - 1 && array[end] < val)

        return end;

    if (sta== end - 1 && array[sta] < val)

        return sta;

    if (sta== end && array[sta] < val)

        return sta;

    return -1;

}

测试程序:

public static boolean testBinSearchLess(int count,intsize) {

    boolean flag= true;

    int[] array;

    int length;

    int rightResult, computeResult;

    Random random = new Random();

    int errorCount = 0;

    array = new int[0];

    rightResult = -1;

    computeResult = binSearchLess(array,-1);

    if(rightResult != computeResult) {

        PrintError(array, computeResult,rightResult, errorCount++);

        flag = false;

    }

    while(count > 0) {

        count--;

        length = random.nextInt(size) + 1;

        rightResult = random.nextInt(length);

        array = new int[length];

        for (int i =0; i < length; i++) {

            if (i== rightResult) {

                int tmp;

                if (i== 0)

                    tmp = random.nextInt(30);

                else

                    tmp = array[i - 1] +random.nextInt(5) + 1;

                array[i] = tmp;

            } else {

                if (i== 0)

                    array[i] =random.nextInt(30);

                else

                    array[i] = array[i - 1] +random.nextInt(5);

            }

        }

        computeResult = binSearchLess(array,array[rightResult]);

        rightResult--;

        if(rightResult != computeResult) {

            PrintError(array,computeResult, rightResult, errorCount++);

            flag = false;

        }

        rightResult = -1;

        computeResult = binSearchLess(array,-1);

        if(rightResult != computeResult) {

            PrintError(array,computeResult, rightResult, errorCount++);

            flag = false;

        }

        rightResult = array.length-1;

        computeResult = binSearchLess(array,Integer.MAX_VALUE);

        if(rightResult != computeResult) {

            PrintError(array,computeResult, rightResult, errorCount++);

            flag = false;

        }

    }

    returnflag;

}

测试报告:

执行testBinSearchLess(1000,100),即测试1000次,测试数组长度为1到100之间,测试结果正确。

 

二分查找变型4--查找最接近val并且大于val的位置

解析:递增序列array可以同一个值出现多次,求解该问题主要在array[mid]和val比较处理和退出循环判断条件问题。

1.  array[mid]>val,则满足最接近val并且大于val值的位置在sta和mid之间, 即[sta,mid]。当sta=end时,mid与end相等,空间[sta,end]变为[sta,mid],空间大小没有改变,会产生死循环。所以循环条件要变为sta<end.因为循环条件变为sta<end,所以在sta=end时没有和val比较,故退出循环通过比较sta位置的值判断是否寻找满足第一个值等于val的值的位置。

2.  array[mid]<val,则满足等于最接近val并且大于val值的位置在mid+1和end之间,即[mid+1,end]。继续循环查找。

3.  array[mid]=val,则满足等于最接近val并且大于val值的位置在mid+1和end之间,即[mid+1,end]。继续循环查找。

Java源码:

public static int binSearchGreater(int[] array,int val){

    int sta= 0;

    int end= array.length - 1;

    int mid;

    while (sta< end) {

        mid = sta + (end - sta) / 2;

        if(array[mid] > val)

            end = mid;

        else if(array[mid] < val)

            sta = mid + 1;

        else

            sta = mid + 1;

    }

    if (sta== end && array[sta] > val)

        return sta;

    return -1;

}

测试程序:

public static boolean testBinSearchGreater(int count,int size) {

    boolean flag= true;

    int[] array;

    int length;

    int rightResult, computeResult;

    Random random = new Random();

    int errorCount = 0;

    array = new int[0];

    rightResult = -1;

    computeResult = binSearchGreater(array,-1);

    if(rightResult != computeResult) {

        PrintError(array, computeResult,rightResult, errorCount++);

        flag = false;

    }

    while(count > 0) {

        count--;

        length = random.nextInt(size) + 1;

        rightResult = random.nextInt(length);

        array = new int[length];

        for (int i =0; i < length; i++) {

            if (i== rightResult) {

                int tmp;

                if (i== 0)

                    tmp = random.nextInt(30);

                else

                    tmp = array[i - 1] +random.nextInt(5) + 1;

                array[i] = tmp;

            } else {

                if (i== 0)

                    array[i] =random.nextInt(30);

                else

                    array[i] = array[i - 1] +random.nextInt(5);

            }

        }

        computeResult = binSearchGreater(array,rightResult==0?-1:array[rightResult-1]);

        if(rightResult != computeResult) {

            PrintError(array,computeResult, rightResult, errorCount++);

            flag = false;

        }

        rightResult = 0;

        computeResult = binSearchGreater(array,-1);

        if(rightResult != computeResult) {

            PrintError(array,computeResult, rightResult, errorCount++);

            flag = false;

        }

        rightResult = -1;

        computeResult = binSearchGreater(array,Integer.MAX_VALUE);

        if(rightResult != computeResult) {

            PrintError(array,computeResult, rightResult, errorCount++);

            flag = false;

        }

    }

    return flag;

}

测试报告:

执行testBinSearchGreater(1000,100),即测试1000次,测试数组长度为1到100之间,测试结果正确。


下载地址:

http://download.csdn.net/detail/ssuchange/6700749


参考资料:

二分查找之美 http://www.cr173.com/html/20428_1.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值