zoukankan      html  css  js  c++  java
  • 【二分搜索树】1、二分查找法的实现

    简单记录 - bobo老师的玩转算法系列–玩转算法 - 二分搜索树

    二叉搜索树 Binary Search Tree

    查找问题 Searching Problem

    查找问题是计算机中非常重要的基础问题

    二分查找法 Binary Search

    v

    <v v >v

    对于有序数列,才能使用二分查找法 (排序的作用)

    二分查找法的思想在1946年提出。
    第一个没有bug的二分查找法在1962年才出现。

    操作:实现二分查找法

    非递归的二分查找算法 BinarySearch.java

    package algo;
    
    // 非递归的二分查找算法
    public class BinarySearch {
    
        // 我们的算法类不允许产生任何实例
        private BinarySearch() {}
    
        // 二分查找法,在有序数组arr中,查找target
        // 如果找到target,返回相应的索引index
        // 如果没有找到target,返回-1
        public static int find(Comparable[] arr, Comparable target) {
    
            // 在arr[l...r]之中查找target
            int l = 0, r = arr.length-1;
            while( l <= r ){
    
                //int mid = (l + r)/2;
                // 防止极端情况下的整形溢出,使用下面的逻辑求出mid
                int mid = l + (r-l)/2;
    
                if( arr[mid].compareTo(target) == 0 )
                    return mid;
    
                if( arr[mid].compareTo(target) > 0 )
                    r = mid - 1;
                else
                    l = mid + 1;
            }
    
            return -1;
        }
    
        // 测试非递归的二分查找算法
        public static void main(String[] args) {
    
            int N = 1000000;
            Integer[] arr = new Integer[N];
            for(int i = 0 ; i < N ; i ++)
                arr[i] = new Integer(i);
    
            // 对于我们的待查找数组[0...N)
            // 对[0...N)区间的数值使用二分查找,最终结果应该就是数字本身
            // 对[N...2*N)区间的数值使用二分查找,因为这些数字不在arr中,结果为-1
            for(int i = 0 ; i < 2*N ; i ++) {
                int v = BinarySearch.find(arr, new Integer(i));
                if (i < N)
                    assert v == i;
                else
                    assert v == -1;
            }
    
            return;
        }
    }
    
    

    使用递归地方式实现二分查找法

    递归实现通常思维起来更容易。
    递归在性能上会略差。

    练习:实现二分查找法的递归实现

    package algo;
    
    // 递归的二分查找算法
    public class BinarySearch2 {
    
        // 我们的算法类不允许产生任何实例
        private BinarySearch2() {}
    
        private static int find(Comparable[] arr, int l, int r, Comparable target){
    
            if( l > r )
                return -1;
    
            //int mid = (l+r)/2;
            // 防止极端情况下的整形溢出,使用下面的逻辑求出mid
            int mid = l + (r-l)/2;
    
            if( arr[mid].compareTo(target) == 0 )
                return mid;
            else if( arr[mid].compareTo(target) > 0 )
                return find(arr, l, mid-1, target);
            else
                return find(arr, mid+1, r, target);
        }
    
        // 二分查找法,在有序数组arr中,查找target
        // 如果找到target,返回相应的索引index
        // 如果没有找到target,返回-1
        public static int find(Comparable[] arr, Comparable target) {
    
            return find(arr, 0, arr.length-1, target);
        }
    
        // 测试递归的二分查找算法
        public static void main(String[] args) {
    
            int N = 1000000;
            Integer[] arr = new Integer[N];
            for(int i = 0 ; i < N ; i ++)
                arr[i] = new Integer(i);
    
            // 对于我们的待查找数组[0...N)
            // 对[0...N)区间的数值使用二分查找,最终结果应该就是数字本身
            // 对[N...2*N)区间的数值使用二分查找,因为这些数字不在arr中,结果为-1
            for(int i = 0 ; i < 2*N ; i ++) {
                int v = BinarySearch2.find(arr, new Integer(i));
                if (i < N)
                    assert v == i;
                else
                    assert v == -1;
            }
    
            return;
        }
    }
    
    

    比较

    Main

    package algo;
    
    import algo.BinarySearch;
    import algo.BinarySearch2;
    
    // 比较非递归和递归写法的二分查找的效率
    // 非递归算法在性能上有微弱优势
    public class Main {
    
        private Main(){}
    
        public static void main(String[] args) {
    
            int N = 1000000;
            Integer[] arr = new Integer[N];
            for(int i = 0 ; i < N ; i ++)
                arr[i] = new Integer(i);
    
    
            // 测试非递归二分查找法
            long startTime = System.currentTimeMillis();
    
            // 对于我们的待查找数组[0...N)
            // 对[0...N)区间的数值使用二分查找,最终结果应该就是数字本身
            // 对[N...2*N)区间的数值使用二分查找,因为这些数字不在arr中,结果为-1
            for(int i = 0 ; i < 2*N ; i ++) {
                int v = BinarySearch.find(arr, new Integer(i));
                if (i < N)
                    assert v == i;
                else
                    assert v == -1;
            }
            long endTime = System.currentTimeMillis();
    
            System.out.println("Binary Search (Without Recursion): " + (endTime - startTime) + "ms");
    
    
            // 测试递归的二分查找法
            startTime = System.currentTimeMillis();
    
            // 对于我们的待查找数组[0...N)
            // 对[0...N)区间的数值使用二分查找,最终结果应该就是数字本身
            // 对[N...2*N)区间的数值使用二分查找,因为这些数字不在arr中,结果为-1
            for(int i = 0 ; i < 2*N ; i ++) {
                int v = BinarySearch2.find(arr, new Integer(i));
                if (i < N)
                    assert v == i;
                else
                    assert v == -1;
            }
            endTime = System.currentTimeMillis();
            System.out.println("Binary Search (With Recursion): " + (endTime - startTime) + "ms");
    
        }
    }
    
    
    D:Environmentsjdk-11.0.2injava.exe -javaagent:D:JavaideaIU-2019.2.winlibidea_rt.jar=9455:D:JavaideaIU-2019.2.winin -Dfile.encoding=UTF-8 -classpath D:IdeaProjectsimoocLearning-Algorithms5-Binary-Search-Treeoutproduction1-Binary-Search algo.Main
    Binary Search (Without Recursion): 337ms
    Binary Search (With Recursion): 514ms
    
    Process finished with exit code 0
    
    

    比较非递归和递归写法的二分查找的效率
    非递归算法在性能上有微弱优势

  • 相关阅读:
    python-进程池实例
    python-进程通过队列模拟数据的下载
    python-多进程模板
    python-多线程同步中创建互斥锁解决资源竞争的问题
    CentOS6.5配置网络
    解决CentOS系统Yum出现"Cannot find a valid baseurl for repo"问题
    CentOS 6.5安装图形界面
    Centos安装git
    Web前端优化,提高加载速度
    谁说写代码的不懂生活
  • 原文地址:https://www.cnblogs.com/liuawen/p/12854054.html
Copyright © 2011-2022 走看看