查找算法

顺序查找

  • 当数据存储在诸如列表的集合中时,我们说这些数据具有线性或顺序关系。 每个数据元素都存储在相对于其他数据元素的位置。 由于这些索引值是有序的,我们可以按顺序访问它们。 这个过程产实现的搜索即为顺序查找。
  • 顺序查找原理剖析:
    • 从列表中的第一个元素开始,我们按照基本的顺序排序,简单地从一个元素移动到另一个元素,直到找到我们正在寻找的元素或遍历完整个列表。如果我们遍历完整个列表,则说明正在搜索的元素不存在。
  • 代码实现:该函数需要一个列表和我们正在寻找的元素作为参数,并返回一个是否存在的布尔值。find 布尔变量初始化为 False,如果我们发现列表中的元素,则赋值为 True。
复制代码
def search(alist,item):
    find = False
    pos = 0
    while True:
        if alist[pos] == item:
            find = True
            break
        else:
            pos += 1
            if pos == len(alist):
                break
    return find
        
l = [1,2,3,4,5]
print(search(l,3))  # True
复制代码

有序列表:之前我们列表中的元素是随机放置的,因此在元素之间没有相对顺序。如果元素以某种方式排序,顺序查找会发生什么?我们能够在搜索技术中取得更好的效率吗?

复制代码
def search(alist,item):
    cur = 0
    find = False
    while True:
        if alist[cur] == item:
            find = True
            break
        elif alist[cur] > item:
            break
        else:
            cur += 1
            if cur == len(alist):
                break
    return find
l = [1,2,3,4,5]
print(search(l,51))   # False
复制代码

二分查找 (前提得是有序列表)

  • 有序列表对于我们的实现搜索是很有用的。在顺序查找中,当我们与第一个元素进行比较时,如果第一个元素不是我们要查找的,则最多还有 n-1 个元素需要进行比较。 二分查找则是从中间元素开始,而不是按顺序查找列表。 如果该元素是我们正在寻找的元素,我们就完成了查找。 如果它不是,我们可以使用列表的有序性质来消除剩余元素的一半。如果我们正在查找的元素大于中间元素,就可以消除中间元素以及比中间元素小的一半元素。如果该元素在列表中,肯定在大的那半部分。然后我们可以用大的半部分重复该过程,继续从中间元素开始,将其与我们正在寻找的内容进行比较。
复制代码
def find(alist, item):
    left = 0  # 序列第一个元素下标
    right = len(alist) - 1  # 序列中最后一个元素下标
    find = False
    while left <= right:
        mid = (left + right) // 2  # 中间元素的下标,注意放入循环内部

        if item == alist[mid]:  # 找到了查找的值
            find = True
            break
        else:
            if item < alist[mid]:  # 查找的值可能存在于中间元素左侧
                right = mid - 1
                 #  left和right表示中间元素左侧的子序列
            else: #  查找的值是存在于中间元素右侧
                left = mid + 1
    return find


alist = [1,2,3,4,5,6,7,8,9]
print(find(alist,3))   # True
复制代码

冒泡排序

  • 1.将序列中两两元素比较,将其最大值逐一的移动到序列末尾的位置 (一步步的往后偏移)
  • 2.将上述操作作用于前n-1个元素,n-2,...以此类推循环循环

 step1

  将序列中两两元素比较,将其最大值逐一的移动到序列末尾的位置

复制代码
# step1:.将序列中两两元素比较,将其最大值逐一的移动到序列末尾的位置
def sort(alist):
    for i in range(len(alist)-1):
        if alist[i] > alist[i + 1]:
            alist[i],alist[i+1] = alist[i+1],alist[i]
    return alist

alist = [3,8,7,5,7,6,2,1]
print(sort(alist))   # [3, 7, 5, 7, 6, 2, 1, 8]
复制代码

step2(冒泡排序最终实现)

  将上述操作作用于前n-1个元素,n-2,...以此类推循环循环

复制代码
# step2:将上述操作作用于前n-1个元素,n-2,...以此类推循环循环
def sort(alist):
    for j in range(len(alist)-1):
        for i in range(len(alist)-1-j):
            if alist[i] > alist[i+1]:
                alist[i],alist[i+1] = alist[i+1],alist[i]
    return alist

alist = [3,8,7,5,7,6,2,1]
print(sort(alist))  # [1, 2, 3, 5, 6, 7, 7, 8]
复制代码

选择排序

  • 1.将乱序序列中的元素两两比较,将其最大值找出,直接和最后一个元素交换位置
  • 2.循环第一步

step1

  将乱序序列中的元素两两比较,将其最大值找出,直接和最后一个元素交换位置

复制代码
# step1:将乱序序列中的元素两两比较,将其最大值找出,直接和最后一个元素交换位置
def sort(alist):
    max_index = 0  # 永远保存最大值下标,一开始假设第0个元素为最大值
    for i in range(1, len(alist)):
        if alist[i] > alist[max_index]:
            max_index = i
    alist[max_index], alist[len(alist)-1] = alist[len(alist)-1], alist[max_index]
    return alist

alist = [3,4,8,7,5,7,6,2,1]
print(sort(alist))  # [3, 4, 1, 7, 5, 7, 6, 2, 8]
复制代码

step2(选择排序最终实现)

  将上述操作作用于前n-1个元素,n-2,...以此类推循环循环

复制代码
# step2:将上述操作作用于前n-1个元素,n-2,...以此类推循环循环
def sort(alist):
    for j in range(len(alist)):
        max_index = 0
        for i in range(1,len(alist)-j):
            if alist[i] > alist[max_index]:
                max_index = i
        alist[max_index],alist[len(alist)-1-j] = alist[len(alist)-1-j],alist[max_index]
    return alist

alist = [3,4,8,7,5,7,6,2,1]
print(sort(alist))  # [1, 2, 3, 4, 5, 6, 7, 7, 8]
复制代码

冒泡排序和选择排序的时间复杂度差不多

插入排序

  • 将乱序的序列假设分为两部分
    • 有序部分:默认情况下将序列第一个元素作为有序部分的第一个元素值
      • 必须保证每刻都是有序
    • 无序部分:n-1个元素作为无序部分的元素
      • 需要将无序部分的每一个元素注意插入到有序部分中几个
  • - [9, 8,5,11,10]
  • - [8,9, 5,11,10]
  • - [8,5,9, 11,10]
  • - [5,8,9,11, 10]
  • - [5,8,9,10,11 ]

启蒙

复制代码
# i为有序部分的元素个数
i = 1
# alist[i]:无序部分中第一个元素
# alist[i-1]:有序部分的最后一个元素
if alist[i] < alist[i-1]:
    alist[i],alist[i-1] = alist[i-1],alist[i]

i = 2
while i > 0:
    if alist[i] < alist[i-1]:
        alist[i],alist[i-1] = alist[i-1],alist[i]
        i -= 1
    else: # 如果无续的第一个元素大于有序最后元素,就不做操作
        break
复制代码

插入排序最终版

复制代码
# 完整代码
def sort(alist):
    for i in range(1,len(alist)):
        while i > 0:
            if alist[i] < alist[i-1]:
                alist[i],alist[i-1] = alist[i-1],alist[i]
                i -= 1
            else: # 如果无续的第一个元素大于有序最后元素,就不做操作
                break
    return alist

alist = [9,8,5,11,10]
print(sort(alist)  # [5, 8, 9, 11, 10]
复制代码

希尔排序

  也称缩小增量排序分组之后对组内进行排序 (乱序序列数据量比较大,乱序幅度比较大,希尔排序比插入排序时间效率更高)

  • 增量gap:
    • 分组的组数
    • 每组数据间的间隔
  • 插入排序其实就是增量为1的希尔排序  

  

step1

复制代码
# 1.加入增量gap,然后将插入排序代码的1改为gap
def sort(alist):
    gap = len(alist) // 2
    for i in range(gap,len(alist)):
        while i > 0:
            if alist[i] < alist[i-gap]:
                alist[i],alist[i-gap] = alist[i-gap],alist[i]
                i -= gap
            else:
                break
    return alist
alist = [3,8,5,7,6,2,1]
print(sort(alist))  # [1, 6, 2, 3, 8, 5, 7]
复制代码

希尔排序 (最终成型)

复制代码
# 2.缩减gap
def sort(alist):
    gap = len(alist) // 2  #初始增量gap需要放在循环外
    while gap >= 1:  # 2.缩减gap
        for i in range(gap,len(alist)): # 加入增量gap,然后将插入排序代码的中1改为gap
            while i>0:
                if alist[i] < alist[i-gap]:
                    alist[i],alist[i-gap] = alist[i-gap],alist[i]
                    i -= gap
                else:
                    break
        gap //= 2  # 2.缩减gap
    return alist

alist = [3,8,5,7,6,2,1]
print(sort(alist))  # [1, 2, 3, 5, 6, 7, 8]
复制代码

快速排序

  • 基数:默认情况下,我们将乱序序列的第一个元素作为基数
  • 核心:
    • 需要将序列中的数值,比基数大的放置在基数右侧,比基数小的放置在基数左侧

   

 

复制代码
# 快速排序
def sort(alist,start,end):
    low = start
    high = end
    
    if low > high: # 递归结束的条件
        
        [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        return
    
    mid = alist[low] # 基数
    while low < high: # 让程序继续偏移
        while low < high:
            if alist[high] > mid: # 让high向左偏移
                high -= 1
            else:
                alist[low] = alist[high]
                break

        while low < high: # 用来将low向右偏移
            if alist[low] < mid:
                low += 1
            else:
                alist[high] = alist[low]
                break
        if low == high:
            alist[low] = mid
            # 也可以写成 alist[high] = mid
            
    #递归作用到左侧子序列
    sort(alist,start,high-1)
    #递归作用到右侧子序列
    sort(alist,low+1,end)
    return alist

alist = [6,1,2,7,9,3,4,5,10,8]
print(sort(alist,0,len(alist)-1)) # 这里需要传入列表的起始索引

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
复制代码

 

更多排序见:

  https://www.cnblogs.com/bobo-zhang/p/10574925.html 

posted @ 2020-08-25 11:23  闲酒肆中听风吟  阅读(145)  评论(0编辑  收藏  举报