二分、值插、斐波那契查找

二分查找

二分查找的思路分析

  • 首先确定该数组的中间的下标

    • mid= (left +right)/ 2
  • 然后让需要查找的数findVal和a[mid]比较

    • findVal> ar[mid],说明你要查找的数在mid的右边,因此需要递归的向右查找
    • findVal< ar[mid],说明你要查找的数在mid的左边,因此需要递归的向左查找
    • findVal== ar[mid]说明找到,就返回
  • 什么时候我们需要结束递归。

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

使用二分查找的前提是该数组是有序的。

查找一个不重复的值

public static void main(String[] args) {
    int[] arr = {1,23,45,67,79,90,212}
    int i = erFenSearch(arr, 0, arr.length-1, 1);
    System.out.println(i);
}

public static int erFenSearch(int[] arr,int left, int right,int findValue){
    if (left > right){
        return -1;
    }
    int mid = (left + right) / 2 ;
    int midValue = arr[mid];
    if (findValue < midValue){
        return erFenSearch(arr, left, mid - 1, findValue);
    }else if (findValue > midValue){
        return erFenSearch(arr, mid + 1, right, findValue);
    }else {
        return mid;
    }
}

查找所有的下标

public static void main(String[] args) {
    int[] arr = {1,23,46,89,89,89,89,122,165,267};
    List<Integer> list = erFenSearch1(arr, 0, arr.length - 1, 89);
    System.out.println(list);
}

public static List<Integer> erFenSearch1(int[] arr, int left, int right, int findValue){
    if (left > right){
        return new ArrayList<Integer>();
    }
    int mid = (left + right) / 2 ;
    int midValue = arr[mid];
    if (findValue < midValue){
        return erFenSearch1(arr, left, mid - 1, findValue);
    }else if (findValue > midValue){
        return erFenSearch1(arr, mid + 1, right, findValue);
    }else {
        List<Integer> list = new ArrayList<Integer>();
        int temp = mid - 1;
        while (true){
            if (temp < 0 || arr[temp] != findValue){
                break;
            }
            list.add(temp);
            temp--;
        }
        list.add(mid);
        temp = mid + 1;
        while (true){
            if (temp > arr.length - 1 || arr[temp] != findValue){
                break;
            }
            list.add(temp);
            temp++;
        }
        return list;
    }
}

插值查找

要求数组有序,适用于数据分布均匀的情况;

image-20200601101014271

public static void main(String[] args) {
    int[] arr = new int[100];
    for (int i = 0; i < arr.length; i++) {
        arr[i] = i + 1;
    }
    int i = insertValueSearch(arr, 0, arr.length - 1, 99);
    System.out.println(i);

}

public static int insertValueSearch(int[] arr,int left, int right,int findValue){
    if (left > right || findValue < arr[0] || findValue > arr[arr.length-1]){
        return -1;
    }
    int mid = left + (right - left) * (findValue - arr[left]) / (arr[right] - arr[left]);
    int midValue = arr[mid];
    if (findValue > midValue){
        return insertValueSearch(arr, mid + 1, right, findValue);
    }else if (findValue < midValue){
        return insertValueSearch(arr, left, mid - 1, findValue);
    }else {
        return mid;
    }
}

斐波那契查找

斐波那契数列{1,1,2,3,5, 8, 13,21, 34, 55}发现斐波那契数列的两个相邻数的比例,无限接近黄金分割值0.618

核心f(k) =f(k - 1) + f(k - 2) ====>>> f(k) - 1 =( f(k - 1) - 1)+(f(k - 2) - 1) + 1

public class FibSearch {
    public static int maxSize = 20;
    public static void main(String[] args) {
        int[] arr = {1,8,10,89,1000,1024};
        System.out.println(fibSearch(arr,1));
    }
    //制造斐波那契数列
    public static int[] fib(){
        int[] f = new int[maxSize];
        f[0] = 1;
        f[1] = 1;
        for (int i = 2; i < maxSize; i++) {
            f[i] = f[i - 1] + f[i - 2];
        }
        return f;
    }
    //斐波那契查找方法
    public static int fibSearch(int[] arr,int key){
        int low = 0;
        int high =arr.length - 1;
        int k = 0;//表示斐波那契分割数值的下标
        int mid = 0;
        //获取斐波那契数列
        int[] f = fib();
        //获取到比arr大的斐波那契分割数值的下标
        while (high > f[k] - 1){
            k++;
        }
        //因为f[k]值可能大于arr的长度,因此我们需要使用Arrays类,构造一个新的数组,并指向temp[]不足的部分会使用最大值填充
        int[] temp = Arrays.copyOf(arr,f[k]);
        for (int i = high + 1; i < temp.length; i++) {
            temp[i] = temp[high];
        }

        while (low <= high){
            mid = low + f[k - 1] - 1;
            if (key < temp[mid]){
                high = mid - 1;
                k--;//f(k) =f(k - 1)高 + f(k - 2)低
            }else if (key > temp[mid]){
                low = mid + 1;
                k -= 2;//f(k) =f(k - 1)高 + f(k - 2)低
            }else {
                if (high < mid){
                    return high;
                }else {
                    return mid;
                }
            }
        }
        return -1;
    }
}
原文地址:https://www.cnblogs.com/chaostudy/p/13024548.html