思路
- 基本介绍
- 对 mid= low +F(k-1)-1的解释:
Python实现
import copy
def get_fibonacci(max_size): # 构建一个斐波那契数列
fib = [0] * max_size
fib[0] = 1
fib[1] = 1
for i in range(2, max_size):
fib[i] = fib[i - 1] + fib[i - 2]
return fib
def fibonacci_search(array, key):
'''
:param array: 传入的数组
:param key:需要查找的关键码(值)
:return:返回对应的下标,如果没有就返回-1
'''
low = 0
high = len(array) - 1
k = 0 # 表示斐波那契分割数值的下标
mid = 0
fib = get_fibonacci(max_size) # 获取到菲波那切数列
# 这一块是,只要数组长度大于斐波那契数列的值,就让值下标一直向后移动
while high > fib[k] - 1: # 获取到菲波那切数列 值 的下标
k += 1
# 因为fib[k] 的值可能大于 array 长度,因此我们需要使用扩充数组
# Java 可以使用Arrays类,构造一个新数组,并指向 array[],属于浅拷贝
# Java做法:int[] temp= Arrays.copyOf(a,f[k]); 不足部分会使用0填充,
# 使用这种方法复制数组时,默认从源数组的第一个元素(索引值为 0)开始复制,
# 目标数组的长度将为 length。如果 length 大于 srcArray.length,则目标数组中采用默认值填充;
# 如果 length 小于 srcArray.length,则复制到第 length 个元素(索引值为 length-1)即止。
# 这种做法,等于可以在原来的基础上扩展原数组,并预留一些空间
# Python的做法:可以用用切片来确定不够的位置,然后填充
temp_list = [0] * len(fib) # 构建一个和fib数列一样长度的数组
temp_list[:len(array)] = copy.copy(array) # 浅拷贝,拷贝数组所有值
# fib 大于 array的部分,依次用array最后一个数填充
for i in range(len(array), len(fib)):
temp_list[i] = array[-1]
while low <= high: # 使用while来循环处理,不用递归,找到需要找的数key
mid = low + fib[k - 1] - 1
if key < temp_list[mid]: # 应该继续向数组的前面查找(左边)
high = mid - 1
# 全部元素 = 前面的元素 + 后边的元素
# f[k] = f[k-1] + f[k-2]
# 因为前面有f[k-1]元素,所以可以继续拆分f[k-1] = f[k-2] + f[k-3]
k -= 1
elif temp_list[mid] < key : # 应该继续向数组的后面查找(右边)
low = mid + 1
# 全部元素=前面的元素+后边的元素
# f[k] = f[k-1] + f[k-2]
# 因为后面有f[k-2] 所以可以继续拆分f[k-1] = f[k-3] + f[k-4]
# 即在f[k-2]的前面进行查找k-=2
# 即下次循环mid=f[k-1-2]-1
k -= 2
else: # 找到了,需要确定返回时,哪个是下标
if mid <= high:
return mid
else:
return high
return -1
if __name__ == '__main__':
li = [1, 8, 10, 89, 1000, 1234]
max_size = 20
get_fibonacci(max_size)
print(fibonacci_search(li, 1000)) # 4
- 总结:变化的确定mid_index的值时,用的是斐波那契数列数值的索引来确定的,整体思想还是二分法的思想,然后 最后操作的数组是浅拷贝的那份数组
也可以不用复制数组
fib = lambda n: n if n < 2 else fib(n - 1) + fib(n - 2)
def fib_search(arr, val):
if len(arr) == 0:
return 'arr is None'
left = 0
right = len(arr) - 1
# 计算fib的值,这个值是大于等于arr的长度的,所以使用时要对key-1
key = 0
while fib(key) < len(arr):
key += 1
while left <= right:
# 当x在分隔的后半部分时,fib计算的mid值可能大于arr长度
# 因为mid是索引位置,这里要取arr长度-1
mid = min(left + fib(key - 1) - 1, len(arr) - 1)
if val < arr[mid]:
right = mid - 1
key -= 1
elif val > arr[mid]:
left = mid + 1
key -= 2
else:
return mid
return -1
def test_fib_search():
arr = [1, 8, 10, 89, 1000, 1234]
print(fib_search(arr, 1000)) # 4
if __name__ == '__main__':
test_fib_search()