算法二:排序

本文介绍了四种基本的排序算法:冒泡排序的时间复杂度为O(n^2),快速排序平均时间复杂度为O(nlogn),归并排序同样为O(nlogn),而堆积树排序是基于二叉树的排序方法。此外,还展示了如何使用Python的heapq库找到列表或字典中的最大或最小N个元素。
摘要由CSDN通过智能技术生成

冒泡排序
  • 冒泡排序是稳定原地排序算法

  • 时间复杂度O(n^2)

  • 排序方式

    遍历列表并比较相邻的元素对,如果元素顺序错误,则交换它们。重复遍历列表未排序部分的元素,直到完成列表排序

"""
冒泡排序
3 8 2 5 1 4 6 7
"""
def bubble_sort(li):
    # 代码第2步: 如果不知道循环几次,则举几个示例来判断
    for j in range(0,len(li)-1):
        # 代码第1步: 此代码为一波比对,此段代码一定一直循环,一直比对多次至排序完成
        for i in range(0,len(li)-j-1):
            if li[i] > li[i+1]:
                li[i],li[i+1] = li[i+1],li[i]

    return li

li = [3,8,2,5,1,4,6,7]
print(bubble_sort(li))
快速排序
  • 快速排序是⾮稳定原地排序算法
  • 时间复杂度O(nlogn)。空间复杂度是O(logn)。
  • 排序步骤:
    1. 首先选择一个元素,称为数组的基准元素;
    2. 将所有小于基准元素的元素移动到基准元素的左侧;将所有大于基准元素的移动到基准元素的右侧
    3. 递归地将上述两个步骤分别应用于比上一个基准元素值更小和更大的元素的每个子数组
"""
快速排序
    1、left找比基准值大的暂停
    2、right找比基准值小的暂停
    3、交换位置
    4、当right<left时,即为基准值的正确位置,最终进行交换
"""
def quick_sort(li, first, last):
    if first > last:
        return

    # 找到基准值的正确位置下表索引
    split_pos = part(li, first, last)
    # 递归思想,因为基准值正确位置左侧继续快排,基准值正确位置的右侧继续快排
    quick_sort(li, first, split_pos-1)
    quick_sort(li, split_pos+1, last)


def part(li, first, last):
    """找到基准值的正确位置,返回下标索引"""
    # 基准值、左游标、右游标
    mid = li[first]
    lcursor = first + 1
    rcursor = last
    sign = False
    while not sign:
        # 左游标右移 - 遇到比基准值大的停
        while lcursor <= rcursor and li[lcursor] <= mid:
            lcursor += 1
        # 右游标左移 - 遇到比基准值小的停
        while lcursor <= rcursor and li[rcursor] >= mid:
            rcursor -= 1
        # 当左游标 > 右游标时,我们已经找到了基准值的正确位置,不能再移动了
        if lcursor > rcursor:
            sign = True
            # 基准值和右游标交换值
            li[first],li[rcursor] = li[rcursor],li[first]
        else:
            # 左右游标互相交换值
            li[lcursor],li[rcursor] = li[rcursor],li[lcursor]

    return rcursor

if __name__ == '__main__':
    li = [6,5,3,1,8,7,2,4,666,222,888,0,6,5,3]
    quick_sort(li, 0, len(li)-1)

    print(li)
归并排序
  • 归并排序是稳定⾮原地排序算法
  • 时间复杂度O(nlogn)。空间复杂度是O(n)。
  • 排序步骤
    1. 连续划分未排序列表,直到有N个子列表,其中每个子列表有1个"未排序"元素,N是原始数组中的元素数
    2. 重复合并,即一次将两个子列表合并在一起,生成新的排序子列表,直到所有元素完全合并到一个排序数组中
"""
归并排序
"""

def merge_sort(li):
    # 递归出口
    if len(li) == 1:
        return li

    # 第1步:先分
    mid = len(li) // 2
    left = li[:mid]
    right = li[mid:]
    # left_li、right_li 为每层合并后的结果,从内到外
    left_li = merge_sort(left)
    right_li = merge_sort(right)

    # 第2步:再合
    return merge(left_li,right_li)

# 具体合并的函数
def merge(left_li,right_li):
    result = []
    while len(left_li)>0 and len(right_li)>0:
        if left_li[0] <= right_li[0]:
            result.append(left_li.pop(0))
        else:
            result.append(right_li.pop(0))
    # 循环结束,一定有一个列表为空,将剩余的列表元素和result拼接到一起
    result += left_li
    result += right_li

    return result

if __name__ == '__main__':
    li = [1,8,3,5,4,6,7,2]
    print(merge_sort(li))
堆积树排序法

堆积树排序法算是选择排序法的改进版,它可以减少在选择排序法中的比较次数,进而减少排序时间。

堆积树排序法用到了二叉树的技巧,它是利用堆积树来完成排序的。

最大堆积树
  1. 它是一个完全二叉树;
  2. 所有节点的值都大于或等于它左右子节点的值;
  3. 树根是堆积树中最大的
最小堆积树
  1. 它是一个完全二叉树;
  2. 所有节点的值都小于或等于它左右子节点的值;
  3. 树根时堆积树中最小的。
def heap(data, size):
    for i in range(int(size / 2), 0, -1):  # 建立堆积树节点
        ad_heap(data, i, size - 1)
    print()
    print('堆积的内容:', end='')
    for i in range(1, size):  # 原始堆积树的内容
        print('[%2d] ' % data[i], end='')
    print('\n')
    for i in range(size - 2, 0, -1):  # 堆积排序
        data[i + 1], data[1] = data[1], data[i + 1]  # 头尾节点交换
        ad_heap(data, 1, i)  # 处理剩余节点
        print('处理过程为:', end='')
        for j in range(1, size):
            print('[%2d] ' % data[j], end='')
        print()


def ad_heap(data, i, size):
    j = 2 * i
    tmp = data[i]
    post = 0
    while j <= size and post == 0:
        if j < size:
            if data[j] < data[j + 1]:  # 找出最大节点
                j += 1
        if tmp >= data[j]:  # 若树根较大,结束比较过程
            post = 1
        else:
            data[int(j / 2)] = data[j]  # 若树根较小,则继续比较
            j = 2 * j
    data[int(j / 2)] = tmp  # 指定树根为父节点


def main():
    data = [0, 5, 6, 4, 8, 3, 2, 7, 1]  # 原始数组的内容
    size = 9
    print('原始数组为:', end='')
    for i in range(1, size):
        print('[%2d] ' % data[i], end='')
    heap(data, size)  # 建立堆积树
    print('排序结果为:', end='')
    for i in range(1, size):
        print('[%2d] ' % data[i], end='')


main()
使用heapq来找出字典或列表的最大或最小的N个数
import heapq

students = [
    {'name': 'a', 'score': '95'},
    {'name': 'b', 'score': '91'},
    {'name': 'c', 'score': '85'},
    {'name': 'd', 'score': '98'},
    {'name': 'e', 'score': '89'},
]

small = heapq.nsmallest(3, students, key=lambda x: x['score'])
large = heapq.nlargest(3, students, key=lambda x: x['score'])
print(small)
print(large)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值