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

Python 实现七大排序算法_python排序方法有哪几种

wptr33 2025-09-24 04:57 21 浏览


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

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

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

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

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

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

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

选择排序 O(n^2) O(n^2) O(n^2) O(1) In-place 不稳定

快速排序 O(n log n) O(n log n) O(n^2) 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),是稳定的排序方法。

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

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

代码实现

# -*- 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 时,整个文件恰被分成一组,算法便终止。

代码实现

# -*- 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(n^2), 是稳定排序算法。

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

代码实现

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


def bubble_sort(lists):
    # 冒泡排序 时间复杂度是 O(n^2)
    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(n^2), 是不稳定排序算法。

基本思想:第 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(n^2)
    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

相关推荐

oracle数据导入导出_oracle数据导入导出工具

关于oracle的数据导入导出,这个功能的使用场景,一般是换服务环境,把原先的oracle数据导入到另外一台oracle数据库,或者导出备份使用。只不过oracle的导入导出命令不好记忆,稍稍有点复杂...

继续学习Python中的while true/break语句

上次讲到if语句的用法,大家在微信公众号问了小编很多问题,那么小编在这几种解决一下,1.else和elif是子模块,不能单独使用2.一个if语句中可以包括很多个elif语句,但结尾只能有一个...

python continue和break的区别_python中break语句和continue语句的区别

python中循环语句经常会使用continue和break,那么这2者的区别是?continue是跳出本次循环,进行下一次循环;break是跳出整个循环;例如:...

简单学Python——关键字6——break和continue

Python退出循环,有break语句和continue语句两种实现方式。break语句和continue语句的区别:break语句作用是终止循环。continue语句作用是跳出本轮循环,继续下一次循...

2-1,0基础学Python之 break退出循环、 continue继续循环 多重循

用for循环或者while循环时,如果要在循环体内直接退出循环,可以使用break语句。比如计算1至100的整数和,我们用while来实现:sum=0x=1whileTrue...

Python 中 break 和 continue 傻傻分不清

大家好啊,我是大田。...

python中的流程控制语句:continue、break 和 return使用方法

Python中,continue、break和return是控制流程的关键语句,用于在循环或函数中提前退出或跳过某些操作。它们的用途和区别如下:1.continue(跳过当前循环的剩余部分,进...

L017:continue和break - 教程文案

continue和break在Python中,continue和break是用于控制循环(如for和while)执行流程的关键字,它们的作用如下:1.continue:跳过当前迭代,...

作为前端开发者,你都经历过怎样的面试?

已经裸辞1个月了,最近开始投简历找工作,遇到各种各样的面试,今天分享一下。其实在职的时候也做过面试官,面试官时,感觉自己问的问题很难区分候选人的能力,最好的办法就是看看候选人的github上的代码仓库...

面试被问 const 是否不可变?这样回答才显功底

作为前端开发者,我在学习ES6特性时,总被const的"善变"搞得一头雾水——为什么用const声明的数组还能push元素?为什么基本类型赋值就会报错?直到翻遍MDN文档、对着内存图反...

2023金九银十必看前端面试题!2w字精品!

导文2023金九银十必看前端面试题!金九银十黄金期来了想要跳槽的小伙伴快来看啊CSS1.请解释CSS的盒模型是什么,并描述其组成部分。...

前端面试总结_前端面试题整理

记得当时大二的时候,看到实验室的学长学姐忙于各种春招,有些收获了大厂offer,有些还在苦苦面试,其实那时候的心里还蛮忐忑的,不知道自己大三的时候会是什么样的一个水平,所以从19年的寒假放完,大二下学...

由浅入深,66条JavaScript面试知识点(七)

作者:JakeZhang转发链接:https://juejin.im/post/5ef8377f6fb9a07e693a6061目录...

2024前端面试真题之—VUE篇_前端面试题vue2020及答案

添加图片注释,不超过140字(可选)...

今年最常见的前端面试题,你会做几道?

在面试或招聘前端开发人员时,期望、现实和需求之间总是存在着巨大差距。面试其实是一个交流想法的地方,挑战人们的思考方式,并客观地分析给定的问题。可以通过面试了解人们如何做出决策,了解一个人对技术和解决问...