为了讲解清楚各个方法的原理,下面是我们要查找的序列,
nums | 1 | 16 | 24 | 35 | 47 | 59 | 62 | 73 | 88 | 99 |
---|---|---|---|---|---|---|---|---|---|---|
序号 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
二分法在这就不在赘述了,其实际复杂度显然是O(logn).
插值法
在猜目标key=59的时候,我们知道59相对来说是略微偏大的,所以但偏大多少用什么来度量呢,在二分法的时候
m
i
d
=
l
o
w
+
1
2
(
h
i
g
h
+
m
i
d
)
mid= low+\frac{1}{2} (high+mid)
mid=low+21(high+mid)
这里采用的是中间1/2来统一度量,但我们有时知道目标key 靠近右端(左端),此时应该再采用统一度量有点吃力不讨好,这也是二分法的一个缺点,故由此引入了插值法,将递归的mid
值修改成
m
i
d
=
l
o
w
+
k
e
y
−
n
u
m
s
[
l
o
w
]
n
u
m
s
[
h
i
g
h
]
−
n
u
m
s
[
l
o
w
]
(
h
i
g
h
+
m
i
d
)
mid= low+\frac{key-nums[low]}{nums[high]-nums[low]} (high+mid)
mid=low+nums[high]−nums[low]key−nums[low](high+mid)
若目标先对靠近左端,我们查找的对象mid就较为靠近左端;此种算法对原序列有一定的依赖性,需要原序列分布比较均匀
,时间复杂度也有O(logn)。
菲波那切查找
这里要引入菲波那切数列1,1,2,3,5,8,13,21……
;我们先将一些后面所附的代码吧,
- 找出序列nums的长度对应的斐波那契数列的项(这里我们找的是f[k=6]=13);
- 将原序列根据最后一元素进行填充到长度为13;
- 计算中间值mid, m i d = l o w + F [ k − 1 ] − 1 mid = low+F[k-1]-1 mid=low+F[k−1]−1
- 如果目标key靠近low的时候k - =1,这是因为在取mid的时候左端的长度是等于F[k-1]的,而右端的长度是等于F[k-2]的;
- key靠近high时k-=2;
- 若还没有取得nums[mid]==key时继
3
迭代。
斐波那契查找的时间复杂度也是O(logn),就平均性能来看要优于二分法,但如果key=16,那么查找将一直处于左边的长半区间查找,此时的效率就比二分法低。其优点在于迭代的更新函数mid值的计算斐波那契法只用到了加减,此在效率上有一定的提高,但在不能保证避免插值法和斐波那契缺点的时候建议还是使用二分法。 啊这emmmm^ < ^
def erfen(nums,key,sort=0):
if sort == 0:
nums.sort()
high = len(nums)-1
low = 0
while low<=high:
mid = int((low+high)/2)
if nums[mid] > key:
high = mid-1
elif nums[mid] < key:
low = mid+1
else:
return mid
return -1
def interp(nums,key,sort=0):
if sort == 0:
nums.sort()
high = len(nums)-1
low = 0
while low<=high:
mid = int( low + (key-nums[low])*(high-low)/(nums[high]-nums[low]) )
if nums[mid] > key:
high = mid-1
elif nums[mid] < key:
low = mid+1
else:
return mid
return -1
def Fibon(nums,key,sort=0):
if sort == 0:
nums.sort() #若开始的列表无序就先安排排序
low, n, high = 0, len(nums)-1, len(nums)-1
#------------------------- 生成菲波那切数列;
F = [1,1]
while F[-1] < n:
F.append(F[-1]+F[-2])
print (F)
print('==============')
#--------------------------
#将有序列表补齐
for i in range(len(nums),F[-1],1):
nums.append(nums[-1])
k = len(F)-1
while low<=high:
mid = low+F[k-1]-1
print('mid',mid)
if nums[mid] > key: # 说明在mid的左边,此时的个数是F[k-1]个
high = mid-1
k-=1
elif nums[mid] < key: # 说明在mid的右边,此时的个数是F[k-2]个
low = mid+1
k = k-2
else:
if mid <= n:
return mid
else:
return n
return -1