一、查找(搜索)基础
我们常用的搜索引擎的原理如下:
下面介绍一些概念:
- 查找(Searching)
就是根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素(或记录)。 - 查找表(Search Table)
由同一类型的数据元素((或记录)构成的集合 - 关键字(Key)
数据元素中某个数据项的值,又称为键值。 - 主键(Primary Key)
可唯一地标识某个数据元素或记录的关键字。
查找表按照操作方式可分为:
- 静态查找表(Static Search Table):只做查找操作的查找表。
它的主要操作是:查询某个“特定的”数据元素是否在表中、检索某个“特定的”数据元素和各种属性 - 动态查找表(Dynamic Search Table):在查找中同时进行插入或删除等操作
查找时插入数据、查找时删除数据
1.顺序查找
顺序查找也称为线性查找,属于无序查找算法,顺序查找适合于存储结构为顺序存储或链接存储的线性表。其基本思想是:从数据结构线形表的一端开始,顺序扫描,依次将扫描到的结点关键字与给定值k相比较,若相等则表示查找成功;若扫描结束仍没有找到关键字等于k的结点,表示查找失败。
时间复杂度分析:查找成功时的平均查找长度为 n + 1 2 \frac{n+1}2 2n+1
查找失败时,查找长度为 n n n
所以顺序查找的时间复杂度为 O ( n ) O(n) O(n)
# 最基础的遍历无序列表的查找算法,时间复杂度为O(n)
def sequential_search(lis, key):
length = len(lis)
for i in range(length):
if lis[i] == key:
return i
else:
return False
if __name__ == '__main__':
nums = [1, 2, 3, 4, 5, 6, 7, 8]
target = 6
result = sequential_search(nums, target)
print(result)
def sequential_search(lis, key):
i = 0
# 往列表末尾防止哨兵,省去了遍历时判断查找是否越界的过程,数据量大时,效果显著
lis.append(key)
while lis[i] != key:
i += 1
# 如果i等于列表长度(最后一个元素索引+1),说明查找失败,否则查找成功
return i
if __name__ == '__main__':
nums = [1, 2, 3, 4, 5, 6, 7, 8]
target = 6
result = sequential_search(nums, target)
print(result)
2.二分查找
二分查找也称折半查找(Binary Search),是一种在有序数组中查找某一特定元素的搜索算法。我们可以从定义可知,运用二分搜索的前提是数组必须是有序的,这里需要注意的是,我们的输入不一定是数组,也可以是数组中某一区间的起始位置和终止位置。
二分查找要注重代码细节,容易出错
二分查找的执行过程如下:
- 从已经排好序的数组或区间中,取出中间位置的元素,将其与我们的目标值进行比较,判断是否相等,如果相等则返回。
- 如果
nums[mid]
和target
不相等,则对nums[mid]
和target
值进行比较大小,通过比较结果决定是从mid
的左半部分还是右半部分继续搜索。
如果target > nums[mid]
则右半区间继续进行搜索,即left = mid + 1
;
若target < nums[mid]
则在左半区间继续进行搜索,即right = mid -1
二分查找过程举例:target = 8
# 针对有序查找表的二分查找算法
# 时间复杂度为O(log(n))
def binary_serach(lis, key):
low = 0
high = len(lis) - 1
# 这里如果low<high,mid会移到12后,low = high = 8,此时跳出循环,返回False
while low <= high:
mid = int(low + (high - low) / 2)
if lis[mid] == key:
return mid
elif lis[mid] > key:
high = mid - 1
elif lis[mid] < key:
low = mid + 1
# 循环结束时,low > high,上面的mid-1,smid+1是为了避免出现死循环