当前位置 博文首页 > 邱天的henry的博客:第八章 数据结构与算法(四类查找算法)

    邱天的henry的博客:第八章 数据结构与算法(四类查找算法)

    作者:[db:作者] 时间:2021-07-05 22:06

    在java中,我们常用的查找算法有四种:
    (1)顺序(线性)查找
    (2)二分查找/折本查找
    (3)插值查找
    (4)斐波那契查找

    8.1线性查找算法
    有一个数列:{1,8,19,3,1000},判断数列中是否包含此名称【顺序查找】要求:如果找到了,就提示找到,并给出下标值
    @思路:
    遍历如果找到符合条件的值就返回

    public class SeqSearch {
        public static void main(String[] args) {
            int[] arr={23,1,78,9,55};
            int index=seqSearch(arr,78);
            if (index != -1){
                System.out.println("目标值的下标为:"+index);
            }else {
                System.out.println("没有找到目标值");
            }
        }
    
        /**
         * 此方法为找到一个目标值就返回
         * @param arr
         * @param value
         * @return
         */
        private static int seqSearch(int[] arr, int value) {
            for (int i=0;i<arr.length;i++){
                if (arr[i] == value){
                    return i;
                }
            }
            return -1;
        }
    }
    
    

    8.2二分查找算法
    ps:二分查找是对有序数组进行查找
    8.2.1二分查找思路分析
    在这里插入图片描述
    8.2.2实例
    (1)请对一个有序数组进行二分查找 {1,8, 10, 89, 1000, 1234} ,输入一个数看看该数组是否存在此数,并且求出下标,如果没有就提示"没有这个数"。
    (2)说明:增加了找到所有的满足条件的元素下标:
    课后思考题: {1,8, 10, 89, 1000, 1000,1234} 当一个有序数组中,有多个相同的数值时,如何将所有的数值都查找到,比如这里的 1000.

    //二分查找的前提是数组是有序的
    public class BinarySort {
        public static void main(String[] args) {
            int[] arr={1,2,2,2,34,67,88,123};
            List<Integer> integers = binarySort2(arr, 0, arr.length - 1, 2);
            Collections.sort(integers);  //对list集合中元素进行排序后输出
            System.out.println(integers); //(list集合特点:有序可重复指的是输出顺序与插入顺序一致,不是数字之间的大小顺序)
            /*int i = binarySort(arr, 0, arr.length - 1, 2);
            System.out.println(i);*/
        }
    
        /**二分查找(此方法参数一定要传入左右下标,因为需要递归进行局部遍历,左右下标会动态变化)
         * @param arr  传入待查找数组
         * @param left  待比较数组的左下标
         * @param right  待比较数组的右下标
         * @param findVal 待查找值
         */
        public static int binarySort(int[] arr,int left,int right,int findVal){
             if(right < left){  //遍历完数组,没有找到符合值
                 return -1;
             }
             int mid=(left+right)/2;  //求出中间值下标
            int midValue=arr[mid];  //求出中间值
            if (findVal >midValue){  //比中间值大,向右递归
                return binarySort(arr,mid+1,right,findVal);
            }else if (findVal < midValue){
                return binarySort(arr,left,mid-1,findVal);
            }else {
                return mid;  //找到
            }
        }
    
        /**增加条件:查找所有满足条件的元素坐标
         * @param arr
         * @param left
         * @param right
         * @param findVal
         * @return
         */
        public static List<Integer> binarySort2(int[] arr, int left, int right, int findVal){
            ArrayList<Integer> indexs = new ArrayList<>();
            if(right < left){  //遍历完数组,没有找到符合值
                return indexs;
            }
            int mid=(left+right)/2;  //求出中间值下标
            int midValue=arr[mid];  //求出中间值
            if (findVal >midValue){  //比中间值大,向右递归
                return binarySort2(arr,mid+1,right,findVal);
            }else if (findVal < midValue){
                return binarySort2(arr,left,mid-1,findVal);
            }else {
                /*课后思考题: {1,8, 10, 89, 1000, 1000,1234} 当一个有序数组中,
                 * 有多个相同的数值时,如何将所有的数值都查找到,比如这里的 1000
                 * 思路分析
                 * 1. 在找到 mid 索引值,不要马上返回
                 * 2. 向 mid 索引值的左边扫描,将所有满足 1000, 的元素的下标,加入到集合 ArrayList
                 * 3. 向 mid 索引值的右边扫描,将所有满足 1000, 的元素的下标,加入到集合 ArrayList
                 * 4. 将 Arraylist 返回*/
                //向左查找
                int i=mid-1;
                while (true){
                    if (i<0 || arr[i] != findVal){  //因为二分查找法是针对有序的数,如果midVal值符合,
                        break;            //则其他几个数也在临近的位置(要么就查找完毕要么就没有了退出循环),
                    }                       //所以后面的阶数条件是arr[i] !=midVal
                    indexs.add(i);
                    i--;
                }
                indexs.add(mid);  //此时的中间值符合别忘了放入集合中
                //向右查找
                 i=mid+1;
                while (true){
                    if (i>arr.length-1 || arr[i] != findVal){
                        break;
                    }
                    indexs.add(i);
                    i++;
                }
                return indexs;  //返回集合
            }
        }
    
    }
    

    8.3插值查找算法
    (1)插值查找原理介绍:插值查找算法类似于二分查找,不同的是插值查找每
    在这里插入图片描述
    8.3.1插值查找应用实例
    @请对一个有序数组进行插值查找 ,输入一个数看看该数组是否存在此数,并且求出下标,如果没有就提示"没有这个数"。

    //插值查找也是适应有序的数组
    public class InsertValueSort {
        public static void main(String[] args) {
            int[] arr = new int[100];
            for (int i=0;i<100;i++){
                arr[i]=i;
            }
            int i = insertValueSort(arr, 0, arr.length - 1, 10);
            System.out.println(i);
        }
    
        /**
         * @param arr  待查找数组
         * @param left  待查找数组的左边边界索引
         * @param right  待查找数组的右边边界索引
         * @param findNum 待查找的数
         * @return
         */
        public static int insertValueSort(int[] arr,int left,int right,int findNum){
            //System.out.println("----");
            //findNum<arr[0] || findNum>arr[arr.length-1]条件不仅是优化,而且是必要条件
            //防止后面的arr[mid]数组越界(倘若findNum非常大)
            if (left>right || findNum<arr[0] || findNum>arr[arr.length-1]){
                return -1;
            }
            //插值算法求mid
            int mid=left+(right-left)*(findNum-arr[left])/(arr[right]-arr[left]);
            int midValue=arr[mid];
            if (findNum<midValue){  //如果小于就往左边循环
                return insertValueSort(arr,left,mid-1,findNum);
            }else if (findNum>midValue){
                return insertValueSort(arr,mid+1,right,findNum);
            }else {
                return mid;
            }
        }
    }
    

    8.4斐波拉契(黄金分割法)查找算法
    8.4.1斐波拉契查找基本介绍
    (1)黄金分割点是指把一条线段分割为两部分,使其中一部分与全长之比等于另一部分与这部分之比。取其前三位数字的近似值是 0.618。由于按此比例设计的造型十分美丽,因此称为黄金分割,也称为中外比。这是一个神奇的数字,会带来意向不大的效果。
    (2) 斐波那契数列 {1, 1, 2, 3, 5, 8, 13, 21, 34, 55 } 发现斐波那契数列的两个相邻数 的比例,无限接近 黄金分割值0.618
    8.4.2斐波拉契原理
    斐波那契查找原理与前两种相似,仅仅改变了中间结点(mid)的位置,mid 不再是中间或插值得到,而是位于黄金分割点附近,即 mid=low+F(k-1)-1(F 代表斐波那契数列),如下图所示