二分查找法

链式薄雾
• 阅读 1053

(一)前言

刚学完二分查找法,虽然该方法很简单,但是还是很有很多坑值得记录一下。

(二)方法介绍

二分查找法的时间复杂度为对数阶,所以他相对于顺序查找法来说效率较高。

(三)代码分析

这里我决定分块阐述,不直接把代码端上来了。应为我们知道,这里可能会有两种情况,一种是我们只查询单个数的索引,它没有重复的数据;另一种则是数组中有重复数据的出现。

(1)单个数据,返回值为int类型的索引

1)main方法准备

这里我们使用了基数排序法(也是对昨天所学的一个复习)对数组排了序,所以最后返回的是排好序的索引结果。

public static void main(String[] args) {
        int[] arr = { 1, 2, 5, 4, 3, 15, 22 };
        BucketSort(arr);
        System.out.println(Arrays.toString(arr));
        ArrayList<Integer> result = binarySearch02(arr, 0, 8, 3);
        System.out.println(result);
    }

2)基数排序法

此方法可以见我上一篇文章的详解,这里不再赘述。

/**
 * 基数排序法
 * 
 * @param arr
 */
private static void BucketSort(int[] arr) {
    int[][] bucket = new int[10][arr.length];
    int[] bucketCounts = new int[10];

    int max = arr[0];
    for (int i = 1; i < arr.length; ++i) {
        if (arr[i] > max) {
            max = arr[i];
        }
    }
    int maxLength = (max + "").length();

    for (int i = 0, n = 1; i < maxLength; ++i, n *= 10) {
        for (int j = 0; j < arr.length; ++j) {
            int digitofElement = arr[j] / n % 10;
            bucket[digitofElement][bucketCounts[digitofElement]] = arr[j];
            bucketCounts[digitofElement]++;
        }
        int index = 0;
        for (int k = 0; k < bucket.length; ++k) {
            if (bucketCounts[k] != 0) {
                for (int l = 0; l < bucketCounts[k]; ++l) {
                    arr[index] = bucket[k][l];
                    index++;
                }
            }
            bucketCounts[k] = 0;
        }

    }
}

3)二分查找核心算法

这里采用了递归而没有使用循环,一方面是对自己递归的一个锻炼,另一个方面递归的效率优于循环。

private static int binarySearch(int[] arr, int left, int right, int value) {
    if (left > right) {
        return -1;
    }
    int mid = (left + right) / 2;
    if (value > arr[mid]) {
        return binarySearch(arr, mid + 1, right, value);
    } else if (value < arr[mid]) {
        return binarySearch(arr, left, mid - 1, value);
    } else {
        return mid;
    }
}
  • 首先,我们需要给方法传参(arr数组,left为左索引,right为右索引,value为索引值),记住:递归的一个十分十分关键的一点,就是退出条件,如果没有退出条件,他会进入死循环,出现StackOverflowError错误。
  • 这里我们判断递归出去的条件是要么找到此数,要么没找到。如果没找到,那么最后跳出条件一定是 left > right。但如果找到那么最后跳出的就是mid参数。
  • 如果不再跳出之列,那么最后进入二级判断:是往左找还是往右找的问题,所以有了这几个if-else判断。

注意:这里也是我在敲代码的时候领悟的一点:使用递归时,如果函数有返回值,那么递归递归调用也必须 return!!!这有这样,在最底层return回来的数据才能被return给调用者。

(2)多个数据返回,返回类型为集合

这里的1)、2)跟前面相差不大,主要是对查找算法的改变。

3)二分查找核心算法

private static ArrayList<Integer> binarySearch02(int[] arr, int left, int right, int value) {
    if (left > right) {
        return new ArrayList<Integer>();
    }
    int mid = (left + right) / 2;
    if (value > arr[mid]) {
        return binarySearch02(arr, mid + 1, right, value);
    } else if (value < arr[mid]) {
        return binarySearch02(arr, left, mid - 1, value);
    } else {
        ArrayList<Integer> list = new ArrayList<>();
        int tmp = mid - 1;
        while (true) {
            if (tmp < 0 || arr[tmp] != value) {
                break;
            }
            list.add(tmp);
            tmp--;
        }
        list.add(mid);
        tmp = mid + 1;
        while (true) {
            if (tmp > arr.length || arr[tmp] != value) {
                break;
            }
            list.add(tmp);
            tmp++;
        }
        return list;
    }
}

改变之处:

  1. 返回值:现在返回一个ArrayList集合,里面放索引
  2. 递归结束返回值:空集合
  3. 最后返回mid位置的数的改进:因为如果找到,那么可能该数左右都有,所以这里用两个while循环将其收入。最后递归返回(本文关键,提高对递归的理解)。
点赞
收藏
评论区
推荐文章
林末 林末
4年前
折半查找-Python版(二分查找)
介绍二分查找也称折半查找(BinarySearch),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。前提必须待查找的序列有序时间复杂度O(log2n)原理1)确定该期间的中间位置K2)将查找的值t与arrayk比较,若相等,查找成功返回此位置;否则确定新的查找区域,继续二分
好买-葡萄 好买-葡萄
3年前
【数据结构与算法】—— 二分查找
1.二分查找的概念二分查找指的是在排好序的数组中,找到目标元素。如果元素存在则返回元素的下标,不存在则返回1.下面以升序为例进行简单描述2.查找过程:取数组中间元素与查找元素target比较。如果target等于中间元素则直接返回中间元素的下标,如果target小于数组中间元素则在数组左边查找,如果target大于数组中间元素则在右边查找。重复以上步骤。
Wesley13 Wesley13
3年前
java 二分查找算法
二分查找又称折半查找,它是一种效率较高的查找方法。将数列按有序(递增或递减)排列,查找过程中采用跳跃式方式查找,即先以有序数列的中点位置为比较对象,如果要找的元素值小于该中点元素,则将待查序列缩小为左半部分,否则为右半部分。通过一次比较,将查找区间缩小一半。它可以明显减少比较次数,提高查找效率。但是,表中的数据元素必
Wesley13 Wesley13
3年前
java 二分法查找
packagecom.test;importjava.util.Arrays;publicclassBinaraySearch{publicstaticintsearch(intkey,inta){intlo0;
东方客主 东方客主
4年前
PHP实现文本快速查找 - 二分查找法
起因先说说事情的起因,最近在分析数据时经常遇到一种场景,代码需要频繁的读某一张数据库的表,比如根据地区ID获取地区名称、根据网站分类ID获取分类名称、根据关键词ID获取关键词等。虽然以上需求都可以在原始建表时,通过冗余数据来解决。但仍有部分业务存的只是关联表的ID,数据分析时需要频繁的查表。所读的表存在共同的特点数据几乎不会变更数据量适中,从一万
九路 九路
4年前
7 二分搜索树的原理与Java源码实现
1折半查找法了解二叉查找树之前,先来看看折半查找法,也叫二分查找法在一个有序的整数数组中(假如是从小到大排序的),如果查找某个元素,返回元素的索引。如下:intarrnewint{1,3,4,6,8,9};在arr数组中查找6这个元素,查到返回对应的索引,没有找到就返回1思想很简单:1先找到数组中间元素ta
九路 九路
4年前
二分查找法的递归和非递归的实现
//二分查找法非递归实现,在一个有序的数组中查找e元素的位置,找不到返回1publicstaticintbinarySearch(intdata,inte){intl0;intrdata.length1;while(l<r){
小恐龙 小恐龙
4年前
彻底搞懂系列B-树、B+树、B-树、B*树
(https://blog.csdn.net/chai471793/article/details/99563704)平衡二叉树概念平衡二叉树是基于二分法的策略提高数据的查找速度的二叉树的数据结构;特点平衡二叉树是采用二分法思维把数据按规则组装成一个树形结构的数据,用这个树形结构的数据减少无关数据的检索,大大
Wesley13 Wesley13
3年前
Java实现的二分查找算法
二分查找又称折半查找,它是一种效率较高的查找方法。折半查找的算法思想是将数列按有序化(递增或递减)排列,查找过程中采用跳跃式方式查找,即先以有序数列的中点位置为比较对象,如果要找的元素值小于该中点元素,则将待查序列缩小为左半部分,否则为右半部分。通过一次比较,将查找区间缩小一半。折半查找是一种高效的查找方法。它可以明显减少比较次数,提高查找效率。但是,
Stella981 Stella981
3年前
Kafka中改进的二分查找算法
最近有学习些Kafak的源码,想给大家分享下Kafak中改进的二分查找算法。二分查找,是每个程序员都应掌握的基础算法,而Kafka是如何改进二分查找来应用于自己的场景中,这很值得我们了解学习。由于Kafak把二分查找应用于索引查找的场景中,所以本文会先对Kafka的日志结构和索引进行简单的介绍。在Kafak中,消息以日志的形式保存,每个日志其实就是一个文
Wesley13 Wesley13
3年前
C#二分查找算法设计实现
C二分查找算法设计实现1.介绍二分查找也称折半查找(BinarySearch),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。(记住了前提要求是顺序存储结构,而且要有序排序,所以说对于一个无序的是没法用二分查找的)2.查找算法过程