Java数据结构与算法-查找算法-[day06]

查找算法

线性查找分析和实现

有一个数列:{1, 9, -1, 34, 89, 11},判断数列中是否包含此名称【顺序查找】要求如果找到了,就提示找到,并给出下标值。

public class SeqSearch {
    
    
    public static void main(String[] args) {
    
    
        int arr[] = {
    
    1, 9, -1, 34, 89, 11};//无序数组
        int z = seqSearch(arr, 89);
        if (z == -1){
    
    
            System.out.println("没有找到");
        }else {
    
    
            System.out.println("找到值,下标为" + z);
        }


        int arz[] = {
    
    9,34,11};
        int[] ints = seqzSearch(arr, arz);
        for (int i = 0; i < ints.length; i++) {
    
    
            System.out.print("下标为" +"[" + ints[i] + "]");
        }
    }

    /**
     *  这里我们实现的线性查找是找到一个满足条件的值,就返回
     * @param arr
     * @param value
     * @return
     */
    public static int seqSearch(int[] arr, int value) {
    
    
        //线性查找是逐一比对,发现有相同的值时,就返回下标
        for (int i = 0; i < arr.length; i++) {
    
    
            if (arr[i] == value){
    
    
                return i;
            }
        }
        return -1;
    }

    public static int[] seqzSearch(int[] arr,int[] arz){
    
    
        int seqz[] = new int[arz.length];

        int index = 0;
        for (int i = 0; i < arr.length; i++) {
    
    
            for (int j = 0; j < arz.length; j++) {
    
    
                if (arr[i] == arz[j]){
    
    
                    seqz[index] = i;
                    index++;
                }
            }

        }
        return seqz;
    }

}


二分查找分析与实现

请对一个有序数组进行二分查找 {1,8, 10, 89, 1000, 1234} ,输入一个数看看该数组是否存在此数,并且求出下标,如果没有就提示"没有这个数"。

二分查找的思路分析:

  1. 首先确定该数组的中间的下标 mid = (left + right) / 2

  2. 然后让需要查找的数 findVal 和 arr[mid] 比较
    2.1 findVal > arr[mid] , 说明你要查找的数在mid 的右边, 因此需要递归的向右查找。
    2.2 findVal < arr[mid], 说明你要查找的数在mid 的左边, 因此需要递归的向左查找。
    2.3 findVal == arr[mid] 说明找到,就返回。

什么时候我们需要结束递归.

  • 找到就结束递归。
  • 递归完整个数组,仍然没有找到findVal ,也需要结束递归 当 left > right 就需要退出。

代码实现

//注意:使用二分查找的前提是 该数组是有序的。
public class BinarySearch {
    
    
    public static void main(String[] args) {
    
    
        int arr[] = {
    
    1, 8, 10, 88, 1000, 1234};

        int resIndex = binarySearch(arr, 0, arr.length, 88);
        System.out.println("resIndex=" + resIndex);


    }

    //二分查找算法

    /**
     *
     * @param arr   数组
     * @param left  查找时左边的索引
     * @param right 右边的索引
     * @param findVal   要查找的值
     * @return 如果找到就返回下标, 如果没有找到, 就返回-1
     */
    public static int binarySearch(int[] arr, int left, int right, int findVal) {
    
    

        //当left > right 时,说明递归整个数组,但是没有找到
        if (left > right){
    
    
            return -1;
        }
        int mid = (left + right) / 2;
        int midVal = arr[mid];

        if (findVal > midVal) {
    
     //向 右递归
            return binarySearch(arr, mid + 1, right, findVal);
        } else if (findVal < midVal) {
    
     //向 左递归
            return binarySearch(arr, left, mid - 1, findVal);
        }else {
    
    
            return mid;
        }
    }
}

算法优化

//注意:使用二分查找的前提是 该数组是有序的。
public class BinarySearch {
    
    
    public static void main(String[] args) {
    
    
        int arr[] = {
    
    1, 8, 10, 88, 1000, 1000, 1000, 1000, 1234,1234,6666,6666};

        List<Integer> list = binarySearchz(arr, 0,arr.length - 1, 6666);
        System.out.println(list);


    }

    //二分查找算法

    /**
     *
     * @param arr   数组
     * @param left  查找时左边的索引
     * @param right 右边的索引
     * @param findVal   要查找的值
     * @return 如果找到就返回下标, 如果没有找到, 就返回-1
     */
    public static int binarySearch(int[] arr, int left, int right, int findVal) {
    
    

        //当left > right 时,说明递归整个数组,但是没有找到
        if (left > right){
    
    
            return -1;
        }
        int mid = (left + right) / 2;
        int midVal = arr[mid];

        if (findVal > midVal) {
    
     //向 右递归
            return binarySearch(arr, mid + 1, right, findVal);
        } else if (findVal < midVal) {
    
     //向 左递归
            return binarySearch(arr, left, mid - 1, findVal);
        } else {
    
    
            return mid;
        }
    }

    //思考题
    /*
    题:{1,8,10,89,1000,1000,1234}当一个有序数组中,有多个相同的数值时
    如何将所有的数值都查找到,比如这里的1000

    思路分析:
    1.在找到mid 索引值时,不要马上返回
    2.向mid 索引值得左边扫描,将所有满足 1000的元素下标,加入到集合ArrayList
    3.向mid 索引值的右边扫描,将所有满足 1000的元素下标,加入到集合ArrayList
    4.将ArrayList返回
     */

    public static List<Integer> binarySearchz(int[] arr, int left, int right, int findVal) {
    
    



        //当left > right 时,说明递归整个数组,但是没有找到
        if (left > right){
    
    
            return new ArrayList<Integer>();
        }
        int mid = (left + right) / 2;
        int midVal = arr[mid];

        if (findVal > midVal) {
    
     //向 右递归
            return   binarySearchz(arr, mid + 1, right, findVal);
        } else if (findVal < midVal) {
    
     //向 左递归
            return binarySearchz(arr, left, mid - 1, findVal);
        } else {
    
    

            /*思路分析:
            1.在找到mid 索引值时,不要马上返回
            2.向mid 索引值得左边扫描,将所有满足 1000的元素下标,加入到集合ArrayList
            3.向mid 索引值的右边扫描,将所有满足 1000的元素下标,加入到集合ArrayList
            4.将ArrayList返回*/
            List<Integer> resIndexlist = new ArrayList<Integer>();
            //2.向mid 索引值得左边扫描,将所有满足 1000的元素下标,加入到集合ArrayList
            int temp = mid - 1;
            while (true){
    
    
                if (temp < 0 || arr[temp] != findVal){
    
    //退出
                    break;
                }
                //否则,就把temp 放入到集合resIndexlist中
                resIndexlist.add(temp);
                temp -= 1;//temp左移
            }
            resIndexlist.add(mid);
            //3.向mid 索引值的右边扫描,将所有满足 1000的元素下标,加入到集合ArrayList
            temp = mid + 1;
            while (true){
    
    
                if (temp > arr.length -1 || arr[temp] != findVal){
    
    //退出
                    break;
                }
                //否则,就把temp 放入到集合resIndexlist中
                resIndexlist.add(temp);
                temp += 1;//temp左移

            }
        //    resIndexlist.add(mid);//别忘了把之前找到的放进去
            return resIndexlist;
        }
    }
}

插值查找分析与实现

插值查找原理

  • 插值查找算法类似于二分查找,不同的是插值查找每次从自适应mid处开始查找。

  • 将折半查找中的求mid 索引的公式 , low 表示左边索引left, high表示右边索引right. key
    就是前面我们讲的findVal

在这里插入图片描述

int mid = low + (high - low) * (key - arr[low]) / (arr[high] -
arr[low]) ;/插值索引/

对应前面的代码公式:

int mid = left + (right – left) * (findVal – arr[left]) / (arr[right]
– arr[left])


举例说明插值查找算法 1-100

具体思路:

数组 arr = [1, 2, 3, …, 100]

  • 假如我们需要查找的值 1

  • 使用二分查找的话,我们需要多次递归,才能找到 1

  • 使用插值查找算法: int mid = left + (right – left) * (findVal – arr[left]) / (arr[right] – arr[left])

  • int mid = 0 + (99 - 0) * (1 - 1)/ (100 - 1) = 0 + 99 * 0 / 99 = 0

  • 比如我们查找的值 100

  • int mid = 0 + (99 - 0) * (100 - 1) / (100 - 1) = 0 + 99 * 99 / 99 = 0

  • 99 = 99

综上,插值查找算法 -> 套公式计算即可

猜你喜欢

转载自blog.csdn.net/SwaeLeeUknow/article/details/108738029