百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

Python 实现七大排序算法 python的排序

off999 2024-12-26 15:53 15 浏览 0 评论


技术博客: https://github.com/yongxinz/tech-blog

同时,也欢迎关注我的微信公众号 AlwaysBeta,更多精彩内容等你来。

本文用 Python 实现了插入排序、希尔排序、冒泡排序、快速排序、直接选择排序、堆排序、归并排序。

先整体看一下各个算法之间的对比,然后再进行详细介绍:

排序算法 平均时间复杂度 最好情况 最坏情况 空间复杂度 排序方式 稳定性

插入排序 O(n2) O(n) O(n2) O(1) In-place 稳定

冒泡排序 O(n2) O(n) O(n2) O(1) In-place 稳定

选择排序 O(n2) O(n2) O(n2) O(1) In-place 不稳定

快速排序 O(n log n) O(n log n) O(n2) O(log n) In-place 不稳定

希尔排序 O(n log n) O(n log n) O(n log n) O(1) In-place 不稳定

堆排序 O(n log n) O(n log n) O(n log n) O(1) In-place 不稳定

归并排序 O(n log n) O(n log n) O(n log n) O(n) Out-place 稳定

n:数据规模

In-place:占用常数内存,不占用额外内存

Out-place:占用额外内存

稳定性:排序后 2 个相等键值的顺序和排序之前它们的顺序相同

插入排序

描述

时间复杂度为 O(n^2),是稳定的排序方法。

插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序。

插入算法把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外(让数组多一个空间才有插入的位置),而第二部分就只包含这一个元素(即待插入元素)。在第一部分排序完成后,再将这个最后元素插入到已排好序的第一部分中。

代码实现

Bash
# -*- coding: UTF-8 -*-


def insert_sort(lists):
    # 插入排序 时间复杂度为 O(n^2)
    count = len(lists)
    for i in range(1, count):
        key = lists[i]
        j = i - 1
        while j >= 0:
            if lists[j] > key:
                lists[j + 1] = lists[j]
                lists[j] = key
            j -= 1
    return lists


if __name__ == "__main__":
    test = [2, 5, 4, 6, 7, 3, 2]
    print(insert_sort(test))

希尔排序

描述

时间复杂度为 O(n log n),是不稳定的排序方法。

希尔排序(Shell Sort)是插入排序的一种,也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。

该方法因 DL.Shell 于 1959 年提出而得名。 希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止。

代码实现

Bash
# -*- coding: UTF-8 -*-


def shell_sort(lists):
    # 希尔排序 时间复杂度是 O(n log n)
    count = len(lists)
    step = 2
    group = int(count / step)
    while group > 0:
        for i in range(0, group):
            j = i + group
            while j < count:
                k = j - group
                key = lists[j]
                while k >= 0:
                    if lists[k] > key:
                        lists[k + group] = lists[k]
                        lists[k] = key
                    k -= group
                j += group
        group = int(group / step)
    return lists


if __name__ == "__main__":
    test = [2, 5, 4, 6, 7, 3, 2]
    print(shell_sort(test))

冒泡排序

描述

时间复杂度是 O(n2), 是稳定排序算法。

它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。

代码实现

# -*- coding: UTF-8 -*-


def bubble_sort(lists):
    # 冒泡排序 时间复杂度是 O(n2)
    count = len(lists)
    for i in range(0, count - 1):
        for j in range(0, count - i - 1):
            if lists[j] > lists[j + 1]:
                lists[j], lists[j + 1] = lists[j + 1], lists[j]
    return lists


if __name__ == "__main__":
    test = [2, 5, 4, 6, 7, 3, 2]
    print(bubble_sort(test))

快速排序

描述

快速排序的时间复杂度是 O(n log n), 是不稳定排序算法。

通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

代码实现

# -*- coding: UTF-8 -*-


def quick_sort(lists, left, right):
    # 快速排序 时间复杂度是 O(n log n)
    if left >= right:
        return lists
    key = lists[left]
    low = left
    high = right
    while left < right:
        while left < right and lists[right] >= key:
            right -= 1
        lists[left] = lists[right]
        while left < right and lists[left] <= key:
            left += 1
        lists[right] = lists[left]
    lists[right] = key
    quick_sort(lists, low, left - 1)
    quick_sort(lists, left + 1, high)
    return lists


if __name__ == "__main__":
    test = [2, 5, 4, 6, 7, 3, 2]
    print(quick_sort(test, 0, len(test) - 1))

直接选择排序

描述

选择排序的时间复杂度是 O(n2), 是不稳定排序算法。

基本思想:第 1 趟,在待排序记录 r1 ~ r[n] 中选出最小的记录,将它与 r1 交换;第 2 趟,在待排序记录 r2 ~ r[n] 中选出最小的记录,将它与 r2 交换;以此类推,第 i 趟在待排序记录 r[i] ~ r[n] 中选出最小的记录,将它与 r[i] 交换,使有序序列不断增长直到全部排序完毕。

代码实现

# -*- coding: UTF-8 -*-


def select_sort(lists):
    # 选择排序 时间复杂度是 O(n2)
    count = len(lists)
    for i in range(0, count):
        min = i
        for j in range(i + 1, count):
            if lists[min] > lists[j]:
                min = j
        lists[min], lists[i] = lists[i], lists[min]
    return lists


if __name__ == "__main__":
    test = [2, 5, 4, 6, 7, 3, 2]
    print(select_sort(test))

堆排序

描述

堆排序的时间复杂度是 O(n log n), 是不稳定排序算法。

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即 A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。

代码实现

# -*- coding: UTF-8 -*-

from collections import deque


def swap_param(lists, i, j):
    lists[i], lists[j] = lists[j], lists[i]
    return lists


def heap_adjust(lists, start, end):
    temp = lists[start]

    i = start
    j = 2 * i

    while j <= end:
        if (j < end) and (lists[j] < lists[j + 1]):
            j += 1
        if temp < lists[j]:
            lists[i] = lists[j]
            i = j
            j = 2 * i
        else:
            break
    lists[i] = temp


def heap_sort(lists):
    length = len(lists) - 1

    first_sort_count = length / 2
    for i in range(first_sort_count):
        heap_adjust(lists, first_sort_count - i, length)

    for i in range(length - 1):
        lists = swap_param(lists, 1, length - i)
        heap_adjust(lists, 1, length - i - 1)

    return [lists[i] for i in range(1, len(lists))]


def main():
    lists = deque([50, 16, 30, 10, 60,  90,  2, 80, 70])
    lists.appendleft(0)
    print heap_sort(lists)


if __name__ == '__main__':
    main()

归并排序

描述

时间复杂度是 O(n log n), 是稳定排序算法。

归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

归并过程为:比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;否则将第二个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]。

代码实现

# -*- coding: UTF-8 -*-


def merge_sort(lists):
    # 归并排序 时间复杂度是 O(n log n)
    if len(lists) <= 1:
        return lists

    num = int(len(lists) / 2)
    left_lists = merge_sort(lists[:num])
    right_lists = merge_sort(lists[num:])

    return merge(left_lists, right_lists)


def merge(left_lists, right_lists):
    left, right = 0, 0
    result = []

    while left < len(left_lists) and right < len(right_lists):
        if left_lists[left] < right_lists[right]:
            result.append(left_lists[left])
            left += 1
        else:
            result.append(right_lists[right])
            right += 1

    result += left_lists[left:]
    result += right_lists[right:]

    return result


if __name__ == "__main__":
    test = [2, 5, 4, 6, 7, 3, 2]
    print(merge_sort(test))

参考文档:

https://baagee.vip/index/article/id/101.html

https://www.jianshu.com/p/d174f1862601

相关推荐

面试官:来,讲一下枚举类型在开发时中实际应用场景!

一.基本介绍枚举是JDK1.5新增的数据类型,使用枚举我们可以很好的描述一些特定的业务场景,比如一年中的春、夏、秋、冬,还有每周的周一到周天,还有各种颜色,以及可以用它来描述一些状态信息,比如错...

一日一技:11个基本Python技巧和窍门

1.两个数字的交换.x,y=10,20print(x,y)x,y=y,xprint(x,y)输出:102020102.Python字符串取反a="Ge...

Python Enum 技巧,让代码更简洁、更安全、更易维护

如果你是一名Python开发人员,你很可能使用过enum.Enum来创建可读性和可维护性代码。今天发现一个强大的技巧,可以让Enum的境界更进一层,这个技巧不仅能提高可读性,还能以最小的代价增...

Python元组编程指导教程(python元组的概念)

1.元组基础概念1.1什么是元组元组(Tuple)是Python中一种不可变的序列类型,用于存储多个有序的元素。元组与列表(list)类似,但元组一旦创建就不能修改(不可变),这使得元组在某些场景...

你可能不知道的实用 Python 功能(python有哪些用)

1.超越文件处理的内容管理器大多数开发人员都熟悉使用with语句进行文件操作:withopen('file.txt','r')asfile:co...

Python 2至3.13新特性总结(python 3.10新特性)

以下是Python2到Python3.13的主要新特性总结,按版本分类整理:Python2到Python3的重大变化Python3是一个不向后兼容的版本,主要改进包括:pri...

Python中for循环访问索引值的方法

技术背景在Python编程中,我们经常需要在循环中访问元素的索引值。例如,在处理列表、元组等可迭代对象时,除了要获取元素本身,还需要知道元素的位置。Python提供了多种方式来实现这一需求,下面将详细...

Python enumerate核心应用解析:索引遍历的高效实践方案

喜欢的条友记得关注、点赞、转发、收藏,你们的支持就是我最大的动力源泉。根据GitHub代码分析统计,使用enumerate替代range(len())写法可减少38%的索引错误概率。本文通过12个生产...

Python入门到脱坑经典案例—列表去重

列表去重是Python编程中常见的操作,下面我将介绍多种实现列表去重的方法,从基础到进阶,帮助初学者全面掌握这一技能。方法一:使用集合(set)去重(最简单)pythondefremove_dupl...

Python枚举类工程实践:常量管理的标准化解决方案

本文通过7个生产案例,系统解析枚举类在工程实践中的应用,覆盖状态管理、配置选项、错误代码等场景,适用于Web服务开发、自动化测试及系统集成领域。一、基础概念与语法演进1.1传统常量与枚举类对比#传...

让Python枚举更强大!教你玩转Enum扩展

为什么你需要关注Enum?在日常开发中,你是否经常遇到这样的代码?ifstatus==1:print("开始处理")elifstatus==2:pri...

Python枚举(Enum)技巧,你值得了解

枚举(Enum)提供了更清晰、结构化的方式来定义常量。通过为枚举添加行为、自动分配值和存储额外数据,可以提升代码的可读性、可维护性,并与数据库结合使用时,使用字符串代替数字能简化调试和查询。Pytho...

78行Python代码帮你复现微信撤回消息!

来源:悟空智能科技本文约700字,建议阅读5分钟。本文基于python的微信开源库itchat,教你如何收集私聊撤回的信息。[导读]Python曾经对我说:"时日不多,赶紧用Python"。于是看...

登录人人都是产品经理即可获得以下权益

文章介绍如何利用Cursor自动开发Playwright网页自动化脚本,实现从选题、写文、生图的全流程自动化,并将其打包成API供工作流调用,提高工作效率。虽然我前面文章介绍了很多AI工作流,但它们...

Python常用小知识-第二弹(python常用方法总结)

一、Python中使用JsonPath提取字典中的值JsonPath是解析Json字符串用的,如果有一个多层嵌套的复杂字典,想要根据key和下标来批量提取value,这是比较困难的,使用jsonpat...

取消回复欢迎 发表评论: