在数据结构中常见的排序方法有:
插入排序、交换排序、选择排序、归并排序和基数排序等。
- 插入排序
- 特点:
- 简单直观,对于小规模的数据排序效率较高。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
- 稳定排序算法,即相等元素的相对顺序在排序前后保持不变。
- 方法:
- 假设第一个元素已经有序,从第二个元素开始,将当前元素与前面已排序的元素依次比较。如果当前元素小于前面的元素,则将前面的元素后移,直到找到合适的位置插入当前元素。例如,对于数组
[5, 3, 4, 6, 1]
,首先认为5
是有序的,处理3
时,因为3 < 5
,将5
后移一位,把3
插入到第一个位置,得到[3, 5, 4, 6, 1]
,以此类推。
- 假设第一个元素已经有序,从第二个元素开始,将当前元素与前面已排序的元素依次比较。如果当前元素小于前面的元素,则将前面的元素后移,直到找到合适的位置插入当前元素。例如,对于数组
- 时间复杂度:
- 最好情况:数据已经有序,时间复杂度为 O ( n ) O(n) O(n),此时只需要进行 n − 1 n - 1 n−1次比较操作,不需要移动元素。
- 最坏情况:数据是逆序的,时间复杂度为 O ( n 2 ) O(n^2) O(n2),每次插入一个元素都需要移动已排序的所有元素。
- 平均情况:时间复杂度为 O ( n 2 ) O(n^2) O(n2)。
- 空间复杂度:
- 空间复杂度为 O ( 1 ) O(1) O(1),因为它只需要一个额外的临时变量来辅助插入操作。
- 特点:
- 交换排序(以冒泡排序为例)
- 特点:
- 也是一种简单的排序算法。它重复地走访要排序的数列,一次比较两个元素,如果顺序不对则进行交换,并一直重复这样的走访操作,直到没有要交换的元素为止。
- 稳定排序算法。
- 方法:
- 从数列的第一个元素开始,依次比较相邻的两个元素。如果前一个元素大于后一个元素,则交换它们的位置。经过第一轮比较后,最大的元素会“浮”到数组的末尾。例如对于数组
[4, 3, 7, 5, 6]
,第一轮比较交换后得到[3, 4, 5, 6, 7]
。
- 从数列的第一个元素开始,依次比较相邻的两个元素。如果前一个元素大于后一个元素,则交换它们的位置。经过第一轮比较后,最大的元素会“浮”到数组的末尾。例如对于数组
- 时间复杂度:
- 最好情况:数据已经有序,时间复杂度为 O ( n ) O(n) O(n),只需要进行一次遍历,比较次数为 n − 1 n - 1 n−1,不需要交换元素。
- 最坏情况:数据是逆序的,时间复杂度为 O ( n 2 ) O(n^2) O(n2),总共需要进行 n ( n − 1 ) / 2 n(n - 1)/2 n(n−1)/2次比较和交换操作。
- 平均情况:时间复杂度为 O ( n 2 ) O(n^2) O(n2)。
- 空间复杂度:
- 空间复杂度为 O ( 1 ) O(1) O(1),因为只需要一个临时变量来进行元素交换。
- 特点:
- 选择排序
- 特点:
- 简单直观,但效率相对较低。它的基本思想是每次在未排序的序列中选择最小(或最大)的元素,将其放到已排序序列的末尾(或开头)。
- 不稳定排序算法,例如序列
[5, 5, 3]
,排序后可能会变成[3, 5, 5]
,两个5
的相对顺序发生了改变。
- 方法:
- 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。例如对于数组
[6, 4, 8, 3]
,第一轮找到最小元素3
,与第一个元素6
交换,得到[3, 4, 8, 6]
,然后继续在剩余元素[4, 8, 6]
中寻找最小元素进行交换。
- 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。例如对于数组
- 时间复杂度:
- 最好情况、最坏情况和平均情况的时间复杂度都是 O ( n 2 ) O(n^2) O(n2),因为无论数据的初始顺序如何,都需要进行 n ( n − 1 ) / 2 n(n - 1)/2 n(n−1)/2次比较操作。
- 空间复杂度:
- 空间复杂度为 O ( 1 ) O(1) O(1),因为只需要一个临时变量来交换元素。
- 特点:
- 归并排序
- 特点:
- 是一种高效的基于分治策略的排序算法。它将一个数组分成两个子数组,对每个子数组进行排序,然后将排好序的子数组合并成一个最终的排序数组。
- 稳定排序算法。
- 方法:
- 分解:将待排序的序列分成两个子序列,直到每个子序列只有一个元素。例如对于数组
[5, 3, 8, 4]
,可以先分成[5, 3]
和[8, 4]
,然后[5, 3]
再分成[5]
和[3]
,[8, 4]
分成[8]
和[4]
。 - 合并:将两个已排序的子序列合并成一个有序序列。比如合并
[3]
和[5]
得到[3, 5]
,合并[4]
和[8]
得到[4, 8]
,然后再合并[3, 5]
和[4, 8]
得到[3, 4, 5, 8]
。
- 分解:将待排序的序列分成两个子序列,直到每个子序列只有一个元素。例如对于数组
- 时间复杂度:
- 时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn),在每次合并操作中,都需要遍历 n n n个元素,一共需要进行 l o g n logn logn次合并操作。
- 空间复杂度:
- 空间复杂度为 O ( n ) O(n) O(n),因为在合并过程中需要一个额外的数组来存储临时的排序结果。
- 特点:
- 基数排序
- 特点:
- 属于非比较排序算法,它是根据数字的每一位来排序。适用于整数排序,特别是对位数固定的整数排序效率较高。
- 稳定排序算法。
- 方法:
- 以整数排序为例,假设要对一组整数按照个位、十位、百位等依次进行排序。首先,根据个位数的值将元素分配到对应的桶中,然后按照桶的顺序收集元素,接着根据十位数的值再次分配到桶中,重复这个过程,直到最高位排序完成。例如对于数组
[123, 456, 789, 101]
,先按照个位数字排序,然后十位,百位。
- 以整数排序为例,假设要对一组整数按照个位、十位、百位等依次进行排序。首先,根据个位数的值将元素分配到对应的桶中,然后按照桶的顺序收集元素,接着根据十位数的值再次分配到桶中,重复这个过程,直到最高位排序完成。例如对于数组
- 时间复杂度:
- 时间复杂度为 O ( d ( n + k ) ) O(d(n + k)) O(d(n+k)),其中 d d d是数字的最大位数, n n n是元素个数, k k k是进制数(例如十进制中 k = 10 k = 10 k=10)。
- 空间复杂度:
- 空间复杂度为 O ( n + k ) O(n + k) O(n+k),需要 k k k个桶来存储元素,每个桶的大小可能为 n n n。
- 特点: