当前位置:   article > 正文

Python实现二分法搜索_二分法python

二分法python

Python实现二分法搜索

二分法是一种效率比较高的搜索方法,时间复杂度为 O(log2n) 。

假设有一个1~100之间的数字,你来猜这个数是多少,每猜一次可以得到三种回答:正确、大了或小了。如何保证用最少的次数猜对?很多人会想到先猜50,如果猜大了,说明答案比50小,然后猜25...用这种方法,每次都可以将数字的范围缩小一半,对于1~100之间的任何数,最多都只需要7次就能找到答案。

这种每次将搜索范围缩小一半的方法,就是二分法搜索的思想。本文使用 Python 来实现二分法搜索。

一、Python 二分法搜索递归实现

在实现代码前,先分析二分法的前提条件:

1. 上面的例子在1~100中查找一个数字,每次都要判断是大了还是小了,这里隐含了一个条件,即1~100是升序排列的。对于二分法,数据列表必须是有序的,一般是升序,降序也可以。

2. 跳出1~100的范围,对于任何的数据集合,都可以使用二分法来搜索其中的某个数。

现在来看一下二分法搜索的具体过程。如在 [50, 77, 55, 29, 10, 30, 66, 18, 80, 51] 中搜索 77 。

1. 对列表排序。通常的数据很少是排好序的,要使用二分法,就要先对数据列表进行排序。

2. 取一半位置的数据。对于一个数据集合,数据量可能是奇数,也可能是偶数,但不管奇数偶数,都取2的整除。

所以,这里先找到一半位置的50。

3. 判断中间位置的数字与目标数字的大小,缩小搜索范围,然后重复第2步。

4. 继续重复2和3,直到找到目标数据。

根据搜索的过程,来实现代码。

  1. # coding=utf-8
  2. class BinarySearch(object):
  3. def binary_search(self, array, data):
  4. """二分查找法递归实现"""
  5. if len(array) == 0:
  6. return False
  7. array.sort()
  8. mid_index = len(array) // 2
  9. if array[mid_index] == data:
  10. return True
  11. return self.binary_search(array[mid_index + 1:], data) if data > array[mid_index] else \
  12. self.binary_search(array[:mid_index], data)

binary_search(array, data):在数据列表 array 中搜索数据 data 。每次递归搜索,数据列表的长度都会缩小“一半”,当找到目标数据或数据列表的长度为0时,递归结束。

  1. if __name__ == '__main__':
  2. array = [50, 77, 55, 29, 10, 30, 66, 18, 80, 51]
  3. search = BinarySearch()
  4. print('搜索结果:', search.binary_search(array, 77))
  5. print('搜索结果:', search.binary_search(array, 777))

运行结果:

  1. 搜索结果: True
  2. 搜索结果: False

二、Python 二分法搜索非递归实现

二分法搜索也可以使用非递归的方法实现,还是以在  [50, 77, 55, 29, 10, 30, 66, 18, 80, 51] 中搜索 77 为例。

1. 对列表排序。

2. 取一半位置的数据。这里策略不变,还是取中间位置的数据。但因为是非递归方式,只能通过循环的方式来实现多次二分,如果第一次没有找到目标数据,第二次取一半位置的索引时,就需要根据第一次的判断结果来计算中间索引。因此需要设置两个游标来记录每次二分的开始索引 start 和结束索引 end,如果没有找到目标数据,就修改开始索引或结束索引的值,用于下一次循环中计算中间索引。

3. 根据第一次循环的判断结果,修改开始索引的值,重新计算中间索引和取中间位置的数据。

4. 重复循环直到找到目标数据。当 start 的值等于 end 的值时,范围已经缩小到只剩一个数据,如果继续循环,start 大于 end,说明找不到目标数据,循环结束。

根据这个过程,来实现代码。

  1. def binary_search_normal(self, array, data):
  2. """二分查找法非递归实现"""
  3. array.sort()
  4. start, end = 0, len(array)-1
  5. while start <= end:
  6. mid_index = (start + end) // 2
  7. if array[mid_index] == data:
  8. return True
  9. if data > array[mid_index]:
  10. start = mid_index + 1
  11. else:
  12. end = mid_index - 1
  13. return False

binary_search_normal(array, data):在数据列表 array 中搜索数据 data 的非递归实现。每次循环,都会根据判断结果修改 start 或 end 的值,下一次循环中根据新的 start 和 end 值计算新的 min_index,直到找到目标数据或找完整个数据列表(start>end),循环结束。

  1. print('搜索结果:', search.binary_search_normal(array, 77))
  2. print('搜索结果:', search.binary_search_normal(array, 777))

运行结果:

  1. 搜索结果: True
  2. 搜索结果: False

三、二分法搜索与二叉搜索树的关系

关于Python实现二叉搜索树,可以参考:https://blog.csdn.net/weixin_43790276/article/details/105753543

如果将上面的数据 [50, 77, 55, 29, 10, 30, 66, 18, 80, 51]  添加到二叉搜索树中,得到的二叉搜索树结构如下。

根据二叉搜索树的特性,在向二叉搜索树中插入数据时,就已经先判断了插入数据与根节点数据的大小,小的插入到左子树中,大的插入到右子树中,所以在二叉搜索树中搜索数据时,可以比较数据与根节点的数据大小,递归判断是在左子树还是在右子树中搜索。每一次递归,都会将范围缩小到左子树或右子树,直到找到目标数据。这种搜索方式与二分法搜索的思路非常相似。

二叉搜索树可以理解为二分法实现的一种数据结构,但并不完全是,因为二叉搜索树只是满足了二分法的思想,与二分法是有区别的。

二分法每次都肯定可以将数据范围缩小“一半”,因为数据长度可能是奇数个或偶数个,二分后的两个数据集合的数量要么相等要么相差1。而在二叉搜索树中,左右子树的节点数量取决于添加的顺序,并不一定满足数量相等或最多相差一个。

要满足二叉搜索树的特性,还要控制左子树和右子树的节点数量差异,就需要对二叉搜索树的“平衡”进行控制,在数据结构中,按这种思路实现的二叉树叫红黑树,后面的文章继续研究。

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/453644
推荐阅读
相关标签
  

闽ICP备14008679号