利用Python实现几种常见排序算法

2023-11-13

一、排序算法概览

插入排序:直接插入排序,二分法插入排序

选择排序:直接选择排序,堆排序

交换排序:冒泡排序,快速排序

归并排序

二、代码实现

1.直接插入排序

最简单直接的一种方式,序列在排序中可分为左边已排序部分和右边未排序部分。每次从未排序部分取出一个数,通过与已排序部分逐次比较,移动,最终放到正确的位置。这个算法不使用辅助空序列,空间复杂度为O(1),平均时间复杂度为O(n^2)。当序列为基本有序时,插入排序能做到O(n)。

def inset_sort(lst):
    for i in range(1, len(lst)):
        x = lst[i]
        j = i
        while j > 0 and lst[j-1] > x:
            lst[j] = lst[j-1]
            j -= 1
        lst[j] = x

2.二分法插入排序

在直接插入的基础上,通过二分法可以快速找到应该插入的位置,优化了比较次数。但仍需要逐步移动数据。因此,和直接插入排序比较,复杂度没有质的改变。

def bisect_inset_sort(lst):
    for i in range(1, len(lst)):
        x = lst[i]
        left = 0
        right = i-1
        mid = int(right / 2)
        # 找到最终位置
        while left < right:
            if lst[mid] > x:
                right = mid-1
            elif lst[mid] <= x:
                left = mid+1
            mid = int((left + right) / 2)
        if lst[mid] <= x:
            index = mid+1
        else:
            index = mid
        # 通过交换移动到最终位置
        for j in range(i, index, -1):
            lst[j-1], lst[j] = lst[j], lst[j-1]

3.直接选择排序

每次从未排序的部分选择最大/小值插入已排序末尾。时间复杂度O(n^2),空间复杂度O(1)

def select_sort(lst):
    for i in range(len(lst)-1):
        k = i
        for j in range(i, len(lst)):
            if lst[j] < lst[k]:
                k = j
        if i != k:
            lst[i], lst[k] = lst[k], lst[i]

4.冒泡排序

每一遍检查,都是两两比较并交换位置。最终导致该次最大元素放到正确位置,同时,较大元素可能移动一定位置。平均时间复杂度O(n^2),空间复杂度O(1)。这个算法对已排序的序列不友好,比如逆序序列要顺序排列,每个元素都需要移动最大距离。

def bubble_sort(lst):
    n = len(lst)
    for i in range(n):
        found = False
        # 可以理解为从0到n-i-1中找到最大值放在n-i-1这个位置
        for j in range(0, n - i - 1):
            if lst[j] > lst[j + 1]:
                lst[j], lst[j + 1] = lst[j + 1], lst[j]
                found = True
        # 如果一轮排序下来没有遇到逆序排列,说明已经全部排好
        if not found:
            break

5.快速排序

(1)方法1,以一个元素为基准,将序列划分为大于和小于该基准两部分,分列左右两边,基准在中间。然后对左右两部分再次进行相同操作。易知,如果每次都能选择中间值作为基准,保证划分的两部分大小相同,此时效率最高。平均时间复杂度O(nlogn),对于空间复杂度,虽然快排也没有使用额外辅助(只有几个临时变量),但使用了递归,有了额外花销。与具体实现有关。

def quick_sort(lst):
    base_sort(lst, 0, len(lst)-1)


def base_sort(lst, left, right):
    if left >= right:
        return
    i, j = left, right
    k = lst[i]
    while i < j:
        while i < j and lst[j] >= k:
            j -= 1
        if i < j:
            lst[i] = lst[j]
            i += 1
        while i < j and lst[i] <= k:
            i += 1
        if i < j:
            lst[j] = lst[i]
            j -= 1
    lst[i] = k
    base_sort(lst, left, i-1)
    base_sort(lst, i+1, right)

(2)方法2,将序列根据基准划分为小记录,大记录,未排序。每次从未排序中选第一个元素,如果大于等于基准,指针往后移;若小于基准,交换大记录第一个和本元素

def quick_sort2(lst):
    def qsort(lst, begin, end):
        if begin >= end:
            return
        k = lst[begin]
        i = begin
        for j in range(begin+1, end+1):
            if lst[j] < k:
                i += 1
                lst[i], lst[j] = lst[j], lst[i]
        lst[begin], lst[i] = lst[i], lst[begin]
        # 递归,再对小于k和大于k的两段序列进行排序
        qsort(lst, begin, i-1)
        qsort(lst, i+1, end)

    qsort(lst, 0, len(lst)-1)

 (3) 三路快排,即将数据划分为小于基准、等于基准、大于基准三部分,等于基准的部分不参与下一轮排序。这个方法在数组中存在大量相同元素时会非常高效。

def quick_sort3(lst):
    def sort(l, r):
        if l >= r:
            return
        lt = l
        gt = r+1
        i = l+1
        # 基准的选择也可以随机
        v = lst[l]
        while i < gt:
            if lst[i] < v:
                lt += 1
                i += 1
            elif lst[i] > v:
                lst[i], lst[gt-1] = lst[gt-1], lst[i]
                gt -= 1
            else:
                i += 1
        lst[l], lst[lt] = lst[lt], lst[l]
        sort(l, lt-1)
        sort(gt, r)
    sort(0, len(lst)-1)

6.归并排序

一开始,一个元素看作一个排好序的段,相邻段合并成包含两个元素的有序段,以此类推。直至段的长度等于序列长度。时间复杂度O(nlogn),这里使用了辅助列表,长度和原序列相同,因此,空间复杂度为O(n)。

def merge_sort(lst):
    """负责合并两个子序列"""
    def merge(lfrom, lto, low, mid, high):
        i, j, k = low, mid, low
        while i < mid and j < high:
            if lfrom[i] <= lfrom[j]:
                lto[k] = lfrom[i]
                i += 1
            else:
                lto[k] = lfrom[j]
                j += 1
            k += 1
        # 复制第一段剩余记录
        while i < mid:
            lto[k] = lfrom[i]
            i += 1
            k += 1
        # 复制第二段剩余记录
        while j < high:
            lto[k] = lfrom[j]
            j += 1
            k += 1
    """完成一遍合并,将子序列两两合并"""
    def merge_pass(lfrom, lto, llen, slen):
        i = 0
        while i + 2 * slen < llen:
            merge(lfrom, lto, i, i+slen, i+2*slen)
            i += 2*slen
        # 剩两段,最后一段长度小于slen
        if i + slen < llen:
            merge(lfrom, lto, i , i+slen, llen)
        # 只剩一段,直接复制
        else:
            for j in range(i, llen):
                lto[j] = lfrom[j]

    slen, llen = 1, len(lst)
    # 和原表等长的辅助表
    tmp_lst = [None] * llen
    while slen < llen:
        merge_pass(lst, tmp_lst, llen, slen)
        slen *= 2
        # 在原表和辅助表之间来回进行归并
        merge_pass(tmp_lst, lst, llen, slen)
        slen *= 2

7.总结

各种排序算法各有适用场景,实际使用中也并非只用一种。比如在使用快速排序和归并排序时,针对短序列(比如当被排序序列长度小于15)可以使用直接插入排序这样的简单稳定算法。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

利用Python实现几种常见排序算法 的相关文章

  • Python 和 Numpy 是 nan 和 set

    我在使用 Python 的 Numpy set 和 NaN 非数字 时遇到了不可预测的行为 gt gt gt set np float64 nan np float64 nan set nan nan gt gt gt set np flo
  • LibreOffice 并行将 .docx 转换为 .pdf 效果不佳

    我有很多 docx 文件需要转换为 pdf 将它们一一转换需要很长时间 所以我编写了一个 python 脚本来并行转换它们 from subprocess import Popen import time import os os chdi
  • 为什么我的混淆矩阵只返回一个数字?

    我正在做二元分类 每当我的预测等于事实时 我发现sklearn metrics confusion matrix返回单个值 难道没有问题吗 from sklearn metrics import confusion matrix print
  • Tkinter 菜单删除项

    如何删除任何菜单项 例如我想删除 播放 self menubar Menu self root self root config menu self menubar self filemenu2 Menu self menubar self
  • 如何删除 PyCharm 中的项目?

    如果我关闭一个项目 然后删除该项目文件夹 则在 PyCharm 重新启动后 会再次创建一个空的项目文件夹 只需按顺序执行以下步骤即可 他们假设您当前在 PyCharm 窗口中打开了该项目 单击 文件 gt 关闭项目 关闭项目 在 PyCha
  • 将 C++ 指针作为参数传递给 Cython 函数

    cdef extern from Foo h cdef cppclass Bar pass cdef class PyClass cdef Bar bar def cinit self Bar b bar b 这总是会给我类似的东西 Can
  • 使用 Pytest 的参数化添加测试功能的描述

    当其中一个测试失败时 可以在测试正在测试的内容的参数化中添加描述 快速了解测试失败的原因 有时您不知道测试失败的原因 您必须查看代码 通过每个测试的描述 您就可以知道 例如 pytest mark parametrize num1 num2
  • numpy:高效执行数组的复杂重塑

    我正在将供应商提供的大型二进制数组读入 2D numpy 数组 tempfid M N load data data numpy fromfile file dirname fid dtype numpy dtype i4 convert
  • 如何将 sql 数据输出到 QCalendarWidget

    我希望能够在日历小部件上突出显示 SQL 数据库中的一天 就像启动程序时突出显示当前日期一样 在我的示例中 它是红色突出显示 我想要发生的是 当用户按下突出显示的日期时 数据库中日期旁边的文本将显示在日历下方的标签上 这是我使用 QT De
  • 如何在 Python 中的函数入口、内部和退出处进行日志记录

    我希望能够使用 Python 日志记录工具在我的代码中进行简单且一致的日志记录 我能够执行以下操作 我希望所有现有 未来的模块和函数都有 输入 和 完成 日志消息 我不想添加相同的代码片段来定义日志记录参数 如下所示don t want t
  • App Engine 实体到字典

    将 google app engine 实体 在 python 中 复制到字典对象的好方法是什么 我正在使用 db Expando 对象 所有属性均为扩展属性 Thanks 有一个名为foo尝试 foo dict
  • Flask 应用程序路由中的多个参数

    烧瓶怎么写app route如果我在 URL 调用中有多个参数 这是我从 AJax 调用的 URL http 0 0 0 0 8888 createcm summary VVV change Feauure 我试图写我的烧瓶app rout
  • 使用seaborn绘制简单线图

    我正在尝试使用seaborn python 绘制ROC曲线 对于 matplotlib 我只需使用该函数plot plt plot one minus specificity sensitivity bs where one minus s
  • pygame:使用 sprite.RenderPlain 绘制精灵组的顺序

    我有一个精灵组 需要按一定的顺序绘制 以便其精灵按应有的方式重叠 然而 即使使用运算符模块函数 sorted self sprites key attrgetter y x 对组进行排序 顺序也是错误的 我该如何解决这个问题 直截了当地说
  • 无法在 PyCharm 版本 9.3.3 中安装 NumPy。 Python版本3.8.2

    在 PyCharm 中安装 NumPy 时出错 尝试安装 Microsoft Visual C 14 0 还是行不通 NumPy 正在通过命令安装pip3 install numpy在 cmd 终端中 但是当尝试将其安装在 PyCharm
  • 将字符串中的随机字符转换为大写

    我尝试随机附加文本字符串 这样就不只是有像这样的输出 gt gt gt david 我最终会得到类似的东西 gt gt gt DaViD gt gt gt dAviD 我现在的代码是这样的 import random import stri
  • 如何从列表类别中对 pandas 数据框进行排序?

    所以我在下面有这个数据集 我想根据我的列表从 名称 列进行排序 以及按 A 升序和按 B 降序排序 import pandas as pd import numpy as np df1 pd DataFrame from items A 1
  • 使用 suds SOAP 库进行 HTTP 身份验证的奇怪行为

    我有一个正在运行的 python 程序 它使用 suds 通过 SOAP 获取大量数据 Web服务是通过分页功能实现的 这样我就可以抓取nnn每个 fetch 调用的行并获取下一个nnn与后续的电话 如果我使用如下代码向 HTTP 服务器进
  • 仅允许正小数

    在我的 Django 模型中 我创建了一个如下所示的小数字段 price models DecimalField u Price decimal places 2 max digits 12 显然 价格为负或零是没有意义的 有没有办法将小数
  • 在 numpy 中连接维度

    我有x 1 2 3 4 5 6 7 8 9 10 11 12 shape 2 2 3 I want 1 2 3 4 5 6 7 8 9 10 11 12 shape 2 6 也就是说 我想连接中间维度的所有项目 在这种特殊情况下我可以得到这

随机推荐

  • GDAL教程——Geotransform

    教程参考链接 非常好的学习资料 https gdal org tutorials geotransforms tut html 1 geotransform 函数 地理变换函数 地理变换是从图像坐标空间 行 列 也称为 像素 线 到地理引用
  • CSPP 数据的机器级表示

    寄存器 intel x86 64 调用寄存器与被调用寄存器 因为要保证在调用函数返回后寄存器的值恢复为未被调用之前 所以下面的例子运用pushq指令保存被调用寄存器rbx的值 函数 gcc产生的指令指示操作数的大小 寄存器的作用 rax存储
  • 华为OD机试 - 勾股数元组(Java)

    题目描述 如果3个正整数 a b c 满足a 2 b 2 c 2的关系 则称 a b c 为勾股数 著名的勾三股四弦五 为了探索勾股数的规律 我们定义如果勾股数 a b c 之间两两互质 即a与b a与c b与c之间均互质 没有公约数 则其
  • Torch安装

    安装步骤参考官网http torch ch docs getting started html 安装过程中可能遇见的问题 1 执行命令 git clone https github com torch distro git torch re
  • python后端学习(九)GIL、深/浅拷贝、私有化、import、封装继承多态

    GIL面试题 描述Python GIL的概念 以及它对python多线程的影响 编写一个多线程抓取网页的程序 并阐明多线程抓取程序是否可比单线程性能有提升 并解释原因 Guido的声明 http www artima com forums
  • Android微信页面缓存清理,安卓用户如何彻底清理微信大量缓存?4招让你彻底解决内存烦恼...

    原标题 安卓用户如何彻底清理微信大量缓存 4招让你彻底解决内存烦恼 作为一个64G版的安卓用户 现在隔三差五就要对手机的内存进行清理 更不用说还在用16G的你了 如果经常出现手机的提醒你的存储容量几乎已满时 你是不老是跟小编以前一样去相册里
  • (Java) 算法题:2的N次方

    题目描述 原题链接 2的N次方 对于一个整数N 512 lt N lt 1024 计算2的N次方并在屏幕显示十进制结果 输入描述 输入一个整数N 512 lt N lt 1024 输出描述 2的N次方的十进制结果 输入例子1 512 输出例
  • 实现即时通讯的几种方式

    文章目录 1 短轮询 2 长轮询 3 SSE 4 WebSocket 总结 在 Web 应用程序中 实现即时通讯是一件常见的任务 为了实现即时通讯 我们需要使用一些特殊的技术和协议来建立一个实时连接 以便实时更新数据 在本文中 我们将介绍几
  • 本地编辑shopify主题的第一种方式

    先进入Shopify商店后台 新建应用程序 填写完无关紧要的信息后 把Theme templates and theme assets权限设置为读写访问权限并保存 然后复制密码 这表示可以通过这个密码对主题进行读写修改了 然后按照命令获取主
  • k8s-(五)最全的安装教程(使用kubeadm在Centos7上部署kubernetes1.18)以及安装异常问题记录

    k8s使用kubeadm进行安装步骤 使用kubeadm安装k8s会简单很多 一直想总结写一篇简单明了的安装教程 希望能有用 k8s在2020年初发布的第一个版本是1 18 0 目前最新版本是1 19 4 并且1 20的版本应该会在年底发布
  • Oracle PL/SQL中的循环处理(sql for循环)

    今年春节算是休了个长假 调整好心态 迎接新一年的挑战 今天来说下Oracle中的循环迭代处理 因为从自己的博客统计中看到 不少网友都搜索了关键字 SQL FOR循环 所以打算在这里说下个人的理解 PL SQL也和我们常用的编程语言一样 提供
  • 真香!用python做副业,月赚1W+,别被死工资拖累

    被压垮的打工人 你还好吗 房贷车贷 上老下小 日常开销 但你的收入有多少 所以你不敢生病 甚至不敢回家 就为了每个月那么点死工资 还得天天加班 然而忙忙忙 却变成了 穷忙族 成为了职场废人 其实很多人都想改变现状 想学点什么的 但就是不知从
  • c语言 字母消消乐,消消乐(C语言版)

    消消乐 游戏规则很简单 点击的位置颜色相连的区域抵消 实现思路 从点击位置开始深搜 递归 记录搜索的坐标并抵消 贴上关键代码 map数组保存每个点的颜色 state保存是否搜索过 判断当前点是否满足条件 并且未搜索过 int isValid
  • VS Code 快捷键(中英文对照版)

    标签 空格分隔 visual studio code 常用 General 按 Press 功能 Function Ctrl Shift P F1 显示命令面板 Show Command Palette Ctrl P 快速打开 Quick
  • 快速解决QQ自动下载腾讯视频播放器

    使用电脑QQ播放视频时 QQ总是会使用默认安装的腾讯视频播放器打开 可是他的这个播放器非常的卡 自己设置的默认不使用播放仍然不起作用 用geek观察了一下电脑 确实没发现腾讯视频 于是在播放视频的时候打开任务管理器 终于发现了腾讯视频播放器
  • 原理图以及vhdl设计一位全加器

    原理图设计以及VHDL设计 一位加法器 全加器原理 全加器真值 输出表达式 原理图设计法 VHDL设计法 代码如下 全加器是用门电路实现两个二进制数相加并求出和的组合线路 称为一位全加器 一位全加器可以处理低位进位 并输出本位加法进位 多个
  • 【目标检测】各种方法中比较难理解的地方

    1 评价指标mAP 全网最清楚的解释 强推 原文链接 http blog sina com cn s blog 9db078090102whzw html 理解的关键点在于每一次的precision和recall计算都是在top X的基础上
  • VMware虚拟机装win7教程

    VMware虚拟机装win7教程 前言 一 VMware虚拟机装win7 二 装Vmware Tools 1 初步装好win7后 要装Vmware Tools 2 搞不定的接着往下看 也是本人遇到的问题 总结 前言 昨晚想要在win10系统
  • 初识RecyclerView

    使用之前 implementation com android support recyclerview v7 26 1 0 添加v7的依赖 不然Recyclerview不给用 1 Xml布局 此处布局文件有两个 一个是整体的父布局文件 代
  • 利用Python实现几种常见排序算法

    一 排序算法概览 插入排序 直接插入排序 二分法插入排序 选择排序 直接选择排序 堆排序 交换排序 冒泡排序 快速排序 归并排序 二 代码实现 1 直接插入排序 最简单直接的一种方式 序列在排序中可分为左边已排序部分和右边未排序部分 每次从