zoukankan      html  css  js  c++  java
  • 数据结构与算法(九)——查找

    一、概述

    1、介绍

      静态查找:数据集合稳定,不会添加,删除元素的查找操作。
      动态查找:数据集合在查找的过程中会添加,删除元素的查找操作。

    2、查找方式

      静态查找:不妨使用线性表结构组织数据,可以使用顺序查找算法;若对关键词排序,可以使用折半查找算法或斐波那契查找算法。
      动态查找:可以使用二叉排序树的查找技术;还可以使用散列表结构来解决查找问题。
      无序查找:顺序查找O(n)。
      有序查找:折半查找O(log2n)、插值查找O(log2n)、斐波那契查找O(log2n)。三种有序表的查找本质上是分割点的选择不同,各有优劣,实际开发可根据数据的特点综合考虑再做决定。

    3、平均查找长度(Average Search Length,ASL)

      需和指定key进行比较的关键字的个数的期望值,成为查找算法在查找成功时的平均查找长度。
      对于含有 n 个数据元素的查找表,查找成功的平均查找长度为:ASL = Pi*Ci的和。
      Pi:查找表中第 i 个数据元素的概率。
      Ci:找到第 i 个数据元素时已经比较过的次数。

    二、顺序(线性)查找

    1、思想

      从第一个(或者最后一个)记录开始,逐个进行记录的关键字和给定值的比较,若某个记录的关键字和给定值相等,则查找成功。否则查找不成功。

    2、代码

    1 // 顺序查找.O(2n)
    2 public static int orderSearch(int[] arr, int key) {
    3     for (int i = 0; i < arr.length; i++) {
    4         if (arr[i] == key) {
    5             return i;
    6         }
    7     }
    8     return -1;
    9 }

    三、折半(二分)查找

    1、思想

      取中间记录作为比较对象,若给定值与中间记录的关键字相等,则查找成功;若给定值小于中间记录的关键字,则在中间记录左半区继续查找;否则,在右半区查找。不断重复,直到查找成功或者查找失败为止。

    2、代码

      代码示例:返回单个

     1 // 折半查找.O(log2n).方式一
     2 public static int halfSearch(int[] arr, int key) {
     3     int left = 0, right = arr.length - 1, mid;
     4 
     5     while (left <= right) {
     6         mid = (left + right) / 2;
     7 
     8         if (key == arr[mid]) {
     9             return mid;
    10         }
    11 
    12         if (key < arr[mid]) {
    13             right = mid - 1;
    14         } else {
    15             left = mid + 1;
    16         }
    17 
    18     }
    19     return -1;
    20 }
    21 
    22 // 折半查找.方式二
    23 public static int halfSearch2(int[] arr, int key) {
    24     int left = 0, right = arr.length - 1, mid;
    25     mid = (left + right) / 2;
    26 
    27     while (key != arr[mid]) {
    28         if (key < arr[mid]) {
    29             right = mid - 1;
    30         } else {
    31             left = mid + 1;
    32         }
    33 
    34         if (left > right) {
    35             return -1;
    36         }
    37         mid = (left + right) / 2;
    38     }
    39     return mid;
    40 }
    41 
    42 // 折半查找.方式三.递归
    43 public static int halfSearch(int[] arr, int left, int right, int key) {
    44     if (left > right) {
    45         return -1;
    46     }
    47 
    48     int mid = (left + right) / 2;
    49     if (key == arr[mid]) {
    50         return mid;
    51     }
    52 
    53     if (key < arr[mid]) {
    54         return halfSearch(arr, left, mid - 1, key);
    55     } else {
    56         return halfSearch(arr, mid + 1, right, key);
    57     }
    58 }

      代码示例:返回多个

     1 // 折半查找.返回多个 {1, 8, 10, 89, 1000, 1000, 1234}
     2 public static List<Integer> halfSearch2(int[] arr, int left, int right, int key) {
     3     if (left > right) {
     4         return new ArrayList<>();
     5     }
     6 
     7     int mid = (left + right) / 2;
     8     if (key == arr[mid]) {
     9         List<Integer> result = new ArrayList<>();
    10         result.add(mid);
    11 
    12         // 向mid左边扫描
    13         int temp = mid - 1;
    14         while (temp >= 0 && arr[temp] == key) {
    15             result.add(temp);
    16             temp--;
    17         }
    18 
    19         // 向mid右边扫描
    20         temp = mid + 1;
    21         while (temp < arr.length && arr[temp] == key) {
    22             result.add(temp);
    23             temp++;
    24         }
    25 
    26         return result;
    27     }
    28 
    29     if (key < arr[mid]) {
    30         return halfSearch2(arr, left, mid - 1, key);
    31     } else {
    32         return halfSearch2(arr, mid + 1, right, key);
    33     }
    34 }

    四、插值(按比例)查找

    1、思想

      折半查找的改进算法,将折半查找的比例参数1/2改进了,根据关键字在整个有序表中所处的位置,让mid值的变化更靠近关键字key,这样也就间接地减少了比较次数。
      适用于数据量较大,关键字分布较均匀。关键字分布不均匀时,该方法不一定比折半查找好。

    2、代码

     1 // 插值查找.
     2 public static int insertSearch(int[] arr, int key) {
     3     int left = 0, right = arr.length - 1, mid;
     4 
     5     while (left <= right) {
     6         // 按比例改进mid
     7         mid = ((key - arr[left]) / (arr[right] - arr[left]) * (right - left)) + left;
     8 
     9         if (key == arr[mid]) {
    10             return mid;
    11         }
    12 
    13         if (key < arr[mid]) {
    14             right = mid - 1;
    15         } else {
    16             left = mid + 1;
    17         }
    18     }
    19     return -1;
    20 }
    21 
    22 // 插值查找.递归
    23 public static int insertSearch(int[] arr, int left, int right, int key) {
    24     if (left > right || key < arr[0] || key > arr[arr.length - 1]) {
    25         return -1;
    26     }
    27     int mid = ((key - arr[left]) / (arr[right] - arr[left]) * (right - left)) + left;
    28 
    29     if (key == arr[mid]) {
    30         return mid;
    31     }
    32 
    33     if (key < arr[mid]) {
    34         return insertSearch(arr, left, mid - 1, key);
    35     } else {
    36         return insertSearch(arr, mid + 1, right, key);
    37     }
    38 }

    五、斐波那契查找(黄金分割法查找)

    1、思想

      折半查找的改进算法。优化 mid 的位置。

    2、代码

    1  // Fibonacci查找
    2  public static int fibonacciSearch(int[] arr, int key) {
    3  
    4  
    5      return key;
    6  }

    未完成。。。

    作者:Craftsman-L

    本博客所有文章仅用于学习、研究和交流目的,版权归作者所有,欢迎非商业性质转载。

    如果本篇博客给您带来帮助,请作者喝杯咖啡吧!点击下面打赏,您的支持是我最大的动力!

  • 相关阅读:
    DRF (Django REST framework) 框架介绍(2)
    DRF (Django REST framework) 框架介绍(1)
    Django中的Admin站点
    Django中的模板和表单
    Django数据库
    跨站请求伪造CSRF以及Flask中的解决办法
    Flask中的模板,Jinjia2介绍
    Flask中的上下文和flask-script扩展
    化学品撮合交易系统
    化学品产品查询系统解决方案
  • 原文地址:https://www.cnblogs.com/originator/p/14391639.html
Copyright © 2011-2022 走看看