- 数据结构与算法
- DSA - 首页
- DSA - 概述
- DSA - 环境设置
- DSA - 算法基础
- DSA - 渐进分析
- 数据结构
- DSA - 数据结构基础
- DSA - 数据结构和类型
- DSA - 数组数据结构
- 链表
- DSA - 链表数据结构
- DSA - 双向链表数据结构
- DSA - 循环链表数据结构
- 栈与队列
- DSA - 栈数据结构
- DSA - 表达式解析
- DSA - 队列数据结构
- 搜索算法
- DSA - 搜索算法
- DSA - 线性搜索算法
- DSA - 二分搜索算法
- DSA - 插值搜索
- DSA - 跳跃搜索算法
- DSA - 指数搜索
- DSA - 斐波那契搜索
- DSA - 子列表搜索
- DSA - 哈希表
- 排序算法
- DSA - 排序算法
- DSA - 冒泡排序算法
- DSA - 插入排序算法
- DSA - 选择排序算法
- DSA - 归并排序算法
- DSA - 希尔排序算法
- DSA - 堆排序
- DSA - 桶排序算法
- DSA - 计数排序算法
- DSA - 基数排序算法
- DSA - 快速排序算法
- 图数据结构
- DSA - 图数据结构
- DSA - 深度优先遍历
- DSA - 广度优先遍历
- DSA - 生成树
- 树数据结构
- DSA - 树数据结构
- DSA - 树的遍历
- DSA - 二叉搜索树
- DSA - AVL树
- DSA - 红黑树
- DSA - B树
- DSA - B+树
- DSA - 伸展树
- DSA - 字典树
- DSA - 堆数据结构
- 递归
- DSA - 递归算法
- DSA - 使用递归实现汉诺塔
- DSA - 使用递归实现斐波那契数列
- 分治法
- DSA - 分治法
- DSA - 最大最小问题
- DSA - Strassen矩阵乘法
- DSA - Karatsuba算法
- 贪心算法
- DSA - 贪心算法
- DSA - 旅行商问题(贪心法)
- DSA - Prim最小生成树
- DSA - Kruskal最小生成树
- DSA - Dijkstra最短路径算法
- DSA - 地图着色算法
- DSA - 分数背包问题
- DSA - 带截止日期的作业排序
- DSA - 最优合并模式算法
- 动态规划
- DSA - 动态规划
- DSA - 矩阵链乘法
- DSA - Floyd-Warshall算法
- DSA - 0-1背包问题
- DSA - 最长公共子序列算法
- DSA - 旅行商问题(动态规划法)
- 近似算法
- DSA - 近似算法
- DSA - 顶点覆盖算法
- DSA - 集合覆盖问题
- DSA - 旅行商问题(近似算法)
- 随机化算法
- DSA - 随机化算法
- DSA - 随机化快速排序算法
- DSA - Karger最小割算法
- DSA - Fisher-Yates洗牌算法
- DSA 有用资源
- DSA - 问答
- DSA - 快速指南
- DSA - 有用资源
- DSA - 讨论
斐波那契查找算法
顾名思义,斐波那契查找算法使用斐波那契数来在一个已排序的输入数组中搜索元素。
但首先,让我们回顾一下斐波那契数的知识——
斐波那契数列是一系列数字,有两个原始数字 0 和 1。后续数字是数列中前两个数字的和。这是一个无限常数数列,因此其中的数字是固定的。斐波那契数列的前几个数字包括——
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89…
斐波那契数列的主要思想也是消除最不可能找到元素的位置。在某种程度上,它类似于分治算法(逻辑最接近二分查找算法)。该算法与跳跃搜索和指数搜索一样,也跳过输入数组的索引以执行搜索。
斐波那契查找算法
斐波那契查找算法利用斐波那契数列来减少要执行搜索的数组范围。每次迭代,搜索范围都会减小,从而更容易在数组中找到元素。下面可以看到搜索的详细过程——
步骤 1——第一步,找到大于或等于输入数组大小的最近的斐波那契数。然后,也保留所选斐波那契数的前两个数,即我们保留斐波那契数列中的 Fm、Fm-1、Fm-2。
步骤 2——将偏移值初始化为 -1,因为我们一开始将整个数组视为搜索范围。
步骤 3——直到 Fm-2 大于 0,我们执行以下步骤——
将要查找的关键元素与索引 [min(offset+Fm-2,n-1)] 处的元素进行比较。如果找到匹配项,则返回索引。
如果发现关键元素小于此元素,我们将输入范围从 0 减少到此元素的索引。斐波那契数也更新为 Fm = Fm-2。
但如果关键元素大于此索引处的元素,我们将从搜索范围中删除此元素之前的元素。斐波那契数更新为 Fm = Fm-1。偏移值设置为此元素的索引。
步骤 4——由于斐波那契数列中有两个 1,因此会出现前两个数字变为 1 的情况。因此,如果 Fm-1 变为 1,则数组中只剩下一个元素要搜索。我们将关键元素与该元素进行比较并返回第一个索引。否则,算法返回搜索失败。
伪代码
Begin Fibonacci Search n <- size of the input array offset = -1 Fm2 := 0 Fm1 := 1 Fm := Fm2 + Fm1 while Fm < n do: Fm2 = Fm1 Fm1 = Fm Fm = Fm2 + Fm1 done while fm > 1 do: i := minimum of (offset + fm2, n – 1) if (A[i] < x) then: Fm := Fm1 Fm1 := Fm2 Fm2 := Fm - Fm1 offset = i end else if (A[i] > x) then: Fm = Fm2 Fm1 = Fm1 - Fm2 Fm2 = Fm - Fm1 end else return i; end done if (Fm1 and Array[offset + 1] == x) then: return offset + 1 end return invalid location; end
分析
斐波那契查找算法需要对数时间复杂度来搜索元素。由于它基于分治法,并且类似于二分查找的思想,因此该算法在最坏情况下执行所需的时间为 O(log n)。
示例
假设我们有一个已排序的元素数组 {12, 14, 16, 17, 20, 24, 31, 43, 50, 62},需要使用斐波那契搜索确定元素 24 的位置。
步骤 1
输入数组的大小为 10。大于 10 的最小斐波那契数是 13。
因此,Fm = 13,Fm-1 = 8,Fm-2 = 5。
我们将偏移值初始化为 -1
步骤 2
在第一次迭代中,将其与索引 = min (offset + Fm-2, n – 1) = min (-1 + 5, 9) = min (4, 9) = 4 处的元素进行比较。
数组中的第四个元素是 20,它不匹配并且小于关键元素。
步骤 3
在第二次迭代中,更新偏移值和斐波那契数。
由于关键元素更大,偏移值将变为元素的索引,即 4。斐波那契数更新为 Fm = Fm-1 = 8。
Fm-1 = 5,Fm-2 = 3。
现在,将其与索引 = min (offset + Fm-2, n – 1) = min (4 + 3, 9) = min (7, 9) = 7 处的元素进行比较。
数组第 7 个索引处的元素是 43,它不匹配并且也小于关键元素。
步骤 4
我们丢弃第 7 个索引之后的元素,因此 n = 7,偏移值保持为 4。
斐波那契数向后推两步,即 Fm = Fm-2 = 3。
Fm-1 = 2,Fm-2 = 1。
现在,将其与索引 = min (offset + Fm-2, n – 1) = min (4 + 1, 6) = min (5, 7) = 5 处的元素进行比较。
数组中索引 5 处的元素是 24,这是我们的关键元素。返回索引 5 作为此示例数组的输出。
输出返回为 5。
实现
斐波那契搜索算法使用分治策略来消除不太可能包含所需元素的搜索空间。此消除是借助斐波那契数来缩小输入数组中的搜索范围而完成的。下面显示了四种不同编程语言中斐波那契搜索方法的实现——
#include <stdio.h> int min(int, int); int fibonacci_search(int[], int, int); int min(int a, int b){ return (a > b) ? b : a; } int fibonacci_search(int arr[], int n, int key){ int offset = -1; int Fm2 = 0; int Fm1 = 1; int Fm = Fm2 + Fm1; while (Fm < n) { Fm2 = Fm1; Fm1 = Fm; Fm = Fm2 + Fm1; } while (Fm > 1) { int i = min(offset + Fm2, n - 1); if (arr[i] < key) { Fm = Fm1; Fm1 = Fm2; Fm2 = Fm - Fm1; offset = i; } else if (arr[i] > key) { Fm = Fm2; Fm1 = Fm1 - Fm2; Fm2 = Fm - Fm1; } else return i; } if (Fm1 && arr[offset + 1] == key) return offset + 1; return -1; } int main(){ int i, n, key, pos; int arr[10] = {6, 11, 19, 24, 33, 54, 67, 81, 94, 99}; printf("Array elements are: "); int len = sizeof(arr) / sizeof(arr[0]); for(int j = 0; j<len; j++){ printf("%d ", arr[j]); } n = 10; key = 67; printf("\nThe element to be searched: %d", key); pos = fibonacci_search(arr, n, key); if(pos >= 0) printf("\nThe element is found at index %d", pos); else printf("\nUnsuccessful Search"); }
输出
Array elements are: 6 11 19 24 33 54 67 81 94 99 The element to be searched: 67 The element is found at index 6
#include <iostream> using namespace std; int min(int, int); int fibonacci_search(int[], int, int); int min(int a, int b){ return (a > b) ? b : a; } int fibonacci_search(int arr[], int n, int key){ int offset = -1; int Fm2 = 0; int Fm1 = 1; int Fm = Fm2 + Fm1; while (Fm < n) { Fm2 = Fm1; Fm1 = Fm; Fm = Fm2 + Fm1; } while (Fm > 1) { int i = min(offset + Fm2, n - 1); if (arr[i] < key) { Fm = Fm1; Fm1 = Fm2; Fm2 = Fm - Fm1; offset = i; } else if (arr[i] > key) { Fm = Fm2; Fm1 = Fm1 - Fm2; Fm2 = Fm - Fm1; } else return i; } if (Fm1 && arr[offset + 1] == key) return offset + 1; return -1; } int main(){ int i, n, key, pos; int arr[10] = {6, 11, 19, 24, 33, 54, 67, 81, 94, 99}; cout<<"Array elements are: "; for(auto j : arr){ cout<<j<<" "; } n = 10; key = 67; cout<<"\nThe element to be searched: "<<key; pos = fibonacci_search(arr, n, key); if(pos >= 0) cout << "\nThe element is found at index " << pos; else cout << "\nUnsuccessful Search"; }
输出
Array elements are: 6 11 19 24 33 54 67 81 94 99 The element to be searched: 67 The element is found at index 6
import java.io.*; import java.util.Scanner; public class FibonacciSearch { static int min(int a, int b) { return (a > b) ? b : a; } static int fibonacci_search(int arr[], int n, int key) { int offset = -1; int Fm2 = 0; int Fm1 = 1; int Fm = Fm2 + Fm1; while (Fm < n) { Fm2 = Fm1; Fm1 = Fm; Fm = Fm2 + Fm1; } while (Fm > 1) { int i = min(offset + Fm2, n - 1); if (arr[i] < key) { Fm = Fm1; Fm1 = Fm2; Fm2 = Fm - Fm1; offset = i; } else if (arr[i] > key) { Fm = Fm2; Fm1 = Fm1 - Fm2; Fm2 = Fm - Fm1; } else return i; } if (Fm1 == 1 && arr[offset + 1] == key) return offset + 1; return -1; } public static void main(String args[]) { int i, n, key; int arr[] = {6, 11, 19, 24, 33, 54, 67, 81, 94, 99}; System.out.print("Array elements are: "); for(int j = 0; j<arr.length; j++){ System.out.print(arr[j] + " "); } n = 10; key = 67; System.out.print("\nThe element to be searched: " + key); int pos = fibonacci_search(arr, n, key); if(pos >= 0) System.out.print("\nThe element is found at index " + pos); else System.out.print("\nUnsuccessful Search"); } }
输出
Array elements are: 6 11 19 24 33 54 67 81 94 99 The element to be searched: 67 The element is found at index 6
def fibonacci_search(arr, n, key): offset = -1 Fm2 = 0 Fm1 = 1 Fm = Fm2 + Fm1 while (Fm < n): Fm2 = Fm1 Fm1 = Fm Fm = Fm2 + Fm1 while (Fm > 1): i = min(offset + Fm2, n - 1) if (arr[i] < key): Fm = Fm1 Fm1 = Fm2 Fm2 = Fm - Fm1 offset = i elif (arr[i] > key): Fm = Fm2 Fm1 = Fm1 - Fm2 Fm2 = Fm - Fm1 else: return i if (Fm1 == 1 and arr[offset + 1] == key): return offset + 1 return -1 arr = [12, 14, 16, 17, 20, 24, 31, 43, 50, 62] print("Array elements are: ") for j in range(len(arr)): print(arr[j], end = " ") n = len(arr); key = 20 print("\nThe element to be searched:", key) index = fibonacci_search(arr, n, key) if(index >= 0): print("The element is found at index: ", (index)) else: print("Unsuccessful Search")
输出
Array elements are: 12 14 16 17 20 24 31 43 50 62 The element to be searched: 20 The element is found at index: 4