目录

数据结构与算法查找算法

数据结构与算法——查找算法

目录


一、查找算法

1.1 分类

  • 线性查找
  • 二分查找
  • 插值查找
  • 斐波那契查找

二、线性查找(SequenceSearch)

2.1 基本思想

逐一比对待排序序列,找出待查找元素的下标。

2.2 线性查找算法实现

代码:

public class SequenceSearch {
    public static void main(String[] args) {
        int arr[] = {8, 9, 1, 7, 2, 3, 5, 4, 6, -1};
        int index = search(arr, 2);
        if (index == -1) {
            System.out.println("序列中不存在该元素。");
        } else {
            System.out.println("该元素下标为:" + index);
        }
    }

    public static int search(int[] arr, int value) {
        //逐一比对待排序序列
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == value) {
                return i;
            }
        }
        return -1;
    }
}

结果:

https://i-blog.csdnimg.cn/blog_migrate/e01202be989c15878f51ae559004a58d.png


三、二分查找(BinarySearch)

3.1 基本思想

先确定有序序列的中间下标,然后向左右两边递归进行二分查找,直到中间下标为 待查找元素的下标 。

3.2 二分查找算法实现

代码:

public class BinarySearch {
    public static void main(String[] args) {
        int arr[] = {-1, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        int index = search(arr, 0, arr.length - 1, 5);
        if (index == -1) {
            System.out.println("序列中不存在该元素。");
        } else {
            System.out.println("该元素下标为:" + index);
        }
    }

    public static int search(int[] arr, int startIndex, int endIndex, int value) {
        if (startIndex > endIndex || value < arr[0] || value > arr[arr.length - 1]) {
            return -1;
        }
        //定义中间元素下标
        int mid = (startIndex + endIndex) / 2;
        //定义中间元素值
        int midVal = arr[mid];

        if (value > midVal) {
            //向右递归
            return search(arr, mid + 1, endIndex, value);
        } else if (value < midVal) {
            //向左递归
            return search(arr, startIndex, mid - 1, value);
        } else {
            return mid;
        }
    }
}

结果:

https://i-blog.csdnimg.cn/blog_migrate/58140020f8b387c5a044f105625499aa.png


四、插值查找(InterpolationSearch)

4.1 基本思想

类似于二分查找,但改变了每次查找的期望索引值。

4.2 期望索引值公式

Expectation = startIndex + (endIndex - startIndex) * (value - arr[startIndex]) / (arr[endIndex] - arr[startIndex])

4.3 插值查找算法实现

代码:

public class InterpolationSearch {
    public static void main(String[] args) {
        int arr[] = {-1, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        int index = search(arr, 0, arr.length - 1, 5);
        if (index == -1) {
            System.out.println("序列中不存在该元素。");
        } else {
            System.out.println("该元素下标为:" + index);
        }
    }

    public static int search(int[] arr, int startIndex, int endIndex, int value) {
        if (startIndex > endIndex || value < arr[0] || value > arr[arr.length - 1]) {
            return -1;
        }
        //定义期望元素下标
        int expectation = startIndex + (endIndex - startIndex) * (value - arr[startIndex]) / (arr[endIndex] - arr[startIndex]);
        //定义期望元素值
        int expectationVal = arr[expectation];

        if (value > expectationVal) {
            //向右递归
            return search(arr, expectationVal + 1, endIndex, value);
        } else if (value < expectationVal) {
            //向左递归
            return search(arr, startIndex, expectationVal - 1, value);
        } else {
            return expectationVal;
        }
    }
}

结果:

https://i-blog.csdnimg.cn/blog_migrate/ee89aa15c8a22521cd23f398e3a669a4.png


五、斐波那契查找(FibonacciSearch)

5.1 基本介绍

斐波那契查找算法又称黄金分割查找算法,黄金分割点是指把一条线段分割成两部分,使其中一部分与全长之比等于另一部分与该部分之比,该比值的近似值为0.618。

相邻两个元素之比无限接近黄金分割值的数列被称为斐波那契数列。

5.2 基本思想

类似于二分查找,但改变了每次查找的期望索引值,该期望索引值位于黄金分割点附近。

5.3 期望索引值公式

Expectation = startIndex + F(k - 1) - 1,F表示斐波那契数列。

  • 由斐波那契数列F(k) = F(k - 1) + F(k - 2)的性质可得:(F(k) - 1) = (F(k - 1) - 1) + (F(k - 2) - 1) + 1,该式说明只要有序序列的长度为F(k) - 1,则可以将该序列分成长度为F(k - 1) - 1和F(k - 2) - 1的两部分,期望索引值的下标为startIndex + F(k - 1) - 1。
  • 当有序序列的长度不为F(k) - 1时,需要将该序列的长度增加至F(k) - 1。

5.4 斐波那契查找算法实现

代码:

public class FibonacciSearch {

    //定义斐波那契数列的长度
    public static int maxSize = 20;

    public static void main(String[] args) {
        int arr[] = {-1, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        int index = search(arr, 5);
        if (index == -1) {
            System.out.println("序列中不存在该元素。");
        } else {
            System.out.println("该元素下标为:" + index);
        }
    }

    public static int search(int[] arr, int value) {
        //定义头指针
        int startIndex = 0;
        //定义尾指针
        int endIndex = arr.length - 1;
        //定义期望元素下标
        int expectation = 0;
        //定义斐波那契分割数值的下标
        int k = 0;
        //定义斐波那契数列
        int[] f = fibonacci();
        //获取斐波那契分割数值
        while (endIndex > f[k] - 1) {
            k++;
        }
        //有序序列长度不足时增加其长度,存入临时数组中,不足部分使用arr数组末尾的值进行填充
        int[] temp = Arrays.copyOf(arr, f[k]);
        for (int i = endIndex + 1; i < temp.length; i++) {
            temp[i] = arr[endIndex];
        }

        while (startIndex <= endIndex) {
            expectation = startIndex + f[k - 1] - 1;
            //定义期望元素值
            int expectationVal = arr[expectation];

            if (value > expectationVal) {
                //向右查找
                startIndex = expectation + 1;
                //右边的有序序列有f[k-2]个元素,可拆分成f[k-2]=f[k-3]+f[k-4],k-2作为新的斐波那契分割数值的下标
                k -= 2;
            } else if (value < expectationVal) {
                //向左查找
                endIndex = expectation - 1;
                //左边的有序序列有f[k-1]个元素,可拆分成f[k-1]=f[k-2]+f[k-3],k-1作为新的斐波那契分割数值的下标
                k--;
            } else {
                //判断查找到的元素下标是否位于增加出的部分,是则返回数组末尾下标
                if (expectation <= endIndex) {
                    return expectation;
                } else {
                    return endIndex;
                }
            }
        }
        return -1;
    }

    //获取斐波那契数列
    public static int[] fibonacci() {
        int[] f = new int[maxSize];
        f[0] = 1;
        f[1] = 1;
        for (int i = 2; i < maxSize; i++) {
            f[i] = f[i - 1] + f[i - 2];
        }
        return f;
    }
}

结果:

https://i-blog.csdnimg.cn/blog_migrate/3838f0814c24f0ba5296f2e1c6bfc16e.png