常用查找算法及Java实现

常用算法

顺序查找

顺序查找也称为线形查找,属于无序查找算法。从数据结构线形表的一端开始,顺序扫描,依次将扫描到的结点关键字与给定值k相比较,若相等则表示查找成功;若扫描结束仍没有找到关键字等于k的结点,表示查找失败。

顺序查找的时间复杂度为O(n)。

public class Search {
    public static void main(String[] args) {
        int arr[] = {5, 11, 7, 9, 2, 3, 12, 8, 6, 1, 4, 10};
        search(arr,3);
    }

    /**
     * 顺序查找
     */
    public static int order(int[] arr, int target) {
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == target) {
                return i;
            }
        }
        return -1;
    }
}

二分查找

也称为是折半查找,属于有序查找算法。用给定值k先与中间结点的关键字比较,中间结点把线形表分成两个子表,若相等则查找成功;若不相等,再根据k与该中间结点关键字的比较结果确定下一步查找哪个子表,这样递归进行,直到查找到或查找结束发现表中没有这样的结点。

最坏情况下,关键词比较次数为log2(n+1),且期望时间复杂度为O(log2n);

   /**
     * 常规二分查找
     */
    public static int half(int[] arr, int target) {
        //使数组有序
        Arrays.sort(arr);
        System.out.println(String.format("原数组%s中查找【%s】", Arrays.toString(arr), target));
        int left = 0;
        int right = arr.length - 1;
        while (left <= right) {
            int mid = ((right - left) >> 1) + left;
            if (target > arr[mid]) {
                left = mid + 1;
            } else if (target < arr[mid]) {
                right = mid - 1;
            } else {
                return mid;
            }
        }
        return -1;
    }

    /**
     * 递归二分查找
     * @param high len-1
     */
    public static int halfByRecurse(int[] arr, int target, int low, int high) {
        int mid = ((high - low) >> 1) + low;
        if (low == high) {
            return -1;
        }
        if (target == arr[mid]) {
            return mid;
        }
        if (target > arr[mid]) {
            return halfByRecurse(arr, target, mid + 1, high);
        }
        if (target < arr[mid]) {
            return halfByRecurse(arr, target, low, mid - 1);
        }
        return -1;
    }

插值查找

基于二分查找算法,将查找点的选择改进为自适应选择,可以提高查找效率。当然,差值查找也属于有序查找
代码基本上和二分查找一样,有修改的地方就是mid的获取

在二分查找中$mid=$$low+high \over {2}$ 可改写成 $mid =low + $ $ {high-low} \over {2}$

也就是说我们的mid每次都是折中的取,但是对于一些均匀分布的有序表,这样做感觉有些费时,比如找字典的时候,找a这个字母,我们肯定不会从中间开始,而是偏向于字典前面一些开始。

插值查找就是基于这样的思想
我们对1/2进行改进:

$mid=low+$$key-a[low] \over a[high]=a[low]$$(high-low)$

key就是要查找的值,数组a是有序表

简单的理解就是计算出key所占比,然后更好地找到key所在的区间范围
但是对于极端分布的数组,插值查找的效率就大打折扣了
比如

int a[7]={0,1,2,100,102,1000,10000}

Java代码实现

    /**
     * 插值查找
     */
    public static int insert(int[] arr, int target) {
        //使数组有序
        Arrays.sort(arr);
        System.out.println(String.format("原数组%s中进行插值查找【%s】", Arrays.toString(arr), target));
        int left = 0;
        int right = arr.length - 1;
        while (left <= right) {
            int mid = left + (right - left) * ((target - arr[left]) / (arr[right] - arr[left]));
            if (target > arr[mid]) {
                left = mid + 1;
            } else if (target < arr[mid]) {
                right = mid - 1;
            } else {
                return mid;
            }
        }
        return -1;
    }

    /**
     * 递归插值查找
     *
     * @param high len-1
     */
    public static int insertByRecurse(int[] arr, int target, int low, int high) {
        int mid = low + (high - low) * ((target - arr[low]) / (arr[high] - arr[low]));
        if (low <= high) {
            if (target == arr[mid]) {
                return mid;
            } else if (target > arr[mid]) {
                return insertByRecurse(arr, target, mid + 1, high);
            } else {
                return insertByRecurse(arr, target, low, mid - 1);
            }
        } else {
            return -1;
        }
    }

斐波那契查找

 斐波那契数列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89…….(从第三个数开始,后边每一个数都是前两个数的和)。然后我们会发现,随着斐波那契数列的递增,前后两个数的比值会越来越接近黄金分割0.618,利用这个特性,我们就可以将黄金比例运用到查找技术中。

也是二分查找的一种提升算法,通过运用黄金比例的概念在数列中选择查找点进行查找,提高查找效率。同样地,斐波那契查找也属于一种有序查找算法。

树表查找

分块查找

哈希查找

posted @ 2020-07-30 20:05  unclezs  阅读(390)  评论(0)    收藏  举报