算法——查找

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的列表不必定是有序的,所以這個內置的查找函數必定是順序查找。 

  所以在考慮選擇順序查找或者二分查找時,若是是有序的確定是使用二分查找,若是是無序的則須要考慮是否要先進行排序。

  排序的時間會很是長,若是查找就此一次那選用順序查找,若是將來查找的次數會很是多,那能夠先排序,將來再查找時速度就很是快了。  

相關文章
相關標籤/搜索