三种静态查找算法:顺序、二分/折半、索引/分块查找

转自
https://blog.csdn.net/u011489043/article/details/78683856
终于找了个时间,把三种静态查找算法简单总结了一下,与大家分享讨论。

1、顺序查找

1.1简介

顺序查找是在一个已知无(或有序)序队列中找出与给定关键字相同的数的具体位置。原理是让关键字与队列中的数逐个比较,直到找出与给定关键字相同的数为止。
代码实现

public static int orderSearch(int arr[], int target) {
        for (int i = 0; i < arr.length; i++)
            if (arr[i] == target)
                return i;
        return -1;
    }

1.2性能分析

时间复杂度O(n)

2、二分/折半查找

2.1简介

二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入删除困难。
因此,折半查找方法适用于不经常变动而查找频繁的有序列表
两个条件:1)序列有序;2)可以随机访问
  
查找过程
首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
  
代码实现

public static int biSearch(int arr[], int target) {
        int low = 0, high = arr.length - 1;
        int mid;
        while (low <= high) {
            mid = low + (high - low) / 2;
            if (arr[mid] == target)
                return mid;
            else if (arr[mid] < target)
                low = mid + 1;
            else
                high = mid - 1;
        }
        return -1;
    }

2.2性能分析

时间复杂度:
因为二分查找每次排除掉一半的不适合值,所以对于n个元素的情况:

一次二分剩下:n/2 
两次二分剩下:n/2/2 = n/4 
……. 
m次二分剩下:n/(2^m)
在最坏情况下是在排除到只剩下最后一个值之后得到结果,即
n/(2^m)=1

所以由上式可得 : 2^m=n

进而可求出时间复杂度为: log2(n)

3、分块/索引查找

3.1简介

分块查找是折半查找和顺序查找的一种改进方法,分块查找由于只要求索引表是有序的,对块内节点没有排序要求(块内无序,块间有序),因此特别适合于节点动态变化的情况。

折半查找虽然具有很好的性能,但其前提条件时线性表顺序存储而且按照关键码排序,这一前提条件在结点树很大且表元素动态变化时是难以满足的。而顺序查找可以解决表元素动态变化的要求,但查找效率很低。如果既要保持对线性表的查找具有较快的速度,又要能够满足表元素动态变化的要求,则可采用分块查找的方法。

当增加或减少节以及节点的关键码改变时,只需将该节点调整到所在的块即可。在空间复杂性上,分块查找的主要代价是增加了一个辅助数组。
  
方法描述
分块查找要求把一个大的线性表分解成若干块,每块中的节点可以任意存放,但块与块之间必须排序。假设是按关键码值非递减的,那么这种块与块之间必须满足已排序要求,实际上就是对于任意的i,第i块中的所有节点的关键码值都必须小于第i+1块中的所有节点的关键码值。还要建立一个索引表(索引表中为每一块都设置索引项,每一个索引项都包含两个内容)

  • 该块的起始地址
  • 该块中最大的元素

比如:

image

显然,索引表是按关键字非递减顺序排列的。
一般先用二分查找索引表,确定需要查找的关键字在哪一块,然后再在相应的块内用顺序查找。
  
代码实现

  public boolean search(int data) {
        int i = binarysearch(data);// 先二分查找确定在哪个块
        for (int j = 0; j < list[i].size(); j++) {// 然后顺序查找在该块内哪个位置
            if (data == (int) list[i].get(j)) {
                System.out.println(String.format("查找元素为  %d 第: %d块  第%d个 元素",data, i + 1, j + 1));
                return true;
            }
        }
        return false;
    }

    /**
     * 二分查找
     */
    private int binarysearch(int value) {
        int start = 0;
        int end = index.length;
        int mid = -1;
        while (start <= end) {
            mid = start + (end - start) / 2;
            if (index[mid] > value) {
                end = mid - 1;
            } else {
                start = mid + 1;// 如果相等,也插入后面
            }
        }
        return start;
    } 

3.2性能分析

这种带索引表的分块有序表查找的时间性能取决于两步查找时间之和:如前面所述,第一步可以采用简单顺序查找和折半查找之一进行。第二步只能采用简单顺序查找,但由于子表的长度较原表的长度小。因此,其时间性能介于顺序查找和折半查找之间。

假设索引表有n个元素,每块含有s个元素,平均查找长度为:ASL=(n/s+s)/2 +1,时间复杂度为O(n)~O(log2n)

3.3分块查找的优点

分块查找的优点是:
①在表中插入或删除一个记录时,只要找到该记录所属的块,就在该块内进行插入和删除运算。
②因块内记录的存放是任意的,所以插入或删除比较容易,无须移动大量记录。
分块查找的主要代价是增加一个辅助数组的存储空间和将初始表分块排序的运算。

4、综合比较

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/csdnlijingran/article/details/83537232