二分查找算法比较熟悉的是折半查找,但是折半查找中计算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)