二分查找

来源:互联网 发布:vb picturebox 保存 编辑:程序博客网 时间:2024/06/18 10:55

(## 二分查找 ##

  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 0
原创粉丝点击