二分查找的Java实现(递归和非递归)

功能描述

二分查找仅针对有序排列(正序或倒序)的数组,通过比较中间元素和待查找元素的大小,从而确定下一步是在左半边还是右半边继续查找,直到找到要找的元素或者序列长度为0或1而不能再继续二分下去。这里采用在内存空间中连续存储的数组形式存储数据,方便快速定位中间元素而不需要从头遍历。程序结束之后给出待查找元素的位置信息或未找到该元素的信号。

本文是我在学习二分查找实现过程中的总结,如果有不完善或错误的地方欢迎指正。

算法实现过程

为了方便划定查找范围,设置一个头指针front(记录下标的整数)指向要查找的数组的第一个元素,设置一个尾指针rear(记录下标的整数)指向该数组最后一个元素的下一个位置,中间位置由

middle = (front + rear) / 2; //中间位置

得到。注意数组元素的位置即下标,是从0开始的。以[1, 2, 3]为例可以得到,middle = (front + rear) / 2 = (0 + 3) / 2 = 1,即元素2是中间位置的元素;以[1, 2]为例,middle = (front + rear) / 2 = (0 + 2) / 2 = 1,即认为元素1是中间的位置。可以看到,对于奇数个元素的数组,中间元素是处于中轴线上的元素,对于元素个数为偶数的数组,中间元素是中轴线右边的元素。对于下标不是从零开始的数组片段也是一样的道理。

如果中间元素正好等于待查找的元素,那么程序直接返回中间元素的下标,皆大欢喜;如果中间元素大于待查找元素,说明后者有可能出现在以中间元素为分界线的左侧数组中,此时已中间指针赋值尾指针,正好就是左侧数组的首尾指针范围;如果中间元素小于待查找元素,说明需要在右侧数组中继续查找,此时可将中间指针的下一个位置赋值给头指针,尾指针不变。上述过程很容易联想到通过递归实现,将首指针、尾指针作为参数传入查找函数中。

这里我们考虑几个终止递归的条件。当数组长度为1时,front == rear == middle,如果该元素大于待查找元素,则需要在左侧数组查找,此时赋值rear = middle;后陷入死循环;如果该元素小于待查找元素,则需要在右侧数组查找,此时rear = middle + 1,赋值之后的rear向后移了一位,数组越界。当数组长度为2时,即rear == front + 1,此时同样会遇到上面的问题。所以,程序需要注意避免死循环和数组越界的问题。

代码展示

这里我以[2, 4, 6]作为演示数组。代码暂不考虑效率问题和性能优化。分别输入3、7、2、4、6作为待查找元素,3可以测试可能导致死循环的异常情况,7可以测试可能导致数组越界的异常情况,2、4、6分别测试三种找到元素的情况。测试之后发现都没问题。这里就不贴主程序代码了,只贴两个函数的代码。

递归方法实现

//二分法递归查找正序排列数组
//输入:待查找数组,头指针,尾指针,待查找元素
//输出:待查找元素的位置或0
public int recBinarySearch(int[] arrInAscendingOrder, int front, int rear, int elementToFind) {
    int middle = (front + rear) / 2; //中间位置
    //结束递归的条件
    if (middle == front) {
        if (arrInAscendingOrder[front] == elementToFind) return middle;
        else return -1; //避免死循环
    }
    if (middle == rear) {
        if (arrInAscendingOrder[middle] == elementToFind) return middle;
        else return -1; // 避免数组越界
    }
    //递归
    if (arrInAscendingOrder[middle] > elementToFind) return recBinarySearch(arrInAscendingOrder, front, middle, elementToFind);
    if (arrInAscendingOrder[middle] < elementToFind)  return recBinarySearch(arrInAscendingOrder, middle + 1, rear, elementToFind);
    if (arrInAscendingOrder[middle] == elementToFind) return middle;
    return -1;
}

非递归方法实现

//二分法非递归查找正序排列数组
//输入:待查找数组,待查找元素
//输出:待查找元素的位置或0
public int nonRecBinarySearch(int[] arrInAscendingOrder, int element) {
    int front = 0; // 头指针
    int rear = arrInAscendingOrder.length; // 尾指针
    int middle = 0; // 中间指针
    while (true) {
        middle = (front + rear) / 2;
        if (arrInAscendingOrder[middle] != element) {
            if (arrInAscendingOrder[middle] > element) {
                if (front == middle) return -1;
                rear = middle;
            } else {
                if (rear == middle) return -1;
                front = middle + 1;
            }
        } else {
            return middle;
        }
    }
}

后记

为什么我写完之后感觉递归比非递归好写多了……虽然空间占用上可能会爆炸……作为一个student我要好好珍惜暂时不用考虑这个问题的时光_(:з」∠)_

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值