算法——查找

1、查找

查找:在一些数据元素中,经过必定的方法找出与给定关键字相同的数据元素过程python

列表查找(线性表查找):从列表中查找指定元素。app

  • 输入:列表、待查找元素
  • 输出:元素下标(未找到元素时通常返回None或-1)

python中内置列表查找函数:index()。函数

2、顺序查找(Linear Search)

  顺序查找:也叫线性查找,从列表第一个元素开始,顺序进行搜索,直到找到元素或搜索到列表最后一个元素为止。测试

一、代码示例

def linear_search(li, val):
    """
    顺序查找
    :param li: 输入的列表
    :param val: 输入的待查找的值
    :return:
    """
    for ind, v in enumerate(li):   # index和值
        if v == val:
            return ind   # 返回元素下标index
    else:
        # 循环完毕仍没找到
        return None

二、时间复杂度分析

   在这里n就是列表的长度,且并无循环减半的过程,有一个与n相关的循环,所以时间复杂度是:O(n)spa

3、二分查找(Binary Search)

  二分查找:又叫作折半查找,从有序列表的初始候选区li[0:n]开始,经过对待查找的值与候选区中间值的比较,能够使候选区减小一半。3d

一、二分查找示例

(1)从列表中查找元素3:

  

(2)用left和right两个变量来维护候选区

  初始的时候left=0,right=n-1blog

  

  经过(left+right)/2求出中间元素5与3进行比较:排序

  

  因为5比3大,候选区修改成mid的左边,right=mid-1,完成候选区修改:索引

  

  计算出新的mid:(0+3)/2=1找到新的mid:class

  

  2比3小说明在mid的右边,须要移动left更新候选区,left=mid+1:

  

   再次经过(2+3)/2=2找到mid的索引值:

  

  mid的值与要找的元素3一致,说明找到了,输出mid的下标。left若是大于right则候选区已经没有值了,说明找不到匹配的值。

二、二分查找代码

def binary_search(li, val):
    """
    二分查找
    :param li: 输入的列表
    :param val: 输入的待查找的值
    :return:
    """
    left = 0
    right = len(li) - 1
    while left <= right:  # 说明候选区有值
        mid = (left + right) // 2   # 由于是下标, 所以要整除2
        if li[mid] == val:
            # 找到待查找的值返回index
            return mid
        elif li[mid] > val:
            # 待查找的值在mid左侧
            right = mid - 1   # 更新候选区
        else:  # li[mid] < val
            # 待查找的值在mid右侧
            left = mid + 1    # 更新候选区
    else:
        # 没有找到
        return None


li = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(binary_search(li, 3))   # 输出:2(index值)

三、时间复杂度分析

  因为二分查找是循环减半的,所以它的复杂度是:O(logn)。

  能够得出:二分查找的效率比线性查找高。

测试验证:

cal_time.py:

import time

def cal_time(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        result = func(*args, **kwargs)
        t2 = time.time()
        print("%s running time: %s secs." % (func.__name__, t2 - t1))
        return result

    return wrapper

给二分查找和线性查找都对同一问题测试查看输出的值:

from cal_time import *

@cal_time
def linear_search(li, val):
    """
    顺序查找
    :param li: 输入的列表
    :param val: 输入的待查找的值
    :return:
    """
    for ind, v in enumerate(li):   # index和值
        if v == val:
            return ind   # 返回元素下标index
    else:
        # 循环完毕仍没找到
        return None


@cal_time
def binary_search(li, val):
    """
    二分查找
    :param li: 输入的列表
    :param val: 输入的待查找的值
    :return:
    """
    left = 0
    right = len(li) - 1
    while left <= right:  # 说明候选区有值
        mid = (left + right) // 2   # 由于是下标, 所以要整除2
        if li[mid] == val:
            # 找到待查找的值返回index
            return mid
        elif li[mid] > val:
            # 待查找的值在mid左侧
            right = mid - 1   # 更新候选区
        else:  # li[mid] < val
            # 待查找的值在mid右侧
            left = mid + 1    # 更新候选区
    else:
        # 没有找到
        return None


li = list(range(1000000))
# print(binary_search(li, 3))   # 输出:2(index值)

linear_search(li, 3800)
binary_search(li, 3800)
"""
linear_search running time: 0.0004601478576660156 secs.
binary_search running time: 2.193450927734375e-05 secs.
"""

  因而可知二分查找的巨大优点。

4、总结

  python中内置列表查找函数index()必定是顺序查找,由于二分查找要求列表必须是有序列表,可是Python的列表不必定是有序的,所以这个内置的查找函数必定是顺序查找。 

  所以在考虑选择顺序查找或者二分查找时,若是是有序的确定是使用二分查找,若是是无序的则须要考虑是否要先进行排序。

  排序的时间会很是长,若是查找就此一次那选用顺序查找,若是将来查找的次数会很是多,那能够先排序,将来再查找时速度就很是快了。  

相关文章
相关标签/搜索