数据结构与算法 排序算法-基数排序

基数排序

计数排序,它适用于数据量 n 较大但数据范围 m 较小的情况。假设我们需要对 n = 10^6 个学号进行排序,而学号是一个 8 位数字,这意味着数据范围 m = 10^8 非常大,使用计数排序需要分配大量内存空间,而基数排序可以避免这种情况。

「基数排序 Radix Sort」的核心思想与计数排序一致,也通过统计个数来实现排序。在此基础上,基数排序利用数字各位之间的递进关系,依次对每一位进行排序,从而得到最终的排序结果。

算法流程

以学号数据为例,假设数字的最低位是第 1 位,最高位是第 8 位,基数排序的步骤如下:

阅读更多

数据结构与算法 排序算法-桶排序

桶排序

前述的几种排序算法都属于“基于比较的排序算法”,它们通过比较元素间的大小来实现排序。此类排序算法的时间复杂度无法超越 O(n log n) 。接下来,我们将探讨几种“非比较排序算法”,它们的时间复杂度可以达到线性水平。

「桶排序 Bucket Sort」是分治思想的一个典型应用。它通过设置一些具有大小顺序的桶,每个桶对应一个数据范围,将数据平均分配到各个桶中;然后,在每个桶内部分别执行排序;最终按照桶的顺序将所有数据合并。

算法流程

考虑一个长度为 n 的数组,元素是范围 [0, 1) 的浮点数。桶排序的流程如下:

阅读更多

数据结构与算法 排序算法-计数排序

「计数排序 Counting Sort」通过统计元素数量来实现排序,通常应用于整数数组。

简单实现

先来看一个简单的例子。给定一个长度为 n 的数组 nums ,其中的元素都是“非负整数”。计数排序的整体流程如下:

  1. 遍历数组,找出数组中的最大数字,记为 m ,然后创建一个长度为 m + 1 的辅助数组 counter
  2. 借助 counter 统计 nums 中各数字的出现次数,其中 counter[num] 对应数字 num 的出现次数。统计方法很简单,只需遍历 nums(设当前数字为 num),每轮将 counter[num] 增加 1 即可。
阅读更多

数据结构与算法 排序算法-归并排序

「归并排序 Merge Sort」基于分治思想实现排序,包含“划分”和“合并”两个阶段:

  1. 划分阶段:通过递归不断地将数组从中点处分开,将长数组的排序问题转换为短数组的排序问题;
  2. 合并阶段:当子数组长度为 1 时终止划分,开始合并,持续地将左右两个较短的有序数组合并为一个较长的有序数组,直至结束;

归并排序的划分与合并阶段

算法流程

“划分阶段”从顶至底递归地将数组从中点切为两个子数组,直至长度为 1 ;

阅读更多

数据结构与算法 排序算法-堆排序

「堆排序 Heap Sort」是一种基于堆数据结构实现的高效排序算法。我们可以利用已经学过的“建堆操作”和“元素出堆操作”实现堆排序:

  1. 输入数组并建立小顶堆,此时最小元素位于堆顶。
  2. 不断执行出堆操作,依次记录出堆元素,即可得到从小到大排序的序列。

以上方法虽然可行,但需要借助一个额外数组来保存弹出的元素,比较浪费空间。在实际中,我们通常使用一种更加优雅的实现方式。

算法流程

设数组的长度为 n ,堆排序的流程如下:

  1. 输入数组并建立大顶堆。完成后,最大元素位于堆顶。
阅读更多

数据结构与算法 排序算法-快速排序

「快速排序 Quick Sort」是一种基于分治思想的排序算法,运行高效,应用广泛。

快速排序的核心操作是「哨兵划分」,其目标是:选择数组中的某个元素作为“基准数”,将所有小于基准数的元素移到其左侧,而大于基准数的元素移到其右侧。具体来说,哨兵划分的流程为:

  1. 选取数组最左端元素作为基准数,初始化两个指针 ij 分别指向数组的两端;
  2. 设置一个循环,在每轮中使用 ij)分别寻找第一个比基准数大(小)的元素,然后交换这两个元素;
  3. 循环执行步骤 2. ,直到 ij 相遇时停止,最后将基准数交换至两个子数组的分界线;
阅读更多

数据结构与算法 排序算法-插入排序

「插入排序 Insertion Sort」是一种简单的排序算法,它的工作原理与手动整理一副牌的过程非常相似。

具体来说,我们在未排序区间选择一个基准元素,将该元素与其左侧已排序区间的元素逐一比较大小,并将该元素插入到正确的位置。

回忆数组的元素插入操作,设基准元素为 base ,我们需要将从目标索引到 base 之间的所有元素向右移动一位,然后再将 base 赋值给目标索引。

单次插入操作

阅读更多

数据结构与算法 排序算法-选择排序

「选择排序 Selection Sort」的工作原理非常直接:开启一个循环,每轮从未排序区间选择最小的元素,将其放到已排序区间的末尾。

设数组的长度为 n ,选择排序的算法流程如下:

  1. 初始状态下,所有元素未排序,即未排序(索引)区间为 [0, n-1] 。
  2. 选取区间 [0, n-1] 中的最小元素,将其与索引 0 处元素交换。完成后,数组前 1 个元素已排序。
  3. 选取区间 [1, n-1] 中的最小元素,将其与索引 1 处元素交换。完成后,数组前 2 个元素已排序。
  4. 以此类推。经过 n - 1 轮选择与交换后,数组前 n - 1 个元素已排序。
  5. 仅剩的一个元素必定是最大元素,无需排序,因此数组排序完成。
阅读更多

算法与数据结构 排序算法

常见的排序算法

  • 选择排序是一种基于比较的排序算法,其基本思想是在每个回合中从未排序部分找出最小(或最大)元素,将其与已排序部分的末尾进行交换,以此类推,直至整个序列有序。该算法具有简单直观的特点,但时间复杂度较高,为O(n²),且不具备稳定性。

  • 冒泡排序通过交换相邻元素来实现排序。通过添加一个标志位来实现提前返回,我们可以将冒泡排序的最佳时间复杂度优化到 O(n) 。

  • 插入排序每轮将未排序区间内的元素插入到已排序区间的正确位置,从而完成排序。虽然插入排序的时间复杂度为 O(n²) ,但由于单元操作相对较少,它在小数据量的排序任务中非常受欢迎。

阅读更多

数据结构与算法 排序算法-冒泡排序

「冒泡排序 Bubble Sort」通过连续地比较与交换相邻元素实现排序。这个过程就像气泡从底部升到顶部一样,因此得名冒泡排序。

我们可以利用元素交换操作模拟上述过程:从数组最左端开始向右遍历,依次比较相邻元素大小,如果“左元素 > 右元素”就交换它俩。遍历完成后,最大的元素会被移动到数组的最右端。

1
利用元素交换操作模拟冒泡

2
bubble_operation_step2

阅读更多