欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

常用查找算法

程序员文章站 2022-07-12 14:51:00
...

查找算法可分为两种:无序查找有序查找,顾名思义,无序查找就是查找数列中的数是无序的,有序查找要求所查找数列是已经按照一定的规律排好序了,常见算法中大多都是无序查找。下面一一介绍几种常见的查找算法。

1. 顺序查找

  • 类型:无序查找。
  • 基本思想:
    从数据列中的一段开始(通常是起始位置),顺序扫描,依次比较所扫描数和目标值,如果相等则查找成功。若扫描结束仍没有找到那么就查找失败。
  • 复杂度分析:
平均查找长度 时间复杂度
(n+1)/2 O(n)
  • 示例代码:
   public static int sequenceSearch(int[] arr, int target) {
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == target) {
                return i;
            }
        }
        return -1;
    }

2. 二分查找(折半查找)

  • 类型:有序查找。
  • 基本思想:
    用给定值k先与中间结点的关键字比较,中间结点把线形表分成两个子表,若相等则查找成功;若不相等,再根据k与该中间结点关键字的比较结果确定下一步查找哪个子表,这样递归进行,直到查找到或查找结束发现表中没有这样的结点。
  • 复杂度分析:
平均查找长度 时间复杂度
log2(n+1) O(log2n)
  • 示例代码:
   //二分查找 非递归
   public static int binarySearch(int[] arr, int target) {
        SortUtil.quickSort(arr, 0, arr.length - 1);
        int low = 0, high = arr.length - 1, mid;
        while (low <= high) {
            if (target == arr[low]) {
                return low;
            }
            if (target == arr[high]) {
                return high;
            }
            mid = (low + high) / 2;
            if (target == arr[mid]) {
                return mid;
            } else if (target > arr[mid]) {
                low = mid + 1;
            } else {
                high = mid - 1;
            }
        }
        return -1;
    }

3. 插值查找

  • 类型:有序查找。
  • 基本思想:
    是二分查找的一种优化,将查找点改进为自适应选择以提高查找效率。(将mid = (low + high) /2取中值的取法换成了mid = low + (target - arr[low]) / (arr[high] - arr[low] * (high - low))
  • 时间复杂度分析: O(log2(log2n))
  • 示例代码:
   public static int insertionSearch(int[] arr, int target, int low, int high) {
        if (low <= high) {
            if (target == arr[low]) {
                return low;
            }
            if (target == arr[high]) {
                return high;
            }
            int mid = low + (target - arr[low]) / (arr[high] - arr[low] * (high - low));
            if (target == arr[mid]) {
                return mid;
            } else if (target < arr[mid]) {
                return insertionSearch(arr, target, low, mid - 1);
            } else {
                return insertionSearch(arr, target, mid + 1, high);
            }
        }
        return -1;
    }

3. 斐波那契查找

  • 类型:有序查找。
  • 斐波那契数列:相信很多同学都早已有所耳闻,即1,1,2,3,5,8,13...,从第三个数开始,后面的数都等于前两个数之和,而斐波那契查找就是利用的斐波那契数列来实现查找的。
  • 基本思想:
    同样的是,它是二分查找的一个优化,它是根据斐波那契序列的特点对有序表进行分割。他要求开始表中记录的个数为某个斐波那契数小1,及n=F(k)-1;然后需要装填一个长度为n的新数组,且mid = low + fib(k - 1) - 1,k为fib(k) - 1刚好大于原数组长度的那个值。

开始将k值与第F(k-1)位置的记录进行比较(及mid=low+F(k-1)-1),比较结果也分为三种
1)相等,mid位置的元素即为所求
2)>,low=mid+1,k-=2;
说明:low=mid+1说明待查找的元素在[mid+1,high]范围内,k-=2 说明范围[mid+1,high]内的元素个数为n-(F(k-1))= Fk-1-F(k-1)=Fk-F(k-1)-1=F(k-2)-1个,所以可以递归的应用斐波那契查找。
3)<,high=mid-1,k-=1。
说明:low=mid+1说明待查找的元素在[low,mid-1]范围内,k-=1 说明范围[low,mid-1]内的元素个数为F(k-1)-1个,所以可以递归 的应用斐波那契查找。

  • 时间复杂度:O(log2n)。
    由于时间有些仓促,下面的查找算法尚未理解透彻,暂时只记录基本思想,示例代码后面有空补上 = =。

4. 树表查找

顾名思义,就是将所查找数列构建成一颗树,其中最常见的是构建成一颗二叉查找树(左子节点的值均小于父节点的值,右子节点的值均大于父节点的值),然后通过遍历比较得出查找结果。