十大经典排序算法总结 -- Python实现(逐步完善中)

十大算法简介

  1. 冒泡排序
  2. 选择排序
  3. 插入排序
  4. 希尔排序
  5. 归并排序
  6. 快速排序
  7. 堆排序
  8. 基数排序
  9. 桶排序(待定)
  10. 计数排序(待定)

稳定性

稳定:当a == b时,a、b的相对位置不变: a,b --> a,b;
不稳定:当a == b时,a、b的相对位置可能发生变化:a,b --> b,a。

稳定算法:冒泡排序、插入排序、归并排序、计数排序、桶排序、基数排序
不稳定算法:选择排序、希尔排序、快速排序、堆排序

是否需要额外空间

不需要:冒泡排序、选择排序、插入排序、希尔排序、快速排序、堆排序
需要:归并排序、计数排序、桶排序、基数排序

内排序/外排序

内排序:所有排序操作都在内存中完成;
外排序:排序通过磁盘和内存的数据传输进行,一般用于数据量较大,需要将数据放入磁盘中。

以上算法中,计数排序桶排序属于外排序算法;其他八种算法,均为内排序算法 —— “八大经典排序算法”。

空间复杂度

冒泡排序、选择排序、插入排序、希尔排序、快速排序、堆排序这六种算法不需要额外空间,但快速排序采用了分治的思想,将问题规模通过分治法消减为log n次,增加了空间复杂度,因此:
冒泡排序选择排序插入排序希尔排序堆排序的空间复杂度均为O(1)
快速排序的空间复杂度为O(log n)
归并排序的空间复杂度为O(n)
计数排序的空间复杂度为O(k),"k"是指要排序的序列中最大值和最下值得差,既额外空间,它的空间复杂度与原问题规模无关;
桶排序基数排序的时间复杂度为O(n+k),原问题规模n和桶的数量(额外空间)

1.冒泡排序

算法描述
1.遍历整个序列,比较系列中相邻位置的两个元素,如果元素顺序错误,则交换两个元素的位置;(一趟比较完后,最大的元素位于最右边(已排序))
2.重复步骤1,遍历除最右边外的剩下元素,依次将最大(次大)的元素移至右边相应位置(已排序序列的前面一个位置),直至所有元素排好;;
3.简言之,第一趟比较,将最大的数“冒”出来,放在最后边;然后依次“次大”、“第三大”....
过程演示

原始序列:5 2 47 36 15
第一趟排序:2 5 36 15 47
第二趟排序:2 5 15 36 47
第三趟排序:2 5 15 36 47
已经有序,结束

时间复杂度

冒泡排序最好情况下的时间复杂度为O(n),此时的序列本身就已经排序好;最坏情况下的时间复杂度为O(n2)平均时间复杂度O(n2)

代码
def bubbleSort(arr):
    n = len(arr) # 计算数组长度
    for i in range(n): # 遍历数组
        for j in range(n-i-1):
            if arr[j] > arr[j+1] : # 比较相邻的两个数
                arr[j], arr[j+1] = arr[j+1], arr[j]

2.选择排序

算法描述
1.找出序列中的最小元素,与序列的起始位置的元素交换位置;
2.从剩余未排序元素中继续寻找最小元素,然后与未排序序列的第一个元素交换位置。以此类推,直到所有元素均排序完毕。
过程演示

原始序列:5 2 47 36 15
第一趟排序:2 5 47 36 15
第二趟排序:2 5 47 36 15
第三趟排序:2 5 15 36 47
第四趟排序:2 5 15 36 47

时间复杂度

选择排序在任何情况下的时间复杂度都为O(n2)

代码
def selectSort(arr):
    for i in range(len(arr)):
        min_index = i # 记录最小元素的位置
        for j in range(i + 1, len(arr)):
            if arr[min_index] > arr[j]:
                min_index = j
        arr[i], arr[min_index] = arr[min_index], arr[i] # 将最小元素与序列第一个元素交换位置

3.插入排序

算法描述
1.将第一个数作为已经排序好的序列;
2.依次遍历未排序的元素,将每个元素,从已排序的序列最后往前比较,找到位置插入,,直到所有元素均排序完毕。
过程演示

原始序列:5 2 47 36 15
第一趟排序:2 5 47 36 15
第二趟排序:2 5 47 36 15
第三趟排序:2 5 36 47 36
第四趟排序:2 5 15 36 47

时间复杂度

插入排序最好情况下的时间复杂度为O(n),此时的序列本身就已经排序好;最坏情况下的时间复杂度为O(n2)平均时间复杂度O(n2)

代码
def insertSort(arr):
    for i in range(1, len(arr)):
        temp = arr[i] # 记录arr[i]的值
        j = i - 1
        while j >= 0 and temp < arr[j]:# 遍历arr[i]之前的序列(已经排序好)
            arr[j + 1] = arr[j]
            j -= 1
        arr[j + 1] = temp

4.希尔排序

希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。

算法描述
1.先取一个正整数d1<n,把所有序号相隔d1的数组元素放一组,组内进行直接插入排序;
2.然后取d2<d1,重复上述分组和排序操作;
3.直至di=1,即所有记录放进一个组中排序为止。
过程演示

原始序列:5 2 47 36 15 8 (间隔为:di = d(1-i)//2)
第一趟排序:[5,36], [2,15], [47,8]
5 2 8 36 15 47
第二趟排序:[5,8,15],[2,36,47]
5 2 8 36 15 47
第三趟排序:[5,2,8,36,15,47]
2 5 8 15 36 47

时间复杂度

希尔排序最好情况下的时间复杂度为O(nlog n)最坏情况下的时间复杂度为O(nlog2n)平均时间复杂度O(nlog2n)

代码
def shellSort(arr):
    n = len(arr)
   d = n // 2
    while d > 0:
        for i in range(d, n):
            temp = arr[i]
            j = i
            while j >= d and arr[j - d] > temp:
                arr[j] = arr[j - d]
                j -= d
            arr[j] = temp
        d = d // 2

5.归并排序

算法描述
1.分割:递归地把当前序列平均分割成两半;
2.集成:在保持元素顺序的同时,将上一步得到的子序列集成到一起(归并)。
过程演示

原始序列:5 2 47 36 15 8 9 6
第一趟排序:2 5 36 47 8 15 6 9
第二趟排序:2 5 36 47 6 8 9 15
第三趟排序:2 5 6 8 9 15 36 47

时间复杂度

归并排序在任何情况下的时间复杂度都为O(n long n)

代码
def merge(arr, l, m, r):
    n1 = m - l + 1
    n2 = r - m
    # 创建临时数组
    L = [0] * (n1)
    R = [0] * (n2)
    for i in range(0, n1):  # 拷贝数据到临时数组 arrays L[] 和 R[]
        L[i] = arr[l + i]
    for j in range(0, n2):
        R[j] = arr[m + 1 + j]
    i = 0  # 初始化第一个子数组的索引
    j = 0  # 初始化第二个子数组的索引
    k = l  # 初始归并子数组的索引
    while i < n1 and j < n2:
        if L[i] <= R[j]:
            arr[k] = L[i]
            i += 1
        else:
            arr[k] = R[j]
            j += 1
        k += 1
    while i < n1:  # 拷贝 L[] 的保留元素
        arr[k] = L[i]
        i += 1
        k += 1
    while j < n2: # 拷贝 R[] 的保留元素
        arr[k] = R[j]
        j += 1
        k += 1
def mergeSort(arr, l, r):
    if l < r:
        m = int((l + (r - 1)) / 2)
        mergeSort(arr, l, m)
        mergeSort(arr, m + 1, r)
        merge(arr, l, m, r)

6.快速排序

算法描述
1.选取一个关键字(通常是第一个)作为枢轴,将序列中比枢轴小的移到枢轴的前边,比枢轴大的移动到枢轴的后边;
2.先将关键字与最后一个数(右边)比较,如果最后一个数比关键字大,与倒数第二个数比较...直到遇到比关键字小的数,交换两者位置;
3.再将关键字与第一个数(左边)比较,找到比关键大的数,交换两者位置;
4.重复步骤2和步骤3,遍历完整个序列,第一趟排序完成,此时关键字左边都是比关键字小的元素,右边是比关键字大的元素;
5.将上述关键字两边,作为两个新的子序列,重复步骤2和步骤3,直到子序列的长度为0或1,排序完成。
过程演示

原始序列:15 2 47 36 5 8 9 6
第一趟排序:6 2 9 8 5 15 36 47
说明:将 15 作为关键字,和最右边元素 6 进行比较,6比15小,交换位置:6 2 47 36 5 8 9 15;
再将15 与左边数字进行比较(6不用再比较了),2,不用交换,47比15大,交换:6 2 15 36 5 8 9 47;
再回到右边,与 9 比较,9比15小,交换:6 2 9 36 5 8 15 47;
再回到左边,与36比较,36比15大,交换:6 2 9 15 5 8 36 47;
再回到右边,与8比较,8比15小,交换:6 2 9 8 5 15 36 47;
第一趟排序完成。
第二趟排序:5 2 6 8 9 15 36 47
第三趟排序:2 5 6 8 9 15 36 47

时间复杂度

快速排序最好情况下的时间复杂度为O(nlog n)最坏情况下的时间复杂度为O(n2)平均时间复杂度O(nlog n)

:快速排序最坏的情况是,原始序列为倒序,此时快速排序倒退为冒泡排序

代码
def quickSort(arr, low, high): # 对从R[Low]到R[High]的关键字进行排序
    temp = 0
    i = low
    j = high
    if low < high:
        temp = arr[low]
        while i < j: # 每次循环完成了一趟排序,即数组中小于temp的关键字放在左边,大于temp的关键字放在右边;左边和右边的分界点就是temp的最终位置
            while i < j and arr[j] >= temp: # 先从右往左扫描,找到第一个小于temp的关键字
                j -= 1
            if i < j: # 这个判断保证退出上面的while循环是因为R[j] < temp,而不是因为 i >= j退出循环的,此步非常重要切忌将其忽略
                arr[i] = arr[j] # 放在temp左边
                i += 1 # i右移一位
            while i < j and arr[i] <= temp: # 从右往左扫描,找到一个大于temp的关键字
                i += 1
            if i < j:
                arr[j] = arr[i] # 放在tem的左边
                j -= 1 # j左移一位
        arr[j] = temp # 将temp放在最终的位置上
        quickSort(arr, low, i - 1) # 递归的对temp左边的关键字进行排序
        quickSort(arr, i + 1, high) # 递归的对temp右边的关键字进行排序

7.堆排序

堆是一种完全二叉树,堆排序分为大根堆排序(正序)和小根堆排序(逆序):大根堆指父节点元素的值大于等于子节点的值,这样每次排序都可以找到未排序序列的最大值;小根堆指父节点元素的值小于等于子节点的值,这样每次排序都可以找到未排序序列的最小值;本文以大根堆为例。

算法描述
1.将序列排成一个完全二叉树,从树的第一个非叶子结点开始,从左至右,从上至下,对每个结点进行调整,直到得到一个大根堆;
对结点的调整方法:将当前结点(假设为A)的值与其孩子结点进行比较,如果存在大于A的值的孩子结点,则从中挑出最大的一个与A进行交换;
当A来到下一层的时候重复上述过程,直到A的孩子结点的值都小于A的值为止。
2.将步骤1中的大根堆,除去根节点(最大值)外的序列,按照步骤1重新排序,依次获得次大值,第三大....直到序列中的元素个数为1时,结束排序。
过程演示

原始序列:15 2 47 36 5 8 9 6
第一趟排序:47 15 36 6 5 8 9 2
第二趟排序:47 36 15 9 5 8 6 2
第三趟排序:47 36 15 9 5 8 6 2
第四趟排序:47 36 15 9 6 8 5 2
第五趟排序:47 36 15 9 8 6 5 2
第六趟排序:47 36 15 9 8 6 5 2
第七趟排序:47 36 15 9 8 6 5 2

时间复杂度

堆排序在任何情况下的时间复杂度都为O(n long n)

代码
def heapify(arr, n, i):
    largest = i
    l = 2 * i + 1  # left = 2*i + 1 
    r = 2 * i + 2  # right = 2*i + 2 
    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 heapSort(arr):
    n = len(arr)
    for i in range(n, -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)

8.基数排序

算法描述
1.首先根据个位数的数值,将序列中的数值,分配至编号0到9的桶中,再将桶中的数串联起来组成一个新序列:
2.将第一步中的新序列,根据十位数的数值,重新分配至编号0到9的桶中,再串联起来;
3.后面依次根据百位、千位....重新分配、串联,持续进行到最高位结束。
过程演示

原始序列:73 22 93 43 55 14 28 65 39 81
第一趟排序:81 22 73 93 43 14 55 65 28 39
0 1 2 3 4 5 6 7 8 9
81 22 73 14 55 28 39
93 65
43
第二趟排序:14 22 28 39 43 55 65 73 81 93
0 1 2 3 4 5 6 7 8 9
14 22 39 43 55 65 73 81 93

时间复杂度

基数排序在任何情况下的时间复杂度都为O(n * k)(k为需要桶的数量)。

import math
def radixSort(arr, radix=10): # radix为桶的数量
    K = int(math.ceil(math.log(max(arr), radix))) # 用K位数可表示任意整数
    bucket = [[] for i in range(radix)] # 开辟桶的数组
    for i in range(1, K+1): # K次循环
        for val in arr:
            bucket[val%(radix**i)//(radix**(i-1))].append(val) # 析取整数第K位数字 (从低到高)
        del arr[:]
        for each in bucket:
            arr.extend(each) # 桶合并
        bucket = [[] for i in range(radix)]

9.桶排序(待定)

10.计数排序(待定)

### 回答1: AIS (Adaptive Incremental Smoothing) 轨迹压缩算法是一种精度可控的轨迹压缩算法,适用于传感器网络、移动设备等限制资源的环境。算法思路是利用数据点之间的距离信息,逐步降低轨迹精度,直到压缩比例满足用户设定的阈值,从而达到最小化轨迹数据量,保证压缩后轨迹与原始轨迹的误差在用户容忍范围内的目的。 在 Python 实现 AIS 轨迹压缩算法的具体步骤如下: 1. 导入必要的库和模块。包括 NumPy、SciPy、Matplotlib 等。 2. 定义一个叫做“compute_distance”的函数,用于计算数据点之间的距离。可以使用欧几里得距离、曼哈顿距离等多种距离定义,根据具体需求而定。 3. 定义一个叫做“smooth_trajectory”的函数,用于根据用户设定的压缩比例和距离信息,实现逐步降低轨迹精度。具体过程是:首先按照一定的间隔计算原始轨迹相邻点之间的距离;然后根据用户设定的压缩比例,选择相邻数据点之间的最大距离作为窗口大小,对每个窗口内的数据点进行平滑处理,即采用均值或者位数等方法得到一个新的数据点作为压缩后的点。重复进行此操作,直到达到用户设定的压缩比例。 4. 进行数据可视化,比较压缩前后的轨迹。 总之,AIS 轨迹压缩算法是一种高效可控的轨迹压缩方法,在 Python 等编程语言都有较为完善的实现。在实际应用,可以根据具体需求和环境选择最适合的算法和实现方式,以达到最佳的压缩效果。 ### 回答2: AIS(Adaptive Image Segmentation)轨迹压缩算法是一种可以实现轨迹数据压缩的算法,使用Python进行实现。该算法首先对轨迹数据进行抽稀处理,将数据进行一定程度的简化。然后,通过聚类算法将轨迹数据进行分组,使得轨迹之间有一定的相似性。最后,利用不同分组间的相似度进行相应的压缩处理,实现轨迹数据的压缩。 在Python实现AIS轨迹压缩算法可以使用scikit-learn库的聚类算法实现轨迹的分组。此外,还可以使用pandas库进行数据的处理和分析。对于大规模数据的处理,也可以使用多线程技术进行加速处理。 总之,AIS轨迹压缩算法是一种非常有效的数据压缩算法,可以在保证数据质量的前提下实现数据的压缩,同时使用Python进行实现也十分方便。 ### 回答3: AIS(Adaptive-Interval-Smooth)轨迹压缩算法是一种常用的轨迹数据压缩技术。该算法可以在存在大量轨迹数据时,将数据量压缩至合理的大小,并保留轨迹信息的完整性。Python是一种广泛使用的编程语言,拥有强大的数据处理和分析功能,因此使用Python实现AIS轨迹压缩算法非常合适。 在Python实现AIS轨迹压缩算法的步骤如下:首先读取轨迹数据,将数据按时间轴排序,并将轨迹点按照距离相近的方式合并成线段。然后,通过调整参数来自适应地压缩每个线段,并确保良好的压缩效果。最后,将所有压缩后的轨迹数据合并成一个数据集,可以进行可视化显示或进行其他数据分析操作。 使用Python实现AIS轨迹压缩算法,可以大大提高数据处理的效率和精度,并且可以进行更加复杂和多样化的数据分析。由于Python语言强大的数据处理和可视化功能,它已成为轨迹数据分析领域的重要工具和编程语言。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值