简单选择排序
算法步骤
- 遍历数列,找到最小的值,置于第1位
- 从第2位开始,遍历数列,找到最小的值,置于第2位
- 以此类推,直到开始位置变为最后一位,排序结束。
示例
我们取 3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48 来进行示范
-
第1轮排序,从第1位 3 开始,遍历数列,找到最小值 2,将其置于第1位,即与 3 交换位置,得 2, 44, 38, 5, 47, 15, 36, 26, 27, 3, 46, 4, 19, 50, 48
-
第2轮排序,从第2位 44 开始,遍历数列,找到最小值 3,将其置于第2位,即与 44 交换位置,得 2, 3, 38, 5, 47, 15, 36, 26, 27, 44, 46, 4, 19, 50, 48
-
第3轮排序,从第3位 38 开始,遍历数列,找到最小值 4,将其置于第3位,即与 38 交换位置,得 2, 3, 4, 5, 47, 15, 36, 26, 27, 44, 46, 38, 19, 50, 48
-
以此类推,直到开始位置变为最后一位,排序结束。
动态图
javascript代码
function selectionSort (arr) {
let min, temp
for (let i = 0; i < arr.length - 1; i++) {
min = i // 最小数索引
for (let j = i; j < arr.length; j++) {
if (arr[j] < arr[min]) {
min = j
}
}
temp = arr[i]
arr[i] = arr[min]
arr[min] = temp
}
return arr
}
堆排序
在讲堆排序之前,我们先了解一些二叉树的知识。
-
二叉树
简单地理解,满足以下两个条件的树就是二叉树:
-
本身是有序树;
-
树中包含的各个节点的度不能超过 2,即只能是 0、1 或者 2;
-
-
满二叉树
如果二叉树中除了叶子结点,每个结点的度都为 2,则此二叉树称为满二叉树。
-
完全二叉树
如果二叉树中除去最后一层节点为满二叉树,且最后一层的结点依次从左到右分布,则此二叉树被称为完全二叉树。
对于完全二叉树来说,如果记根节点的索引值为0,那么对于任意一个节点i,其左右节点如果存在的话,索引值分别为 2i + 1,2i + 2。之所以介绍二叉树,是因为堆排序就要用到我们上面所讲的完全二叉树。
算法步骤
-
建立大跟堆或小跟堆,我们以大根堆为例,所谓建立大跟堆,就是各个节点与其左右节点比较,将大的值置换到根部,这样一个个节点比较下去,直到将最大的值置换到根节点,大跟堆建立完毕。
-
将大根堆中的根节点与其尾节点进行交换
-
将二叉树的长度减一,即尾结点不参与下一轮排序。重复操作1,直到直到堆的尺寸为 1。
示例
我们取 91, 60, 96, 13, 35, 65, 46, 65, 10, 30, 20, 31, 77, 81, 22 进行示范。
数列对应的完全二叉树如下图

第一轮排序
-
46 与 81、22 比较,81最大,81 与 46 互换位置,得
-
65 与 31、77 比较,77最大,77 与 65 互换位置,得
-
35 与 30、20 比较,35最大,位置不变。
-
13 与 65、10 比较,65最大,65 与 13 互换,得
-
96 与 77、81 比较,96最大,位置不变
-
60 与 65、35比较,65最大,65 与 60 互换,得
-
91 与 65、96比较,96最大,96 与 91互换,得到最大值96
-
将根节点96与尾结点22互换,即最大值置于尾结点。数列长度减一,即尾节点不再参与堆构建,如图
-
第一轮排序结束,重复以上步骤,直到堆的尺寸为 1,排序结束。
动态图
javascript代码
let last // 参与堆构建的最后一个节点索引值
// 建立大根堆
function buildMaxHeap(arr) {
for (let i = Math.floor((last + 1) / 2); i >= 0; i--) {
heapify(arr, i)
}
}
// 堆调整函数,此处为构建大根堆
function heapify (arr, i) {
// 在完全二叉树中,索引值从0开始,若节点i存在左右子节点,则左右子节点索引分别为 2i + 1, 2i + 2
let left = 2 * i + 1,
right = 2 * i + 2,
largest = i
if (left <= last && arr[left] > arr[largest]) {
largest = left
}
if (right <= last && arr[right] > arr[largest]) {
largest = right
}
if (largest != i) {
swap(arr, i, largest)
}
}
function swap(arr, i, j) {
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
// 堆排序
function heapSort(arr) {
for (let i = 0; i < arr.length - 1; i++) {
last = arr.length - 1 - i
buildMaxHeap(arr)
swap(arr, 0, last)
}
return arr
}
两种算法的复杂度及稳定性
排序算法 | 时间复杂度(平均) | 时间复杂度(最坏) | 时间复杂度(最好) | 空间复杂度 | 稳定性 |
---|---|---|---|---|---|
简单选择排序 | O(n2) | O(n2) | O(n2) | O(1) | 不稳定 |
堆排序 | O(nlog2n) | O(nlog2n) | O(nlog2n) | O(1) | 不稳定 |