搜索算法之斐波那契搜索详细解读(附带Java代码解读)

斐波那契搜索(Fibonacci Search)详细介绍

1. 基本概念

斐波那契搜索是一种高效的查找算法,用于在已排序的数组中查找目标值。它使用斐波那契数列来确定中间点,避免了二分搜索中的中点计算问题。斐波那契数列是由 F(n) = F(n-1) + F(n-2) 定义的,初始值为 F(0) = 0 和 F(1) = 1。

2. 工作原理

斐波那契搜索的基本步骤如下:

  1. 初始化

    • 计算斐波那契数列中适合当前数组长度的最大值 F(k),其中 F(k) 是小于或等于数组长度的最大斐波那契数。
    • 设置两个指针,offset 用于跟踪当前搜索的起始位置。
  2. 斐波那契数列

    • 计算两个斐波那契数 F(m)F(m-1),通过这些数来确定当前的中间点位置。
  3. 比较

    • 如果目标值等于中间点的元素,返回中间点的索引。
    • 如果目标值小于中间点的元素,调整搜索范围,将斐波那契数列中的位置向左移动。
    • 如果目标值大于中间点的元素,调整搜索范围,将斐波那契数列中的位置向右移动。
  4. 结束条件

    • 重复上述步骤直到找到目标值或搜索范围为空。返回找到的索引或 -1,表示目标值不在数组中。
3. 算法步骤

以下是斐波那契搜索的详细步骤:

  1. 输入

    • 一个已排序的整数数组 arr
    • 一个目标值 target
  2. 步骤

    • 计算斐波那契数列 F(k),其中 F(k) 是小于或等于数组长度的最大斐波那契数。
    • 初始化 offset 为 -1。
    • 使用斐波那契数列确定中间点 ii = min(offset + F(m-2), n-1),其中 F(m-2) 是当前斐波那契数列中的较小值。
    • 如果 arr[i] 等于目标值,返回 i
    • 如果 arr[i] 大于目标值,调整搜索范围:将 F(m-2) 设置为 F(m-1) - F(m-2)
    • 如果 arr[i] 小于目标值,调整搜索范围:将 offset 更新为 i,并将 F(m-1) 设置为 F(m-1) - F(m-2)
    • 继续使用斐波那契数列计算中间点,直到找到目标值或搜索范围为空。
  3. 结束条件

    • 如果在搜索过程中未找到目标值,返回 -1
4. 时间复杂度分析
  • 最坏情况

    • 斐波那契搜索的时间复杂度与斐波那契数列的增长有关,最坏情况下需要 O(log n) 次比较。
  • 最佳情况

    • 如果目标值正好在斐波那契中间点的位置,时间复杂度为 O(1)。
  • 平均情况

    • 平均情况下,时间复杂度为 O(log n),类似于二分搜索。
5. 空间复杂度
  • 空间复杂度:斐波那契搜索只需要常数级别的额外空间来存储变量 offset 和斐波那契数,因此空间复杂度为 O(1)。
6. 实现代码
public class FibonacciSearch {

    /**
     * 执行斐波那契搜索
     * @param arr 已排序的数组
     * @param target 目标值
     * @return 目标值的索引,如果未找到返回-1
     */
    public static int fibonacciSearch(int[] arr, int target) {
        int n = arr.length;
        int fibM_2 = 0; // F(m-2)
        int fibM_1 = 1; // F(m-1)
        int fibM = fibM_1 + fibM_2; // F(m)

        // 找到最小的斐波那契数大于或等于数组长度
        while (fibM < n) {
            fibM_2 = fibM_1;
            fibM_1 = fibM;
            fibM = fibM_1 + fibM_2;
        }

        // 初始化 offset
        int offset = -1;

        // 使用斐波那契数列进行搜索
        while (fibM > 1) {
            int i = Math.min(offset + fibM_2, n - 1);

            if (arr[i] < target) {
                fibM = fibM_1;
                fibM_1 = fibM_2;
                fibM_2 = fibM - fibM_1;
                offset = i;
            } else if (arr[i] > target) {
                fibM = fibM_2;
                fibM_1 = fibM_1 - fibM_2;
                fibM_2 = fibM - fibM_1;
            } else {
                return i; // 找到目标值,返回索引
            }
        }

        // 最后一次检查
        if (fibM_1 == 1 && arr[offset + 1] == target) {
            return offset + 1;
        }

        return -1; // 未找到目标值
    }

    public static void main(String[] args) {
        // 示例数组(已排序)
        int[] numbers = {1, 2, 4, 7, 9, 10, 15};

        // 目标值
        int target = 7;

        // 执行斐波那契搜索
        int result = fibonacciSearch(numbers, target);

        // 输出搜索结果
        if (result != -1) {
            System.out.println("元素 " + target + " 在数组中的索引是: " + result);
        } else {
            System.out.println("元素 " + target + " 不在数组中。");
        }
    }
}

代码解读

  • public static int fibonacciSearch(int[] arr, int target)

    • 定义了一个静态方法 fibonacciSearch,接受两个参数:一个已排序的整数数组 arr 和一个目标值 target
    • 方法返回目标值的索引,如果未找到则返回 -1
  • int fibM_2 = 0; int fibM_1 = 1; int fibM = fibM_1 + fibM_2;

    • 初始化斐波那契数列的前两个值和它们的和。
  • while (fibM < n)

    • 找到最小的斐波那契数大于或等于数组长度的最大值。
  • int i = Math.min(offset + fibM_2, n - 1);

    • 计算中间点 i。使用 offset 和当前斐波那契数 fibM_2 来确定中间点。
  • if (arr[i] < target)

    • 如果中间点的值小于目标值,更新斐波那契数列并移动 offset
  • else if (arr[i] > target)

    • 如果中间点的值大于目标值,更新斐波那契数列,缩小搜索范围。
  • return i;

    • 如果找到目标值,返回中间点的索引。
  • if (fibM_1 == 1 && arr[offset + 1] == target)

    • 最后一次检查,确保在最后一个斐波那契数列的情况下正确找到目标值。
7. 实际应用
  • 已排序数据:斐波那契搜索适用于已排序的数组。它提供了另一种在有序数据中进行查找的方法。

  • 优化性能:在某些应用中,斐波那契搜索可以与其他搜索算法结合使用,以优化查找性能。

  • 数据分布:虽然斐波那契搜索的效率在大多数情况下是好的,但其性能也受限于数据分布的均匀性。

8. 局限性
  • 计算复杂度:虽然斐波那契搜索的时间复杂度与二分搜索相同,但其实现和斐波那契数列的计算可能使其略显复杂。

  • 内存使用:计算斐波那契数列的过程中需要额外的内存来存储中间值。

你可能感兴趣的:(算法分析,算法,数据结构,排序算法)