📜  斐波那契搜索

📅  最后修改于: 2021-04-23 18:36:36             🧑  作者: Mango

给定大小为n的排序数组arr []和要在其中搜索的元素x。如果x存在于数组中,则返回x的索引,否则返回-1。
例子:

Input:  arr[] = {2, 3, 4, 10, 40}, x = 10
Output:  3
Element x is present at index 3.

Input:  arr[] = {2, 3, 4, 10, 40}, x = 11
Output:  -1
Element x is not present.

斐波那契搜索是一种基于比较的技术,使用斐波那契数字来搜索排序数组中的元素。
与二分搜索的相似之处:

  1. 适用于排序数组
  2. 分而治之算法。
  3. 具有Log n时间复杂度。

二进制搜索的区别

  1. 斐波那契搜索将给定数组分为不相等的部分
  2. 二进制搜索使用除法运算符对范围进行除法。斐波那契搜索不使用/,而是使用+和-。在某些CPU上,除法运算符可能会很昂贵。
  3. Fibonacci Search在后续步骤中检查相对较近的元素。因此,当输入数组很大而无法容纳在CPU缓存或RAM中时,斐波那契搜索将很有用。

背景:
斐波那契数递归定义为F(n)= F(n-1)+ F(n-2),F(0)= 0,F(1)=1。前几个斐波那契数为0、1、1、1。 2,3,5,8,13,21,34,55,89,144,…
观察结果:
下面的观察用于范围消除,因此用于O(log(n))复杂度。

F(n - 2) ≈ (1/3)*F(n) and 
F(n - 1) ≈ (2/3)*F(n).

算法:
令搜索到的元素为x。
这个想法是首先找到大于或等于给定数组长度的最小斐波那契数。令找到的斐波那契数为fib(第m个斐波那契数)。我们使用第(m-2)个斐波那契数作为索引(如果它是有效索引)。令第(m-2)个斐波那契数为i,我们将arr [i]与x进行比较,如果x相同,则返回i。否则,如果x更大,则在i之后重现子数组,否则在i之前重现子数组。
下面是完整的算法
令arr [0..n-1]为输入数组,要搜索的元素为x。

  1. 查找大于或等于n的最小斐波那契数。将此数字设为fibM [第m个斐波那契数]。设其前面的两个斐波那契数为fibMm1 [第(m-1)个斐波那契数]和fibMm2 [第(m-2)个斐波那契数]。
  2. 虽然数组具有要检查的元素:
    1. 将x与fibMm2覆盖范围的最后一个元素进行比较
    2. 如果x匹配,则返回索引
    3. 否则,如果x小于元素,则将三个Fibonacci变量向下移动两个Fibonacci,表示消除了剩余数组的大约后三分之二。
    4. 如果x大于元素,则将三个斐波那契变量向下移动一个斐波那契。将偏移量重置为索引。这些共同表明消除了其余阵列的大约三分之一。
  3. 由于可能还剩下一个要比较的元素,因此请检查fibMm1是否为1。如果是,则将x与该剩余元素进行比较。如果匹配,则返回索引。
C
// C program for Fibonacci Search
#include 
 
// Utility function to find minimum of two elements
int min(int x, int y) { return (x <= y) ? x : y; }
 
/* Returns index of x if present,  else returns -1 */
int fibMonaccianSearch(int arr[], int x, int n)
{
    /* Initialize fibonacci numbers */
    int fibMMm2 = 0; // (m-2)'th Fibonacci No.
    int fibMMm1 = 1; // (m-1)'th Fibonacci No.
    int fibM = fibMMm2 + fibMMm1; // m'th Fibonacci
 
    /* fibM is going to store the smallest Fibonacci
       Number greater than or equal to n */
    while (fibM < n) {
        fibMMm2 = fibMMm1;
        fibMMm1 = fibM;
        fibM = fibMMm2 + fibMMm1;
    }
 
    // Marks the eliminated range from front
    int offset = -1;
 
    /* while there are elements to be inspected. Note that
       we compare arr[fibMm2] with x. When fibM becomes 1,
       fibMm2 becomes 0 */
    while (fibM > 1) {
        // Check if fibMm2 is a valid location
        int i = min(offset + fibMMm2, n - 1);
 
        /* If x is greater than the value at index fibMm2,
           cut the subarray array from offset to i */
        if (arr[i] < x) {
            fibM = fibMMm1;
            fibMMm1 = fibMMm2;
            fibMMm2 = fibM - fibMMm1;
            offset = i;
        }
 
        /* If x is greater than the value at index fibMm2,
           cut the subarray after i+1  */
        else if (arr[i] > x) {
            fibM = fibMMm2;
            fibMMm1 = fibMMm1 - fibMMm2;
            fibMMm2 = fibM - fibMMm1;
        }
 
        /* element found. return index */
        else
            return i;
    }
 
    /* comparing the last element with x */
    if (fibMMm1 && arr[offset + 1] == x)
        return offset + 1;
 
    /*element not found. return -1 */
    return -1;
}
 
/* driver function */
int main(void)
{
    int arr[]
        = { 10, 22, 35, 40, 45, 50, 80, 82, 85, 90, 100,235};
    int n = sizeof(arr) / sizeof(arr[0]);
    int x = 235;
      int ind = fibMonaccianSearch(arr, x, n);
  if(ind>=0)
    printf("Found at index: %d",ind);
  else
    printf("%d isn't present in the array",x);
    return 0;
}


Java
// Java program for Fibonacci Search
import java.util.*;
 
class Fibonacci {
    // Utility function to find minimum
    // of two elements
    public static int min(int x, int y)
    {
        return (x <= y) ? x : y;
    }
 
    /* Returns index of x if present, else returns -1 */
    public static int fibMonaccianSearch(int arr[], int x,
                                         int n)
    {
        /* Initialize fibonacci numbers */
        int fibMMm2 = 0; // (m-2)'th Fibonacci No.
        int fibMMm1 = 1; // (m-1)'th Fibonacci No.
        int fibM = fibMMm2 + fibMMm1; // m'th Fibonacci
 
        /* fibM is going to store the smallest
        Fibonacci Number greater than or equal to n */
        while (fibM < n) {
            fibMMm2 = fibMMm1;
            fibMMm1 = fibM;
            fibM = fibMMm2 + fibMMm1;
        }
 
        // Marks the eliminated range from front
        int offset = -1;
 
        /* while there are elements to be inspected.
        Note that we compare arr[fibMm2] with x.
        When fibM becomes 1, fibMm2 becomes 0 */
        while (fibM > 1) {
            // Check if fibMm2 is a valid location
            int i = min(offset + fibMMm2, n - 1);
 
            /* If x is greater than the value at
            index fibMm2, cut the subarray array
            from offset to i */
            if (arr[i] < x) {
                fibM = fibMMm1;
                fibMMm1 = fibMMm2;
                fibMMm2 = fibM - fibMMm1;
                offset = i;
            }
 
            /* If x is less than the value at index
            fibMm2, cut the subarray after i+1 */
            else if (arr[i] > x) {
                fibM = fibMMm2;
                fibMMm1 = fibMMm1 - fibMMm2;
                fibMMm2 = fibM - fibMMm1;
            }
 
            /* element found. return index */
            else
                return i;
        }
 
        /* comparing the last element with x */
        if (fibMMm1 == 1 && arr[n-1] == x)
            return n-1;
 
        /*element not found. return -1 */
        return -1;
    }
 
    // driver code
    public static void main(String[] args)
    {
        int arr[] = { 10, 22, 35, 40, 45, 50,
                      80, 82, 85, 90, 100,235};
        int n = 12;
        int x = 235;
      int ind = fibMonaccianSearch(arr, x, n);
        if(ind>=0)
        System.out.print("Found at index: "
                         +ind);
      else
        System.out.print(x+" isn't present in the array");
    }
}
 
// This code is contributed by rishabh_jain


Python3
# Python3 program for Fibonacci search.
from bisect import bisect_left
 
# Returns index of x if present,  else
# returns -1
 
 
def fibMonaccianSearch(arr, x, n):
 
    # Initialize fibonacci numbers
    fibMMm2 = 0  # (m-2)'th Fibonacci No.
    fibMMm1 = 1  # (m-1)'th Fibonacci No.
    fibM = fibMMm2 + fibMMm1  # m'th Fibonacci
 
    # fibM is going to store the smallest
    # Fibonacci Number greater than or equal to n
    while (fibM < n):
        fibMMm2 = fibMMm1
        fibMMm1 = fibM
        fibM = fibMMm2 + fibMMm1
 
    # Marks the eliminated range from front
    offset = -1
 
    # while there are elements to be inspected.
    # Note that we compare arr[fibMm2] with x.
    # When fibM becomes 1, fibMm2 becomes 0
    while (fibM > 1):
 
        # Check if fibMm2 is a valid location
        i = min(offset+fibMMm2, n-1)
 
        # If x is greater than the value at
        # index fibMm2, cut the subarray array
        # from offset to i
        if (arr[i] < x):
            fibM = fibMMm1
            fibMMm1 = fibMMm2
            fibMMm2 = fibM - fibMMm1
            offset = i
 
        # If x is less than the value at
        # index fibMm2, cut the subarray
        # after i+1
        elif (arr[i] > x):
            fibM = fibMMm2
            fibMMm1 = fibMMm1 - fibMMm2
            fibMMm2 = fibM - fibMMm1
 
        # element found. return index
        else:
            return i
 
    # comparing the last element with x */
    if(fibMMm1 and arr[n-1] == x):
        return n-1
 
    # element not found. return -1
    return -1
 
 
# Driver Code
arr = [10, 22, 35, 40, 45, 50,
       80, 82, 85, 90, 100,235]
n = len(arr)
x = 235
ind = fibMonaccianSearch(arr, x, n)
if ind>=0:
  print("Found at index:",ind)
else:
  print(x,"isn't present in the array");
 
# This code is contributed by rishabh_jain


C#
// C# program for Fibonacci Search
using System;
 
class GFG {
 
    // Utility function to find minimum
    // of two elements
    public static int min(int x, int y)
    {
        return (x <= y) ? x : y;
    }
 
    /* Returns index of x if present, else returns -1 */
    public static int fibMonaccianSearch(int[] arr, int x,
                                         int n)
    {
        /* Initialize fibonacci numbers */
        int fibMMm2 = 0; // (m-2)'th Fibonacci No.
        int fibMMm1 = 1; // (m-1)'th Fibonacci No.
        int fibM = fibMMm2 + fibMMm1; // m'th Fibonacci
 
        /* fibM is going to store the smallest
        Fibonacci Number greater than or equal to n */
        while (fibM < n) {
            fibMMm2 = fibMMm1;
            fibMMm1 = fibM;
            fibM = fibMMm2 + fibMMm1;
        }
 
        // Marks the eliminated range from front
        int offset = -1;
 
        /* while there are elements to be inspected.
        Note that we compare arr[fibMm2] with x.
        When fibM becomes 1, fibMm2 becomes 0 */
        while (fibM > 1) {
            // Check if fibMm2 is a valid location
            int i = min(offset + fibMMm2, n - 1);
 
            /* If x is greater than the value at
            index fibMm2, cut the subarray array
            from offset to i */
            if (arr[i] < x) {
                fibM = fibMMm1;
                fibMMm1 = fibMMm2;
                fibMMm2 = fibM - fibMMm1;
                offset = i;
            }
 
            /* If x is less than the value at index
            fibMm2, cut the subarray after i+1 */
            else if (arr[i] > x) {
                fibM = fibMMm2;
                fibMMm1 = fibMMm1 - fibMMm2;
                fibMMm2 = fibM - fibMMm1;
            }
 
            /* element found. return index */
            else
                return i;
        }
 
        /* comparing the last element with x */
        if (fibMMm1 == 1 && arr[n-1] == x)
            return n-1;
 
        /*element not found. return -1 */
        return -1;
    }
 
    // driver code
    public static void Main()
    {
        int[] arr = { 10, 22, 35, 40, 45, 50,
                      80, 82, 85, 90, 100,235 };
        int n = 12;
        int x = 235;
          int ind = fibMonaccianSearch(arr, x, n);
          if(ind>=0)
        Console.Write("Found at index: "+ind);
          else
        Console.Write(x+" isn't present in the array");
    }
}
 
// This code is contributed by nitin mittal.


PHP
 1)
    {
        // Check if fibMm2 is a valid location
        $i = min($offset+$fibMMm2, $n-1);
 
        /* If x is greater than the value at index fibMm2,
        cut the subarray array from offset to i */
        if ($arr[$i] < $x)
        {
            $fibM = $fibMMm1;
            $fibMMm1 = $fibMMm2;
            $fibMMm2 = $fibM - $fibMMm1;
            $offset = $i;
        }
 
        /* If x is less than the value at index fibMm2,
        cut the subarray after i+1 */
        else if ($arr[$i] > $x)
        {
            $fibM = $fibMMm2;
            $fibMMm1 = $fibMMm1 - $fibMMm2;
            $fibMMm2 = $fibM - $fibMMm1;
        }
 
        /* element found. return index */
        else return $i;
    }
 
    /* comparing the last element with x */
    if($fibMMm1 && $arr[$n-1] == $x)return $n-1;
 
    /*element not found. return -1 */
    return -1;
}
 
/* driver code */
    $arr = array(10, 22, 35, 40, 45, 50, 80, 82,85, 90, 100,235);
    $n = count($arr);
    $x = 235;
    $ind = fibMonaccianSearch($arr, $x, $n);
    if($ind>=0)
    printf("Found at index: ".$ind);
    else
    printf($x." isn't present in the array");
 
// This code is contributed by mits
?>


Javascript


输出
Found at index: 11

插图:
让我们通过以下示例了解算法:

图片

插图假设:基于1的索引。目标元素x为85。数组n的长度= 11。
大于或等于11的最小斐波那契数为13。根据我们的说明,fibMm2 = 5,fibMm1 = 8,fibM = 13。
另一个实现细节是偏移变量(零初始化)。它标志着从前面开始已消除的范围。我们会不时更新。
现在,由于偏移值是一个索引,并且已删除了包括它及其以下的所有索引,因此仅在其上添加内容是有意义的。由于fibMm2标记了数组的大约三分之一以及它所标记的索引肯定是有效的,因此我们可以将fibMm2添加到offset并检查索引为i = min(offset + fibMm2,n)的元素。

fibSearch

可视化:

fibSearch3

时间复杂度分析:
当我们将目标放在数组的较大(2/3)分数中时,就会发生最坏的情况,因为我们继续找到它。换句话说,我们每次都消除了数组的较小部分(1/3)。我们一次调用n,然后调用(2/3)n,然后调用(4/9)n,此后。
考虑到:

fibSearch2