折半查找算法[二分查找法]算法的实现和解决整数溢出问题~

简介: 折半查找算法[二分查找法]算法的实现和解决整数溢出问题~

算法实现的要求:

折半查找法又称为二分查找法,这种方法对待查找的列表有两个要求:

1:必须采用顺序存储结构
2:必须按关键字大小有序排列

算法思想:

将表中间位置记录的关键字与查找关键字进行比较如果两者相等,则查找成功,否则利用中间位置记录将表分成前后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表

重复上述查找过程,直到找到满足条件的记录,则查找成功,或直到子表不存在为止,则查找不成功

使用java实现该算法:

算法实现方法:

1:前提要求:有已排序数组A,[因为在查找的过程中是根据下标进行的]
2:定义左边界L,右边R,确定搜索范围,循环执行二分查找
3:获取中间索引M=(L+R)/2,如果是小数,一般默认向下取整
4:中间索引的值A[M]与带搜索的值T进行比较
A[M]==T,返回中间索引
A[M]>T,中间值右侧的其他元素都大于T,无需比较,中间索引左边去找,M-1,设置为右边界,重新查找
A[M]<T,中间值左侧的其他元素都小于T,无需比较,中间索引右边去找,M+1设置为左边界,重新查找
5:当L>R时,表示没有找到,应结束循环

代码如下所示:

package bin_find;
import java.util.Scanner;
public class bin_find {
    public static void main(String[] args) {
        int arr[] = {4, 10, 18, 23, 45, 68, 199};
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入你要查找的数:");
        int x = scanner.nextInt();
        int result= bin_research(arr,x);
        if(result!=-1){
            System.out.println("你要查找的数已找到,它是数组的第"+(result+1)+"个元素");
        }
        else{
            System.out.println("你要查找的数不存在");
        }
    }
    public static int bin_research(int arr[], int x) {
        int L = 0;
        int R = arr.length - 1;
        while(L<=R) {
        //不要写到循环外面了,因为每查找一次,中间索引的位置也需要变化
            int M = (L + R) / 2;
            if (x > arr[M]) {
                L = M+1;
            } else if (x < arr[M]) {
                R = M - 1;
            } else if (x == arr[M]) {
                return M;
            }
        }
        return -1;
    }
}

输出:

请输入你要查找的数:
23
你要查找的数已找到,它是数组的第4个元素

整数溢出现象:

package bin_find;
public class bin_find2 {
    public static void main(String[] args) {
        int l=0;
        int r=Integer.MAX_VALUE-1;
        int m=(l+r)/2;
        //当要查找的数在左子表时:
        System.out.println(m);
        //当要查找的数在右子表时:发生整数溢出现象
        l=m+1;
        m=(l+r)/2;
        System.out.println(m);
    }
}

输出:

1073741823
-536870913

之所以会出现负数的原因:是因为在计算机中,是根据二进制进行运算的,逢二进一,由于最高位表示符号位,当它为1时,该数即为负数!

对该过程不熟悉的小伙伴,可以去看我写的这篇文章

解决整数溢出问题:

上述代码中产生溢出的原因是由于:当要查找的数在右子表时,此时:r最初为整数的最大值-1不变,而l的值增大到了r/2的大小,因此即使他两相加除2,在计算机中,是根据二进制进行运算的,逢二进一,由于最高位表示符号位,当它为1时,该数即为负数,那么解决溢出的核心就是改变m的值,但所谓的改变,并不是将m的值真正的改变,而是通过变换表达式等等,去调整m的大小


方法1:通过调整数学表达式

方法如下:

代码如下:

package bin_find;
public class bin_find2 {
    public static void main(String[] args) {
        int l=0;
        int r=Integer.MAX_VALUE-1;
        int m=l+(r-l)/2;
        //当要查找的数在左子表时:
        System.out.println(m);
        //当要查找的数在右子表时:
        l=m+1;
        m=l+(r-l)/2;
        System.out.println(m);
    }
}


输出:

1073741823
1610612735

方法2:通过>>>运算符

>>>表示无符号右移运算符,也叫逻辑右移,即若该数为正,则高位补0,而若该数为负数,则右移后高位同样补0,移动的是二进制位,但他们的操作数必须是整数,[当被操作的数是整数时]右移一位有除二的效果,因此对于上述溢出现象,右移一位既能够避免最高位[符号位]为1,导致该数为负数的现象,而且正好借用它右移一位有除二的效果,还简化了数学表达式;

修改如下:

package bin_find;
public class bin_find2 {
    public static void main(String[] args) {
        int l=0;
        int r=Integer.MAX_VALUE-1;
        int m=(r+l)>>>1;
        //当要查找的数在左子表时:
        System.out.println(m);
        //当要查找的数在右子表时:
        l=m+1;
        m=l+(r-l)>>>1;
        System.out.println(m);
    }
}


输出:

1073741823
1073741823

对于上述两种做法均可以解决整数溢出问题,不过我们更加推荐第二种,因为它的效率比较高!

练习题:

有一个有序表为 1,5,8,11,19,22,31,35,4045,89,50 当分查找值为48的结点时,查找成功需要比较的次数

[来源于:京东实习生招聘]

答案为:4次


这里需要强调的点就是:当子表的元素个数为偶数时,如果题目没有强调,那么我们默认选择靠左边的元素为中间数


使用二分法在序列 1,4,6,7,15,33,39,50,64,78,75,81,89,96 中查找元素81 时,需要经过()比较

[来源于:美团点评校招]


答案为:4次


在拥有128个元素的数组中二分查找一个数,需要比较的次数最多不超过多少次 [来源于:北京易道博识社招]


答案为:7次


方法1:

上述题目相当于为2^n=128,n的值为多少?


方法2:

使用128一直不断的除2,直到变为1,只需要计算除2的次数即可


方法3:

使用计算器,问题转变为log2^128,不过需要知道该计算机是以多少为底,下图为Windows10操作系统的计算器,以10为底

运算结果是整数,则该整数即为最终结果

运算结果是小数,则舍去小数部分,整数加一为最终结果

相关文章
|
16天前
|
算法 索引
【算法】——二分查找合集
二分查找基础模版和进阶模版,查找元素位置,搜索插入位置,x的平方根,山脉数组的峰顶索引,寻找峰值,点名
|
5月前
|
算法
【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置
【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置
|
3月前
|
算法 C# 索引
C#二分查找算法
C#二分查找算法
|
3月前
|
存储 算法 C语言
【C语言】二分查找算法
【C语言】二分查找算法
|
3月前
|
消息中间件 存储 算法
一文搞懂二分查找算法!
一文搞懂二分查找算法!
155 0
|
3月前
|
算法 Java 索引
数据结构与算法学习十五:常用查找算法介绍,线性排序、二分查找(折半查找)算法、差值查找算法、斐波那契(黄金分割法)查找算法
四种常用的查找算法:顺序查找、二分查找(折半查找)、插值查找和斐波那契查找,并提供了Java语言的实现代码和测试结果。
40 0
|
5月前
|
人工智能 算法
第一周算法设计与分析:C : 200和整数对之间的情缘
这篇文章介绍了解决算法问题"200和整数对之间的情缘"的方法,通过统计数组中每个数模200的余数,并计算每个同余类中数的组合数来找出所有满足条件的整数对(i, j),使得\( A_i - A_j \)是200的整数倍。
|
5月前
|
存储 算法 Java
深入算法基础二分查找数组
文章深入学习了二分查找算法的基础,通过实战例子详细解释了算法的逻辑流程,强调了确定合法搜索边界的重要性,并提供了Java语言的代码实现。
深入算法基础二分查找数组
|
6月前
|
算法
【算法】二分查找(整数二分和浮点数二分)
算法学习——二分查找(整数二分和浮点数二分)
51 0
【算法】二分查找(整数二分和浮点数二分)
|
5月前
|
算法
【算法】二分查找——二分查找
【算法】二分查找——二分查找