二分查找

(## 二分查找 ##

  1. 二分查找与一般查找相比,为什么要快?
  2. 二分查找的实现原理是什么?
  3. 二分查找的具体实现以及实例应用
  4. 二分查找的扩展(面向对象的程序设计)

1、二分查找与一般查找相比,为什么要快?

一般查找算法(从头到尾依次比较)

public static int rank(int key , int[] arr){
    for(int index = 0 ; index < arr.length ; index++){
        if(arr[index] == key){
            return index;
        }
        return -1;
    }
}

这种暴力实现处理大量输入非常慢。
然而,二分查找之所以快,是因为它只需要检查很少几个条目(相较于数组的大小来说),就可以找到目标元素(或者确认目标元素不存在)。


2、二分查找的实现原理是什么?

原理图
二分查找原理图


3、二分查找的具体实现以及实例应用

开发用例:白名单过滤

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Scanner;

public class BinarySearch {
    /**
     * 二分查找
     *
     * @param key 要查找的整数键
     * @param arr 数组必须是有序的
     * @return 如果该整数键存在于数组中,则返回它的索引,否则返回-1
     */
    public static int rank(int key, int[] arr) {
        int lo = 0;
        int hi = arr.length - 1;
        while (lo <= hi) {
            int mid = lo + ((hi - lo) >> 1);//①:a>>n相当于a/2^n。②:此处有坑,不要图快用加法,会溢出。即:mid = (lo + hi) >> 1;③、注意 >> 的优先级别低于 + ,也就是说先执行 + ,在执行 >>
            if (key < arr[mid]) {
                hi = mid - 1;
            } else if (key > arr[mid]) {
                lo = mid + 1;
            } else {
                return mid;
            }
        }
        return -1;
    }

    /**
     * 开发用例:白名单过滤
     * 过滤掉标准输入中的所有存在于白名单中的条目,仅将不在白名单上的整数打印到标准输出中
     * @param args
     */
    public static void main(String[] args) {
        int key;
        int[] whiteList = {10,77,12,16,98,23,48,57,29,54,33,68,11,84,18};
        Arrays.sort(whiteList);
        Scanner in = new Scanner(new BufferedReader(new InputStreamReader(System.in)));
        while(in.hasNext()){
            key = in.nextInt();
            if(rank(key,whiteList) < 0){
                System.out.println(key);
            }
        }
    }
}

4、二分查找的扩展(面向对象的程序设计)

一般来说,算法是某个抽象数据类型的一个实例方法的实现。正如前面白名单的例子就被实现为一个抽象数据类型的用例。它进行了以下操作:

  • 由一组给定的值构造了一个SET(集合)对象;
  • 判定一个给定的值是否存在于该集合中。

这些操作封装在 StaticSETofInts 抽象数据类型中。
将上面二分查找的代码重写为一段面向对象的程序(用于在整数集合中进行查找的一种抽象数据类型
这里写图片描述

典型的用例

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Scanner;

/**
 * 典型用例
 * @author TinyDolphin
 *         2017/5/7 17:13.
 */
public class WhiteList {
    public static void main(String[] args) {
        int[] whiteList = {10,77,12,16,98,23,48,57,29,54,33,68,11,84,18};
        StaticSETofInts staticSETofInts = new StaticSETofInts(whiteList);
        Scanner in = new Scanner(new BufferedReader(new InputStreamReader(System.in)));
        while(in.hasNext()){
            int key = in.nextInt();
            //如果key,不在白名单中,则打印它
            if(!staticSETofInts.contains(key)){
                System.out.println(key);
            }
        }
    }
}

数据类型的实现

import java.util.Arrays;

/**
 * 二分查找--数据类型的实现
 * @author TinyDolphin
 *         2017/5/7 16:37.
 */
public class StaticSETofInts {
    /**
     * 类中内置数组
     */
    private int[] arr;
    /**
     * 数组的大小
     */
    private int size;

    public StaticSETofInts(int[] keys) {
        size = keys.length;
        arr = new int[size];
        System.arraycopy(keys, 0, arr, 0, size); //保护性复制(保护原数组的顺序),此处使用了性能较优的数组复制方法
        Arrays.sort(arr);
    }

    /**
     * 该key是否存在于数组中
     *
     * @param key 查找的key
     * @return 若存在,返回true,否则返回false
     */
    public boolean contains(int key) {
        return rank(key) != -1;
    }

    /**
     * @param key 查找的key
     * @return key所在的位置
     */
    private int rank(int key) {
        int lo = 0;
        int hi = size - 1;
        while (lo <= hi) {
            int mid = lo + (hi - lo) >> 1;//①:a>>n相当于a/2^n。②:此处有坑,不要图快用加法,会溢出。即:mid = (lo + hi) >> 1;
            if (key < arr[mid]) {
                hi = mid - 1;
            } else if (key > arr[mid]) {
                lo = mid + 1;
            } else {
                return mid;
            }
        }
        return -1;
    }
}

使用 Java 的类机制来支持数据的抽象将使我们受益匪浅。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值