zoukankan      html  css  js  c++  java
  • 二分法查找

    二分法查找

    概述

    二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好。

    其缺点是要求待查表为有序表,且插入删除困难。因此,折半查找方法适用于不经常变动而查找频繁的有序列表。

    首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;

    否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。

    重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。

    算法复杂度

    二分查找的基本思想是将n个元素分成大致相等的两部分,取a[n/2]与x做比较;

    如果x=a[n/2],则找到x,算法中止;

    如果x<a[n/2],则只要在数组a的左半部分继续搜索x;

    如果x>a[n/2],则只要在数组a的右半部搜索x.

    时间复杂度无非就是while循环的次数!

    代码示例

    # 二分查找算法
    # seq   待查序列
    # query 要查找的目标
    def binary_search(seq, query):
        # start为起始索引
        # end  为结束索引
        start, end = 0, len(seq) - 1
    
        while start <= end:
            mid = start + (end - start) // 2  # // 整除
            val = seq[mid]
            if val == query:
                # 在seq中找到目标query
                # 返回对应的索引值
                return mid
            elif val < query:
                # 目标值大于中间值
                # 说明目标值在mid - end之间
                start = mid + 1
            else:
                # 目标值小于于中间值
                # 说明目标值在start - mid之间
                end = mid - 1
    
        # 目标值不存在于seq中,返回None
        return None
    
    if __name__ == "__main__":
    
        print("二分查找示例")
    
        print("二分查找只适合有序的序列")
    
        seq = [1, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 10, 13, 15]
    
        print(seq)
        print("---------二分查找--------")
        print("找到:", 5, " 索引是: ", binary_search(seq, 5))
    
        print("---------二分查找--------")
        print("找到:", 4, " 索引是: ", binary_search(seq, 4))
    
        print("---------二分查找--------")
        print("找到:", 13, " 索引是: ", binary_search(seq, 13))
    
        print("---------二分查找--------")
        print("找到:", 1, " 索引是: ", binary_search(seq, 1))
    
        print("---------二分查找--------")
        print("找到:", 25, " 索引是: ", binary_search(seq, 25))

    小结

    大家可以尝试下如果对乱序序列进行查找会有什么情况出现。

    从上文中,我们了解了二分查找基本实现原理和具体的实现算法。

    但大家有没有发现,如果目标查找值,如果在查找序列中存在多个,则查找返回的索引值,会有所变化。

    那下面我们试着利用二分查找实现以下功能:

    • 查找目标值在序列中第一次出现时的索引

    • 查找目标值在序列中最后一次出现时的索引

    例如,有序列如下:

    seq = [1, 2, 3, 4, 5, 5, 5, 5, 6, 7, 8]

    我们查找目标值: 5

    • 第一次出现在索引为:4 的位置

    • 最后一次出现在索引为:7 的位置

    下面我们对二分查找算法进行策略改造升级为:

    # 用于实现二分查找第一次出现的算法
    first_binary_search(seq, query)

    # 用于实现二分查找最后一次出现的算法
    last__binary_search(seq, query)

    代码实现

    first优先策略算法实现

    # first二分查找算法
    # seq   待查序列
    # query 要查找的目标
    def first_binary_search(seq, query):
        # start为起始索引
        # end  为结束索引
        start, end = 0, len(seq) - 1
    
        while start <= end:
            mid = start + (end - start) // 2  # // 整除
            if (mid == 0 and seq[mid] == query) or (seq[mid] == query and seq[mid - 1] < query):
                # 这是实现first的最关键判断
                # 在seq中找到目标query第一次出现的位置
                # 返回对应的索引值
                return mid
            elif seq[mid] < query:
            # 目标值大于中间值
            # 说明目标值在mid - end之间
                start = mid + 1
        else:
            # 目标值小于于中间值
            # 说明目标值在start - mid之间
            end = mid - 1
    
    
    # 目标值不存在于seq中,返回None
        return None
    
    if __name__ == "__main__":
        print("二分查找first示例")
        print("二分查找只适合有序的序列")
    
        seq = [1, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 10, 13, 15]
    
        # 返回7
        print("5第一次出现的索引位置为: ", first_binary_search(seq, 5))
    
        # 返回13
        print("7第一次出现的索引位置为: ", first_binary_search(seq, 7))
    
        # 返回15
        print("8第一次出现的索引位置为: ", first_binary_search(seq, 8))

    last优先策略算法实现

    # last二分查找算法
    # seq   待查序列
    # query 要查找的目标
    def last_binary_search(seq, query):
        # start为起始索引    # end  为结束索引
        start, end = 0, len(seq) - 1
    
        while start <= end:
            mid = start + (end - start) // 2  # // 整除
            if (seq[mid] == query and mid == len(seq) - 1) or (seq[mid] == query and seq[mid + 1] > query):
                # 这是实现last的最关键判断
                # 在seq中找到目标query第一次出现的位置
                # 返回对应的索引值
                return mid
            elif seq[mid] < query:
                # 目标值大于中间值
                # 说明目标值在mid - end之间
                start = mid + 1
            else:
                # 目标值小于于中间值
                # 说明目标值在start - mid之间
                end = mid - 1
    
        # 目标值不存在于seq中,返回None
        return None
    
    
    if __name__ == "__main__":
        print("二分查找last示例")
        print("二分查找只适合有序的序列")
    
        seq = [1, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 10, 13, 15]
    
        # 返回9
        print("5最后一次出现的索引位置为: ", last_binary_search(seq, 5))
    
        # 返回14
        print("7最后一次出现的索引位置为: ", last_binary_search(seq, 7))
    
        # 返回15
        print("8最后一次出现的索引位置为: ", last_binary_search(seq, 8))

    代码示例2

     版本一:

    l = [1,2,4,5,6,7,8,9,10,11,12,13,14,15,16,355,3375,3653,6655]
    
    def binary_search(l,num):
        print(l)
        if len(l)>1:
            mid_index = len(l)//2
            if num >l[mid_index]:
                #in the right
                l = l[mid_index:]
                binary_search(l,num)
            elif num < l[mid_index]:
                #in the left
                l = l[:mid_index]
                binary_search(l,num)
            else:
                print('find it ')
    
        else:
            if l[0]==num:
                print('find it')
            else:
                print('not exist')
            return
    
    
    binary_search(l,65)

    运行结果:

    [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 355, 3375, 3653, 6655]
    [11, 12, 13, 14, 15, 16, 355, 3375, 3653, 6655]
    [16, 355, 3375, 3653, 6655]
    [16, 355]
    [16]
    not exist
    View Code

    版本二:

    n = [1,2,4,5,6,7,8,9,10,11,12,13,14,15,16,355,3375,3653,6655]
    
    def binary_search(n,num):
        print(n)
        if len(n)==1:
            if n[0]==num:
                print('find it')
            else:
                print('not exists')
            return
        mid_index = len(n)//2
        mid_value = n[mid_index]
        if num == mid_value:
            print('find it')
            return
        if num > mid_value:
            n = n[mid_index:]
        if num < mid_value:
            n = n[:mid_index]
        binary_search(n,num)
    
    
    binary_search(n,355)

    运行结果:

    [1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 355, 3375, 3653, 6655]
    [11, 12, 13, 14, 15, 16, 355, 3375, 3653, 6655]
    [16, 355, 3375, 3653, 6655]
    [16, 355]
    find it
    View Code
  • 相关阅读:
    常用日期函数介绍
    常用数学函数介绍
    oracle 常用sql字符函数介绍
    centos6.5 相关命令
    Kettle5.4.0 java.lang.OutOfMemoryError
    oracle多表连接方式Hash Join Nested Loop Join Merge Join
    CONNECT_BY_ROOT
    设置Oracle PL/SQL时间显示格式NLS_TIMESTAMP_FORMAT
    INSTR代替NOT LIKE
    多表插入
  • 原文地址:https://www.cnblogs.com/hcxy2007107708/p/10110773.html
Copyright © 2011-2022 走看看