zoukankan      html  css  js  c++  java
  • 查找

    顺序查找

      顺序查找是指将序列从头开始遍历,直到找到指定的元素为止。

      在一个元素为n的序列中查找不存在的元素,需要比较n次。顺序查找虽然效率低下,但是却适用于任何序列。

      顺序查找的代码如下:

    1 public static int seqSearch(int[] arr, int val) {
    2     for (int i = 0; i < arr.length; i++) {
    3         if (arr[i] == val) return i;
    4     }
    5     return -1;
    6 }
    seqSearch

      例如,在序列(1, 2, 3, 4, 5, 6, 7, 8, 9)中查找元素7:从1开始比较,直到找到了7所在位标并返回。

      顺序查找一共比较了7次。

    二分查找

      二分查找是指取有序序列中间的元素作为枢轴,枢轴两边被分割为两个子序列,一边比枢轴大,另一边比枢轴小。这样,查找的元素要么为枢轴,要么在其中一个子序列中。每次递归查找时,可以将区间规模大致缩减一半,从而大大加快查找效率。

      在一个元素为n的序列中查找不存在的元素,需要比较log2n次。二分查找只适用于有序序列。

      二分查找的代码如下:

    1 public static int binarySearch(int[] arr, int low, int high, int val) {
    2     if (low > high) return -1;
    3     int mid = (low + high) / 2;
    4     if (arr[mid] == val) return mid;
    5     if (arr[mid] > val)   // 降序则为arr[mid] < val
    6         return binarySearch(arr, low, mid - 1, val);
    7     return binarySearch(arr, mid + 1, high, val);
    8 }
    binarySearch

      例如,在序列(1, 2, 3, 4, 5, 6, 7, 8, 9)中查找元素7:

        a. 找到序列最中间的元素5,5 < 7,需要对右子序列递归查找。

        b. 找到右子序列最中间的元素7,7 = 7,找到元素。

      二分查找一共比较了2次。

    插值查找

      插值查找与二分查找类似。二分查找是以序列中间的元素作为枢轴,即

        

      而插值查找获取枢轴的公式为:

        

      其中,low和high分别是当前序列第一个元素的位标和最后一个元素的位标。

      与二分查找一样,插值查找只适用于有序序列。有序序列越接近等差序列,插值查找的效率越高。

      插值查找的代码如下:

    1 public static int insertValueSearch(int[] arr, int low, int high, int val) {
    2     // arr[low] > val和arr[high] < val是为了防止val数值过大,导致算出的mid越界
    3     if (low > high || arr[low] > val || arr[high] < val) return -1;
    4     int mid = low + (high - low) * (val - arr[low]) / (arr[high] - arr[low]);
    5     if (arr[mid] == val) return mid;
    6     if (arr[mid] > val)   // 降序则为arr[mid] < val
    7         return insertValueSearch(arr, low, mid - 1, val);
    8     return insertValueSearch(arr, mid + 1, high, val);
    9 }
    insertValueSearch

      例如,在序列(1, 2, 3, 4, 5, 6, 7, 8, 9)中查找元素7:直接代入计算枢轴的值为pivot = 0 + [(7 - 1) / (9 - 1)] * (8 - 0) = 6,而arr[6] = 7。

      插值查找一共比较了1次。

    斐波那契查找

      斐波那契数列的特点为:f(n) = f(n - 1) + f(n - 2)。将该式变化后得到:f(n) - 1 = [f(n - 1) - 1] + [f(n - 2) - 1] + 1。

      斐波那契查找也与二分查找类似,其获取枢轴的公式为:

        

      也就是说,枢轴将有序序列分割为:

        

      斐波那契查找只适用于有序序列,而且在查找前需要保证序列长度为f(k) - 1(如果长度不为f(k) - 1则需要扩容,其扩容的空间使用原序列最后一个元素填充)。

      斐波那契查找的代码如下:

     1 public static int fibonacciSearch(int[] arr, int val) {
     2     int low = 0, high = arr.length - 1, mid;
     3     // 找到第一个满足f(k) - 1 >= arr.length的k
     4     int k = 1;
     5     while (f.get(k) - 1 < arr.length) k++;
     6     // 扩容
     7     int[] temp = Arrays.copyOf(arr, f.get(k) - 1);
     8     for (int i = arr.length; i < temp.length; i++) temp[i] = arr[arr.length - 1];
     9     while (low <= high) {
    10         mid = low + f.get(k - 1) - 1;
    11         if (val < temp[mid]) {   // 降序则为val > temp[mid]
    12             high = mid - 1;
    13             k--;
    14         } else if (val > temp[mid]) {   // 降序则为val < temp[mid]
    15             low = mid + 1;
    16             k -= 2;
    17         } else {
    18             if (mid <= high) return mid;
    19             return high;
    20         }
    21     }
    22     return -1;
    23 }
    fibonacciSearch

      例如,在序列(1, 2, 3, 4, 5, 6, 7, 8, 9)中查找元素7:

        a. 原序列长度为9 < f(6) - 1 = 12,所以需要扩容到长度为12,且使用元素9填充,序列变为(1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9)。此时,k = 6。

        b. 枢轴pivot = 0 + f(6 - 1) - 1 = 7,arr[pivot] =  8 > 7,所以7位于左子序列(0, 6)中。此时,k = 5。

        c. 枢轴pivot = 0 + f(5 - 1) - 1 = 4,arr[pivot] = 5 < 7,所以7位于右子序列(5, 6)中。此时,k = 3。

        d. 枢轴pivot = 5 + f(3 - 1) - 1 = 6,arr[pivot] = 7,找到指定元素的位标。

      斐波那契查找一共比较了3次。

  • 相关阅读:
    关于表格
    split函数
    javac classpath和java classpath
    ORA01460: 转换请求无法实现或不合理 的原因
    业务流程学习(1)
    启动oracle10监听器错误:本地计算机上的OracleOraDb10g_home1TNSListener服务启动后又停止了 解决方案
    CF1594F. Ideal Farm
    CF1373G. Pawns
    CF1373F. Network Coverage
    CF1515F. Phoenix and Earthquake
  • 原文地址:https://www.cnblogs.com/lqkStudy/p/11594709.html
Copyright © 2011-2022 走看看