查找算法原理与实现[顺序查找、二分法查找、插值查找、分块查找](python版)

1. 顺序查找

  • 原理

顺序查找就是将数列从头到尾按照顺序查找一遍,只需遍历一遍列表,然后逐一判断,顺序查找是最容易理解,时间复杂度最高的排序方法(不需要事先排序)

  • 代码实现
# -*- coding:utf-8 -*-

""" 
Author: leadingme
Mail:[email protected]
MyWebsite:leadingme.top
"""

def sequentialSearch(iList,key):

    for i in range(len(iList)):
        if iList[i] == key:
            return i
    return -1

if __name__ == '__main__':
    iList = [7, 5, 9, 3, 5, 1, 12, 10, 15, 9]
    key = 10
    res = sequentialSearch(iList,key)
    print(res)
    if res >= 0:
        print('%d is in the list, index is: %d\n'%(key, res))
    else:
        print('%d is not in list'%key)

2. 二分法查找

  • 原理

又称之为折半查找,一种计算复杂度为log(n)的查找方法,与线性查找相比,数量级越大,效率的优势越是明显。但是二分法查找的前提是“已经排序好的线性表”,也就是说,一维数组中的数据必须是已经排序好了,才能使用二分法来进行查找,排序方式没有影响。

  • 思路

1:首先,从数组的中间元素开始搜索,如果该元素正好是目标元素,则搜索过程结束,否则执行下一步。
2:如果目标元素大于/小于中间元素,则在数组大于/小于中间元素的那一半区域查找,然后重复步骤1的操作。
3:如果某一步数组为空,则表示找不到目标元素。

  • 代码实现
# -*- coding:utf-8 -*-
""" 
Author: leadingme
Mail:[email protected]
MyWebsite:leadingme.top
"""
from quickSort import quickSort # 从外部导入的快速排序算法

def binarySearch(iList, key):
    iLen = len(iList)
    left = 0   # 初始化左边界下标
    right = iLen - 1  # 初始化右边界下标

    while right > left: # 如果右边结的下标与左边下标相等则跳出循环
        mid = (right+left) // 2
        if key < iList[mid]:   # 如果比中间的数小,则调整右边界为mid-1
            right = mid - 1
        elif key > iList[mid]:  # 如果比中间的数大,则调整左边界mid+1
            left = mid + 1
        else:   # 相等则返回
            return mid
    if key == iList[left]:
        return left
    elif key == iList[right]:
        return right
    else:     # 如果到right > left还没找到,则证明列表中没有改元素
        return -1

if __name__ == '__main__':
    iList = [7, 5, 9, 3, 5, 1, 12, 10, 15, 9]
    iList = quickSort(iList)  # 用快速排序给列表排序
    key = 10
    res = binarySearch(iList, key)
    if res >= 0:
        print('%d is in the list, index is: %d\n' % (key, res))
    else:
        print('%d is not in list' % key)

插值查找

  • 原理

其原理跟二分法的原理很类似,依旧是在左右边界中间取一个特定的mid值,只不过与二分法的区别在于它的mid的取值不是取左右边界的下标均值,而是以mid = left + (key -iList[left])*(right-left) //(iList[right]-iList[left])数学式,其中的left,right分别表示左右边界的下标,值得注意的是,因为除以(iList[right]-iList[left])取整,所以iList[right]与iList[left]差值太大,mid的值会一直取left,从而陷入死循环。

  • 代码实现
# -*- coding:utf-8 -*-
""" 
Author: leadingme
Mail:[email protected]
MyWebsite:leadingme.top
"""

from quickSort import quickSort # 从外部导入的快速排序算法

def insertSearch(iList, key):
    """
    插值查找 (已测,效率比较低)
    :param iList:
    :param key:
    :return:
    """
    iLen  = len(iList)
    left  = 0
    right = iLen - 1
    while right > left:
        mid = left + (key - iList[left])*(right-left) // (iList[right]-iList[left])
        if mid == left:
            mid += 1     # 当iLis[right] 与 iList[left]相差太大是时,有可能导致mid一直等于left,从而陷入死循环
        if key < iList[mid]:
            right = mid -1
        elif key > iList[mid]:
            left = mid + 1
        else:
            return mid

    if key == iList[left]:
        return left
    elif key == iList[right]:
        return right
    else:
        return -1

if __name__ == '__main__':
    iList = [7, 5, 9, 3, 5, 1, 12, 10, 15, 9]
    iList = quickSort(iList)  # 用快速排序给列表排序
    key = 10
    res = insertSearch(iList, key)
    if res >= 0:
        print('%d is in the list, index is: %d\n' % (key, res))
    else:
        print('%d is not in list' % key)

分块查找

  • 原理

分块查找首先按照一定的取值范围将数列分成数块,块内的元素可以是无序的,但块必须是有序的(处于后面位置的块的最小元素要比前一个块的最大元素大),在分块完成后,再确定key值(需要查找的值)所处与块的区间,最后用顺序排序法逐一比对。

  • 代码实现
# -*- coding:utf-8 -*-

""" 
Author: leadingme
Mail:[email protected]
MyWebsite:leadingme.top
"""

iList = [7, 5, 9, 3, 5, 1, 12, 10, 15, 9]
indexList = [[5,0],[10,0],[15,0],[20,0]]

def divideBlock():
    global iList, indexList
    sortList = []  # 用来存放分块好后的新列表
    for key in indexList:
        subList = []   # 定义一个列表,用来存放每一块的元素
        for i in iList:
            if i < key[0]:
                subList.append(i)
        for j in subList:   # 过滤掉已经加入到subList中的元素
            iList.remove(j)
        key[1] = len(subList)
        sortList += subList
    iList = sortList
    return indexList

def blockSearch(iList, indexList, key):
    left = 0 # 搜索数列的起始点索引
    right = 0 # 搜索数列的终点索引
    for indexInfo in indexList: # 确定key所在的块级
        left += right
        right += indexInfo[1]
        if key < indexInfo[0]:
            break
    for i in range(left, right):
        if key == iList[i]:
            return i
    return -1

if __name__ == '__main__':
    indexList = divideBlock()
    print(indexList)
    print(iList)
    key = 7
    res = blockSearch(iList, indexList, key)
    if res >= 0:
        print('%d is in the list, index is: %d\n' % (key, res))
    else:
        print('%d is not in list' % key)

如果有问题,欢迎在评论区交流喔,博主看到会第一时间回复。

你可能感兴趣的:(数据结构与算法,二分法,列表,算法,python,数据结构)