今天学查找算法,先写线性查找、二分查找及两种改进(插值查找和斐波那契查找)。树查找、散列查找等以后再补。
def linear_search(nums: list, value) -> int:
"""
线性查找
:param nums:被查找序列
:param value:目标值
:return:目标值在被查找序列中的索引,查不到时为-1
"""
for i, num in enumerate(nums):
if num == value: return i
return -1
def binary_search(nums: list, value) -> int:
"""
二分查找
:param nums:被查找序列,要求已排好序
:param value:目标值
:return:目标值在被查找序列中的索引,查不到时为-1
"""
start, end = 0, len(nums) - 1 # 初始化始末索引
if value < nums[start] or value > nums[end]: return -1 # 如果目标值越界,直接返回-1
while start <= end:
mid_index = (start + end) // 2 # 计算中间索引
if value == nums[mid_index]: return mid_index # 如果中间值等于目标值,返回中间索引
elif value < nums[mid_index]: end = mid_index - 1 # 如果目标值小于中间值,修改结束索引为中间索引的前一个位置
else: start = mid_index + 1 # 如果目标值大于中间值,修改开始索引为中间索引的后一个位置
return -1
def interpolation_search(nums: list, value) -> int:
"""
插值查找
:param nums:被查找序列,要求已排好序
:param value:目标值
:return:目标值在被查找序列中的索引,查不到时为-1
"""
start, end = 0, len(nums) - 1
if value < nums[start] or value > nums[end]: return -1
# 增加nums[start] != nums[end]条件防止分母为零
while start <= end and nums[start] != nums[end]:
mid_index = start + int(((value - nums[start]) / (nums[end] - nums[start])) * (end - start)) # 计算中间索引,基于值的比例进行插值计算
if value == nums[mid_index]: return mid_index
elif value < nums[mid_index]:
end = mid_index - 1
if value > nums[end]: break # 避免在近似值内循环
else:
start = mid_index + 1
if value < nums[start]: break # 避免在近似值内循环
if nums[start] == nums[end] == value: return start # 若因开始和结束索引的值相等退出,检查其是否为目标值
return -1
def fibonacci_search(nums: list, value) -> int:
"""
斐波那契查找
### 改进建议
1. **增强逻辑严密性**:虽然使用黄金分割比的近似值来近似斐波那契查找可能在很多情况下有效,但在特定数据分布或特定情境下,可能无法达到与真正的斐波那契查找相同的效率。因此,可以考虑实现标准的斐波那契查找算法,以更准确地反映其原始意图和潜在的性能优势。
:param nums:被查找序列,要求已排好序
:param value:目标值
:return:目标值在被查找序列中的索引,查不到时为-1
"""
start, end = 0, len(nums) - 1
if value < nums[start] or value > nums[end]: return -1
while start <= end:
mid_index = start + int(((5 ** 0.5 - 1) / 2) * (end - start)) # 使用斐波那契数列太麻烦了,这里直接用黄金分割点的近似值,效果也差不多。
if value == nums[mid_index]: return mid_index
elif value < nums[mid_index]: end = mid_index - 1
else: start = mid_index + 1
return -1
if __name__ == '__main__':
from random import choices
nums = choices(range(100), k=10)
sorted_nums = sorted(nums)
print(f'nums:{nums}\nsorted_nums:{sorted_nums}')
print(f'Search:{nums[-1]},result:\n'
f' linear_search:{linear_search(nums, nums[-1])}\n'
f' binary_search:{binary_search(sorted_nums, nums[-1])}\n'
f' interpolation_search:{interpolation_search(sorted_nums, nums[-1])}\n'
f' fibonacci_search:{fibonacci_search(sorted_nums, nums[-1])}')
print(f'Search:{100},result:\n'
f' linear_search:{linear_search(nums, 100)}\n'
f' binary_search:{binary_search(sorted_nums, 100)}\n'
f' interpolation_search:{interpolation_search(sorted_nums, 100)}\n'
f' fibonacci_search:{fibonacci_search(sorted_nums, 100)}')
输出:
nums:[13, 35, 11, 2, 96, 37, 5, 48, 48, 45]
sorted_nums:[2, 5, 11, 13, 35, 37, 45, 48, 48, 96]
Search:45,result:
linear_search:9
binary_search:6
interpolation_search:6
fibonacci_search:6
Search:100,result:
linear_search:-1
binary_search:-1
interpolation_search:-1
fibonacci_search:-1