九种排序方法(冒泡、选择、插入、希尔、归并、快速、计数、桶、基数)

一、冒泡排序

冒泡排序的名字来源于这个过程:就像水中的气泡从底部向上浮到水面一样,较大的元素会逐步移动到数组的末尾。
我们使用「冒泡」的方式来模拟一下这个过程:

  1. 将数组元素想象成大小不同的「泡泡」,值越大的元素「泡泡」越大。
  2. 从左到右依次比较相邻的两个元素。
  3. 如果左侧元素大于右侧元素,则交换位置。
  4. 每完成一趟遍历,最大的元素就会「浮」到最右侧。

算法步骤

对于长度为𝑛 的数组,冒泡排序的步骤如下:
第 1 趟冒泡:对前𝑛 个元素依次比较相邻元素,将较大的元素向右交换,最终使最大值移动到数组末尾(第𝑛 个位置)。

  1. 比较第 1 个和第 2 个元素,如果前者大于后者则交换。
  2. 比较第 2 个和第 3 个元素,如果前者大于后者则交换。
  3. 以此类推,直到比较第𝑛 − 1 个和第𝑛 个元素。
  4. 完成后,最大元素已位于末尾。

第 2 趟冒泡:对前𝑛 − 1 个元素重复上述过程,将次大值移动到倒数第二个位置(第𝑛 − 1 个位置)。

  1. 比较第 1 个和第 2 个元素,如果前者大于后者则交换。
  2. 比较第 2 个和第 3 个元素,如果前者大于后者则交换。
  3. 以此类推,直到比较第𝑛 − 2 个和第𝑛 − 1 个元素。

完成后,次大元素已位于倒数第二位。
持续进行上述冒泡过程,每一趟比较的元素个数递减,直到某一趟未发生任何交换,说明数组已完全有序,排序结束。

以数组[5, 2, 3, 6, 1, 4] 为例,演示一下冒泡排序的算法步骤。

图片2

二、选择排序

选择排序(Selection Sort)基本思想是将数组分为两个区间:左侧为已排序区间,右侧为未排序区间。每趟从未排序区间中选择最小的元素,放到已排序区间的末尾。

算法步骤

假设数组长度为𝑛,选择排序的算法步骤如下:

  1. 初始状态:已排序区间为空,未排序区间为[0, 𝑛 − 1]。
  2. 第 𝑖 趟选择(𝑖 从 1 开始):
  3. 在未排序区间[𝑖 − 1, 𝑛 − 1] 中找到最小元素的位置𝑚𝑖𝑛_𝑖。
  4. 将位置𝑖 − 1 的元素与位置𝑚𝑖𝑛_𝑖 的元素交换。
  5. 此时[0, 𝑖 − 1] 为已排序区间,[𝑖, 𝑛 − 1] 为未排序区间。
  6. 重复步骤 2,直到未排序区间为空,排序完成。

以数组[5, 2, 3, 6, 1, 4] 为例,演示一下选择排序的算法步骤。

图片3

图片4

图片5

图片6

三、插入排序

插入排序(Insertion Sort)基本思想是将数组分为有序区间和无序区间,每次从无序区间取出一个元素插入到有序区间的正确位置。

算法步骤

假设数组nums长度为𝑛,算法步骤如下:

  1. 初始化:有序区间为[0, 0],无序区间为[1, 𝑛 − 1]
  2. 第 𝑖 趟插入(𝑖 从 1 到𝑛 − 1):
    • 取出无序区间第一个元素nums[𝑖]
    • 从右到左遍历有序区间,将大于nums[𝑖] 的元素右移一位
    • 找到合适位置后插入nums[𝑖]
    • 有序区间扩展为[0, 𝑖],无序区间变为[𝑖 + 1, 𝑛 − 1]

以数组[5, 2, 3, 6, 1, 4] 为例,演示一下插入排序的算法步骤。

插入排序

四、希尔排序

希尔排序(Shell Sort)基本思想是通过设定不同的间隔(gap),将数组分组进行插入排序,然后逐步缩小间隔直至为 1,最终完成整个数组的排序。

算法步骤

假设数组长度为𝑛,算法步骤如下:

  1. 设定初始间隔gap = n / 2。
  2. 按间隔将数组分组,对每组进行插入排序。
  3. 缩小间隔gap = gap / 2。
  4. 重复步骤 2 ∼ 3,直到gap = 1。5. 最后对整个数组进行一次插入排序。

以数组[7, 2, 6, 8, 0, 4, 1, 5, 9, 3] 为例,演示一下希尔排序的算法步骤。

希尔排序

五、归并排序

归并排序(Merge Sort)基本思想是利用分治法,将数组递归地一分为二,直至每个子数组只包含一个元素。随后,将这些有序子数组两两合并,最终得到一个整体有序的数组。

算法步骤

假设数组的元素个数为 𝑛 个,则归并排序的算法步骤如下:

分解过程:递归地将当前数组平分为两部分,直到每个子数组只包含一个元素为止。

  1. 找到数组的中间位置 mid ,将数组划分为左、右两个子数组 left_nums 和 right_nums。
  2. 分别对 left_nums 和 right_nums 递归执行分解操作。
  3. 最终将原数组拆分为 𝑛 个长度为 1 的有序子数组。

归并过程:从长度为 1 的有序子数组开始,逐步将相邻的有序子数组两两合并,最终合并为一个长度为𝑛 的有序数组。

  1. 新建数组nums用于存放合并后的有序结果。
  2. 设置两个指针 left_𝑖 和 right_𝑖,分别指向 left_nums 和 right_nums 的起始位置。
  3. 比较两个指针所指元素,将较小者加入结果数组 nums ,并将对应指针后移一位。
  4. 重复上述操作,直到某一指针到达对应子数组末尾。
  5. 将另一个子数组剩余的所有元素依次加入结果数组 nums 。
  6. 返回合并后的有序数组 nums 。

以数组[0, 5, 7, 3, 1, 6, 8, 4] 为例,演示一下归并排序的算法步骤。

归并排序

六、快速排序

快速排序(Quick Sort)基本思想:采用分治策略,选择一个基准元素,将数组分为两部分:小于基准的元素放在左侧,大于基准的元素放在右侧。然后递归地对左右两部分进行排序,最终得到有序数组。

算法步骤

快速排序的核心是 分区操作,具体步骤如下:

  1. 选择基准:从数组中选择一个元素作为基准值(通常选择第一个元素)
  2. 分区操作:
    • 使用双指针法,左指针从数组开始,右指针从数组末尾
    • 右指针向左移动,找到第一个小于基准值的元素
    • 左指针向右移动,找到第一个大于基准值的元素
    • 交换这两个元素
    • 重复上述过程,直到左右指针相遇
    • 将基准值放到正确位置(左右指针相遇处)
  3. 递归排序:对基准值左右的两个子数组分别进行快速排序

以数组[4, 7, 5, 2, 6, 1, 3] 为例,先来演示一下快速排序的分区操作过程。

快速排序1

快速排序2

快速排序3

快速排序4

完成一次分区后,数组被分为三部分:左子数组、基准值、右子数组。然后递归地对左右子数组进行排序。

快速排序5

七、计数排序

计数排序(Counting Sort)基本思想是统计数组中每个元素出现的次数,然后根据统计信息将元素按顺序放置到正确位置,实现排序。

算法步骤

  1. 确定数值范围:找出数组中的最大值和最小值,计算数值范围。
  2. 创建计数数组:创建一个大小为数值范围的数组,用于统计每个元素出现的次数。
  3. 统计元素频次:遍历原数组,统计每个元素出现的次数。
  4. 计算累积频次:将计数数组转换为累积频次数组,表示每个元素在排序后数组中的位置。
  5. 逆序填充结果:逆序遍历原数组,根据累积频次将元素放入正确位置。

以数组[3, 0, 4, 2, 5, 1, 3, 1, 4, 5] 为例,演示一下计数排序的算法步骤。

计数排序

八、桶排序

桶排序(Bucket Sort)是将待排序元素分散到多个桶中,对每个桶单独排序后合并。

算法步骤

  1. 确定桶的数量:根据待排序数组的数值范围,将其划分为𝑘 个桶,每个桶对应一个特定的区间。
  2. 元素分配:遍历数组,将每个元素根据其数值映射到所属的桶中。
  3. 桶内排序:对每个非空桶分别进行排序(可选用插入排序、归并排序、快速排序等算法)。
  4. 合并结果:按桶的顺序依次合并所有已排序的桶,得到最终有序数组。

以数组[39, 49, 8, 13, 22, 15, 10, 30, 5, 44] 为例,演示一下桶排序的算法步骤。

桶排序

九、基数排序

基数排序(Radix Sort)基本思想是按照数字的每一位进行排序,从最低位到最高位,逐位比较。

算法步骤

基数排序算法可以采用「最低位优先法(Least Significant Digit First)」或者「最高位优先法(Most Significant Digit first)」。最常用的是「最低位优先法」。
下面我们以最低位优先法为例,讲解一下算法步骤。

  1. 确定最大位数:遍历数组元素,找到数组中最大值的位数。
  2. 从最低位(个位)开始,到最高位为止,逐位对每一位进行排序:
  • 创建 10 个桶(每个桶分别代表 0 ∼ 9 中的一个数字)。
  • 按照每个元素当前位上的数字,将元素放入对应桶中。
  • 清空原始数组,然后按照桶的顺序依次取出对应元素,重新加入到数组中。

我们以[692, 924, 969, 503, 871, 704, 542, 436] 为例,演示一下基数排序的算法步骤。

基数排序

各算法对比

排序算法 最好时间复杂度 平均时间复杂度 最坏时间复杂度 空间复杂度 稳定性
冒泡排序 O(n) O(n²) O(n²) O(1) ✅ 稳定
选择排序 O(n²) O(n²) O(n²) O(1) ❌ 不稳定
插入排序 O(n) O(n²) O(n²) O(1) ✅ 稳定
希尔排序 O(n log n) ~ O(n) 约 O(n^1.3) O(n²) O(1) ❌ 不稳定
归并排序 O(n log n) O(n log n) O(n log n) O(n) ✅ 稳定
快速排序 O(n log n) O(n log n) O(n²) O(log n) ❌ 不稳定
计数排序 O(n + k) O(n + k) O(n + k) O(n + k) ✅ 稳定
桶排序 O(n + k) O(n + k) O(n²) O(n + k) 视实现而定
基数排序 O(d(n + k)) O(d(n + k)) O(d(n + k)) O(n + k) ✅ 稳定
posted @ 2026-03-02 16:11  王正义的学习笔记  阅读(122)  评论(0)    收藏  举报