排序算法总结(Python)

目录

  • 1. 介绍

    • 1.1 排序算法分类
    • 1.2 关于时间复杂度
    • 1.3 关于稳定性
  • 2. 细节
    • 2.1 冒泡排序
    • 2.2 选择排序
    • 2.3 插入排序
    • 2.4 希尔排序
    • 2.5 归并排序
    • 2.6 快速排序
    • 2.7 堆排序
    • 2.8 计数排序
    • 2.9 桶排序
    • 2.10 基数排序
  • 参考

1. 介绍

1.1 排序算法分类

  1. 内部排序: 数据记录在内存中进行排序
  2. 外部排序: 因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存

1.2 关于时间复杂度

  1. 平方阶(\(O(n^2)\))排序 各类简单排序:直接插入、直接选择和冒泡排序
  2. 线性对数阶(\(O(n\log(n))\))排序:快速排序、堆排序和归并排序
  3. \(O(n^{1+§})\)排序,§是介于0和1之间的常数:希尔排序
  4. 线性阶(\(O(n)\))排序:基数排序,此外还有 桶、箱排序

1.3 关于稳定性

  1. 稳定的排序算法:冒泡排序、插入排序、归并排序和基数排序
  2. 不稳定的排序算法:选择排序、快速排序、希尔排序、堆排序

2. 细节

2.1 冒泡排序

  • 步骤
  1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
  2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
  3. 针对所有的元素重复以上的步骤,除了最后一个。
  4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

  • 实现
def bubble_sort(arr):
    '''
    如果没有逆序对,提前退出循环
    '''
    n = len(arr)
    for i in range(n-1):
        swapped = False
        for j in range(n-1-i):
            if arr[j] > arr[j+1]:
                arr[j],arr[j+1] = arr[j+1],arr[j]
                swapped = True
        # print(arr)
        if not swapped:
            break
    return arr

2.2 选择排序

  • 步骤
  1. 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
  2. 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
  3. 重复第二步,直到所有元素均排序完毕。

  • 实现
def selection_sort(arr):
    n = len(arr)
    for i in range(n):
        min = i
        for j in range(i+1, n):
            if arr[j] < arr[min]:
                min = j
        arr[i],arr[min] = arr[min],arr[i]
        # print(arr)
    return arr

2.3 插入排序

  • 步骤
  1. 将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
  2. 从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)

  • 实现
def insertion_sort(arr):
    n = len(arr)
    for i in range(n):
        cursor = arr[i]
        pos = i
        while pos > 0 and arr[pos-1] > cursor:
            # 大于cursor就一直往前移,前面的数往后补位
            arr[pos] = arr[pos-1]
            pos = pos-1
        # 最后再赋值
        arr[pos] = cursor
        # print(arr)
    return arr

2.4 希尔排序

希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:

  1. 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率
  2. 插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位
    基本思想:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
  • 步骤
  1. 选择一个增量序列\(t_1\), \(t_2\), ... ,\(t_k\),其中\(t_i>t_j\), \(t_k=1\);(序列是递减的)
  2. 按增量序列个数 k,对序列进行 k 趟排序;
  3. 每趟排序,根据对应的增量\(t_i\),将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

  • 实现
def shell_sort(arr):
    '''
    相当于套了一个gap的插入排序:每次排序的对象是数组中间隔gap的元素
    '''
    n = len(arr)
    gap = n//2
    while gap > 0: # gap=0是循环出口
        for i in range(gap, n):
            cursor = arr[i]
            pos = i
            while pos >= gap and arr[pos-gap] > cursor:
                arr[pos] = arr[pos-gap]
                pos -= gap
            arr[pos] = cursor
        # print(arr)
        gap = gap//2
    return arr

2.5 归并排序

  • 步骤
  1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
  2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置;
  3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
  4. 重复步骤 3 直到某一指针达到序列尾;
  5. 将另一序列剩下的所有元素直接复制到合并序列尾。

  • 实现
def merge_sort(arr):
    if len(arr) <= 1:
        return arr
    mid = len(arr)//2
    left,right = arr[:mid],arr[mid:]
    return merge(merge_sort(left), merge_sort(right), arr.copy())

def merge(left, right, merged):
    l,r = 0,0
    while l < len(left) and r < len(right):
        if left[l] <= right[r]:
            merged[l+r] = left[l]
            l+=1
        else:
            merged[l+r] = right[r]
            r+=1
    for l in range(l, len(left)): # 注意这里的l和r
        merged[l+r] = left[l]
    for r in range(r, len(right)):
        merged[l+r] = right[r]
    return merged

2.6 快速排序

快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。本质上来看,快速排序应该算是在冒泡排序基础上的递归分治法
快速排序通常明显比其他 Ο(nlogn) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来

  • 步骤
  1. 从数列中挑出一个元素,称为 "基准"(pivot);
  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;

  • 实现
def partition(arr, low, high):
    i = low-1 # i是小于pivot的数的索引
    pivot = arr[high]

    for j in range(low, high):
        # 遍历low到high,将所有小于pivot的数都提到前面来
        if arr[j] < pivot:
            i += 1
            arr[i],arr[j]=arr[j],arr[i]

    # 将pivot提到索引i之后
    arr[i+1],arr[high]=arr[high],arr[i+1]
    return (i+1)

def quick_sort(arr, low, high):
    if low < high:
        pivot = partition(arr, low, high)
        quick_sort(arr, low, pivot-1)
        quick_sort(arr, pivot+1, high)
    return arr

########################################

def qsort(arr):
    '''
    简化版,利用了python list的特点
    速度很慢,严格意义上不算快排
    '''
    if len(arr) <= 1:
        return arr
    pivot = arr[-1]
    return qsort([x for x in arr[:-1] if x < pivot]) + [pivot] + qsort([x for x in arr[:-1] if x >= pivot])

2.7 堆排序

  • 步骤
  1. 创建一个大顶堆;
  2. 把堆首(最大值)和堆尾互换;
  3. 把堆的尺寸缩小 1,并调用heapify(),目的是把新的数组顶端数据调整到相应位置;
  4. 重复步骤 2,直到堆的尺寸为 1。

  • 实现
def heapify(arr, n, i):
    largest = i
    l = 2 * i + 1
    r = 2 * i + 2

#     arr = [1,2,3,6,4,3,7,8,13,5]
#     print("        {}       ".format(arr[0]))
#     print("    {}       {}   ".format(arr[1], arr[2]))
#     print(" {}    {}   {}   {} ".format(arr[3],arr[4],arr[5],arr[6]))
#     print("{} {} {} ".format(arr[7],arr[8],arr[9]))
#     print("==========================")

    if l < n and arr[i] < arr[l]:
        largest = l 

    if r < n and arr[largest] < arr[r]:
        largest = r 

    if largest != i:
        arr[i],arr[largest] = arr[largest],arr[i]
        heapify(arr, n, largest) 

def heap_sort(arr):
    n = len(arr) 

    # 建立大顶堆:从 n//2-1 逐渐往顶部走
    for i in range(n//2-1, -1, -1):
        heapify(arr, n, i) 

    # 排序
    for i in range(n-1, 0, -1):
        # 交换顶部与末端未排序元素
        arr[i], arr[0] = arr[0], arr[i]
        heapify(arr, i, 0) 

    return arr

2.8 计数排序

计数排序是一种非基于比较的排序算法,其空间复杂度和时间复杂度均为O(n+k),其中k是整数的范围。
计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数

  • 步骤
  1. 花O(n)的时间扫描一下整个序列 A,获取最小值 min 和最大值 max
  2. 开辟一块新的空间创建新的数组 B,长度为 (max - min + 1)
  3. 数组 B 中 index 的元素记录的值是 A 中某元素出现的次数
  4. 最后输出目标整数序列,具体的逻辑是遍历数组 B,输出相应元素以及对应的个数

  • 实现
def counting_sort(arr):

    m = min(arr)
    # 对负数设置一个offset
    offset = 0
    if m < 0:
        offset = -m
        for i in range(len(arr)):
            arr[i] += offset
    k = max(arr)

    temp_arr = [0] * (k + 1)

    for i in range(0, len(arr)):
        temp_arr[arr[i]] += 1

    for i in range(1, k + 1):
        # 向后叠加
        temp_arr[i] += temp_arr[i - 1]

    result_arr = arr.copy()

    for i in range(len(arr) - 1, -1, -1):
        # arr[i]的排位看temp_arr[arr[i]]的数值,并减一(自身)
        result_arr[temp_arr[arr[i]] - 1] = arr[i] - offset
        # 针对重复位情况
        temp_arr[arr[i]] -= 1
    return result_arr

2.9 桶排序

桶排序(Bucket sort)是一种基于计数的排序算法。

  • 步骤
  1. 设置固定数量的空桶。
  2. 把数据放到对应的桶中。
  3. 对每个不为空的桶中数据进行排序。
  4. 拼接不为空的桶中数据,得到结果。

  • 实现
def bucket_sort(arr, bucket_size=5):
    min_value,max_value = min(arr),max(arr)
    bucket_count = (max_value-min_value)//bucket_size + 1
    buckets = [[] for _ in range(bucket_count)]

    for i in arr:
        buckets[(i-min_value)//bucket_size].append(i)

    sorted_list = []
    for bucket in buckets:
        sorted_list.extend(next_sort(bucket))

    return sorted_list

def next_sort(arr):
    # 插入排序
    n = len(arr)
    for i in range(n):
        cursor = arr[i]
        pos = i
        while pos>0 and arr[pos-1]>cursor:
            arr[pos] = arr[pos-1]
            pos -= 1
        arr[pos] = cursor
    return arr

2.10 基数排序

  • 步骤
  1. 建立一个10进制的表记录每个数的基数
  2. 从最低位开始,依次进行一次排序
  3. 从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列

  • 实现
def radix_sort(arr):
    '''
    先按个位排,再按十位排...直到pos>max
    '''
    pos = 1
    max_value = max(arr)
    while pos<max_value:
        queue_list = [list() for _ in range(10)]
        for num in arr:
            digit_number = num // pos % 10
            queue_list[digit_number].append(num)
        index = 0
        for numbers in queue_list:
            for num in numbers:
                arr[index] = num
                index += 1
        pos*=10
    return arr

参考

  1. https://mp.weixin.qq.com/s/vn3KiV-ez79FmbZ36SX9lg
  2. https://www.runoob.com/python3/python3-examples.html
  3. https://github.com/keon/algorithms
  4. https://github.com/TheAlgorithms/Python

原文地址:https://www.cnblogs.com/southtonorth/p/12287415.html

时间: 2024-10-30 05:52:46

排序算法总结(Python)的相关文章

几种常用排序算法的python实现

1:快速排序 思想: 任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序. 一趟快速排序的算法是: 1)设置两个变量i.j,排序开始的时候:i=0,j=N-1: 2)以第一个数组元素作为关键数据,赋值给key,即key=A[0]: 3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]赋给A[i]: 4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大

八大排序算法---基于python

本文节选自:http://python.jobbole.com/82270/ 本文用Python实现了插入排序.希尔排序.冒泡排序.快速排序.直接选择排序.堆排序.归并排序.基数排序. 1.插入排序 描述 插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的.个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2).是稳定的排序方法.插入算法把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外(让数组多一个空间才有插入的位置),

算法导论之所有排序算法的Python实现

最近一段时间学习了算法导论第二版书的第一部分和第二部分的内容,自己编写了其中排序相关的几乎全部算法,包括冒泡排序(bubble sort).选择排序( selection sort).插入排序(insertion sort).希尔排序(shell sort).归并排序(merge sort).快速排序(quick sort).计数排序(count sort).基数排序(radix sort).桶排序(bucket sort).期望线性时间的第k个顺序统计量选择.最坏情况线性时间的中位数选择,并给

基本排序算法的Python实现

本篇主要实现九(八)大排序算法,分别是冒泡排序,插入排序,选择排序,希尔排序,归并排序,快速排序,堆排序,计数排序.希望大家回顾知识的时候也能从我的这篇文章得到帮助. 为了防止误导读者,本文所有概念性内容均截取自对应Wiki 冒泡排序 原理 冒泡排序(Bubble Sort)是一种简单的排序算法.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成.这个算法的名字由来是因为越小的元素会经由交换慢

常用排序算法的python实现和性能分析

http://www.cnblogs.com/wiki-royzhang/p/3614694.html 一年一度的换工作高峰又到了,HR大概每天都塞几份简历过来,基本上一天安排两个面试的话,当天就只能加班干活了.趁着面试别人的机会,自己也把一些基础算法和一些面试题整了一下,可以阶段性的留下些脚印——没办法,平时太忙,基本上没有时间写博客.面试测试开发的话,这些也许能帮得上一些. 这篇是关于排序的,把常见的排序算法和面试中经常提到的一些问题整理了一下.这里面大概有3个需要提到的问题: 虽然专业是数

八大排序算法的python实现(三)冒泡排序

代码: #coding:utf-8 #author:徐卜灵 #交换排序.冒泡排序 L = [1, 3, 2, 32, 5, 4] def Bubble_sort(L): for i in range(len(L)): for j in range(i+1,len(L)): if L[i]>L[j]: # temp = L[j] # L[j] = L[i] # L[i] = temp L[i], L[j] = L[j], L[i]#交换顺序 print L Bubble_sort(L) 冒泡排序应

经典排序算法及python实现

今天我们来谈谈几种经典排序算法,然后用python来实现,最后通过数据来比较几个算法时间 选择排序 选择排序(Selection sort)是一种简单直观的排序算法.它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完. 选择排序是不稳定的排序方法(比如序列[5, 5, 3]第一次就将第一个[5]与[3]交换,导致第一个5挪动到第二个5后面).(注:选自百度百科) 假如,有一个无须序列A={6,3,1,9,2,5,8,7,4},

常用排序算法的python实现

排序算是编程最基本的算法问题之一了,熟练掌握排序算法也能加深自己对数据结构的理解,也能提高自己的编程能力,以下为个人参考许多大神博客后对常用排序算法的学习总结. 目录: 概述 冒泡排序 直接插入排序 简单选择排序 希尔排序 堆排序 归并排序 快速排序 算法的比较与测试 参考 1. 概述 所谓排序(sorting)就是整理数据的序列,使其按照特定顺序排列的操作.排序在现实生活中(如整理书籍,表格数据等),在计算领域中(如二分查找,图论的最小生成树的Kruskal算法)均有重要意义,所以一种高效的排

十大经典排序算法(python实现)(原创)

经典排序算法图解: 经典排序算法的复杂度: 大类一(比较排序法): 1.冒泡排序(Bubble Sort) python代码实现: 1 d0 = [2, 15, 5, 9, 7, 6, 4, 12, 5, 4, 2, 64, 5, 6, 4, 2, 3, 54, 45, 4, 44] 2 d0_out = [2, 2, 2, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 7, 9, 12, 15, 44, 45, 54, 64] # 正确排序 3 4 while 1: 5 stat

八大排序算法的 Python 实现

插入排序: 插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的.个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2).是稳定的排序方法.插入算法把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外(让数组多一个空间才有插入的位置),而第二部分就只包含这一个元素(即待插入元素).在第一部分排序完成后,再将这个最后元素插入到已排好序的第一部分中. 1 def insert_sort(lists): 2 count = len(