算法:二分查找

347 阅读2分钟

什么是二分查找

二分查找也称折半查找,它是一种效率较高的查找算法。
但是,二分查找有2个前提要求:
   1)必须是顺序存储结构
      例如列表和元组,可以通过index查找元素,在内存中是顺序存储的
      字典则不是,链表也不是,因为字典在存储的时候是无序的
   2)必须是排好序的。
  

二分查找的步骤

首先,假设元素是按从小到大排列

step1: 将中间位置的元素与目标元素比较,如果两者相等,则查找成功;
step2: step1没查找到,再利用中间位置下标index将表分成前、后两个子表,如果中间位置的元素大于目标元素,则进一步查找前一子表,否则进一步查找后一子表。
step3: 重复以上步骤,直到找到目标元素,或直到子表不存在为止,此时查找不成功。
   
这种方法类似于现在的核酸检测中的混检  

时间复杂度是
O(logn)

python代码实例1

   #下面这种方法,只能知道target_value是否在列表中,且可以知道其位置,及index.
   #但是不能统计target_value出现的次数
   def bin_search(data_list,target_value):
       left_index = 0  
       right_index = len(data_list) - 1  
        
       while left_index <= right_index:
           mid = (left_index + right_index) // 2  # 地板除
           if data_list[mid] == target_value:
              return mid,target_value  # 返回位置和目标元素
              
           elif data_list[mid] > target_value:
              right = mid - 1
           else:
              left = mid + 1
       # 如果while循环都结束了也没有找到target_value,及没有触发return 语句,则返回None
       
       return None
        
   data_list = [1,2,3,3,3,4,5,6,7]
   target_value = 10
   bin_search(data_list,target_value)
   如果最后返回的是None,则说明target_value不在data_list中

python代码实例2

   #下面这种方法,可以知道target_value是否在列表中,同时可以知道出现了几次。
   #直接找到目标元素的最左边的下标left_index,最右边的下标right_index
   #right_index - left_index + 1

   class Solution:    
       # 找data中第一次出现k的下标index
       def func_get_left_index(self,data_list,k,left,right):
           while left <= right:
               mid = (left + right) // 2
               #注:传统的二分法没有等号,如果相等了,就直接返回mid了,但这个有点特殊
               if data_list[mid] >= k:  
                   right = mid - 1
               else:
                   left = mid + 1
           return left

       # 找data中最后一次出现k的下标index
       def func_get_right_index(self,data_list,k,left,right):
           while left <= right:
               mid = (left + right) // 2
               if data_list[mid] > k:
                   right = mid - 1
               else:  # 注意,其他情况要包括等于
                   left = mid + 1
           return right
       
       # 主函数
       def main(self,data_list,k):
           left = 0
           right = len(data_list) - 1

           left_k = self.func_get_left_index(data_list,k,left,right)
           right_k = self.func_get_right_index(data_list,k,left,right)

           return left_k,right_k,right_k - left_k + 1 # 返回开始index,结束index,以及出现次数