二分查找算法比较熟悉的是折半查找,但是折半查找中计算mid时,有加法和除法。下面介绍仅有加法方式的二分查找算法

核心思想利用斐波那契表达式来实现加法方式的折半查找
技巧点:
1)将数组中数的个数(f(n)-1)分成 f(n-1) -1和 f(n-2)
2):f(n) - 1 = (f(n-1)-1 )+ (f(n-2)-1)
在数组中因为要用到一个mid数(中间位置的数) 故总共要减掉1,故上述表达式成立。

  1 #-*-coding: UTF-8 -*-
  2 
  3 
  4 # 
  5 # 时间复杂度O(log(n))
  6  
  7 def fibonacci_search_F1(lis, key):
  8     print("---F1---")
  9     # 需要一个现成的斐波那契列表。其最大元素的值必须超过查找表中元素个数的数值。
 10     F = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144,
 11          233, 377, 610, 987, 1597, 2584, 4181, 6765,
 12          10946, 17711, 28657, 46368]
 13     low = 0
 14     high = len(lis) - 1
 15     
 16     # 为了使得查找表满足斐波那契特性,在表的最后添加几个同样的值
 17     # 这个值是原查找表的最后那个元素的值
 18     # 添加的个数由F[k]-1-high决定
 19     k = 0
 20     while high > F[k]-1:
 21         k += 1
 22     print(k)
 23     i = high
 24     while F[k]-1 > i:
 25         lis.append(lis[high])
 26         i += 1
 27     print(lis)
 28     
 29     # 算法主逻辑。time用于展示循环的次数。
 30     time = 0
 31     while low <= high:
 32         time += 1
 33         # 为了防止F列表下标溢出,设置if和else
 34         if k < 2:
 35             mid = low
 36         else:
 37             #利用F[k-1]来计算中间位置的数
 38             mid = low + F[k-1]-1
 39         
 40         print("low=%s, mid=%s, high=%s" % (low, mid, high))
 41         if key < lis[mid]:
 42             high = mid - 1
 43             k -= 1
 44         elif key > lis[mid]:
 45             low = mid + 1
 46             k -= 2
 47         else:
 48             if mid <= high:
 49                 # 打印查找的次数
 50                 print("times: %s" % time)
 51                 return mid
 52             else:
 53                 print("times: %s" % time)
 54                 return high
 55     print("times: %s" % time)
 56     return False
 57 
 58 def fibonacci_search_F2(lis, key):
 59     print("---F2---")
 60     # 需要一个现成的斐波那契列表。其最大元素的值必须超过查找表中元素个数的数值。
 61     F = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144,
 62          233, 377, 610, 987, 1597, 2584, 4181, 6765,
 63          10946, 17711, 28657, 46368]
 64     low = 0
 65     high = len(lis) - 1
 66     
 67     # 为了使得查找表满足斐波那契特性,在表的最后添加几个同样的值
 68     # 这个值是原查找表的最后那个元素的值
 69     # 添加的个数由F[k]-1-high决定
 70     k = 0
 71     while high > F[k]-1:
 72         k += 1
 73     print(k)
 74     i = high
 75     while F[k]-1 > i:
 76         lis.append(lis[high])
 77         i += 1
 78     print(lis)
 79     
 80     # 算法主逻辑。time用于展示循环的次数。
 81     time = 0
 82     while low <= high:
 83         time += 1
 84         # 为了防止F列表下标溢出,设置if和else
 85         if k < 2:
 86             mid = low
 87         else:
 88             mid = low + F[k-2]-1
 89         
 90         print("low=%s, mid=%s, high=%s" % (low, mid, high))
 91         if key < lis[mid]:
 92             high = mid - 1
 93             k -= 2
 94         elif key > lis[mid]:
 95             low = mid + 1
 96             k -= 1
 97         else:
 98             if mid <= high:
 99                 # 打印查找的次数
100                 print("times: %s" % time)
101                 return mid
102             else:
103                 print("times: %s" % time)
104                 return high
105     print("times: %s" % time)
106     return False
107  
108 if __name__ == '__main__':
109     LIST = [1,2,3,4, 5,6, 7, 8,9,10,11,12,13,14,15,16,17,18,19,20]
110     print("F1:%d" % fibonacci_search_F1(LIST, 15))
111     print("F2:%d" % fibonacci_search_F2(LIST, 15))

以上用两种方式查找mid的值,主要思想是 mid 既可以由f(n-1) 获得 又可以由f(n-2) 获得。

F1:     f(n-1) + f(n-2) = f(n)

F2:     f(n-2) + f(n-1) = f(n)