算法 - 排序 - 选择排序 (Selection Sort)
返回上级:算法 - 查找与排序 (Searching and Sorting)
本文将用C++实现堆排序算法。
常见的选择排序:
-
简单选择排序 (Simple Selection Sort)
-
堆排序 (Heap Sort)
-
树形选择排序 (Tree Selection Sort) ,也称锦标赛排序;(不在这里讨论)
在查看本文之前,需要一些程序语言的基础,还需要熟悉"完全二叉树"。
所有排序方法中,统一使用如下库与结构:
// Author: https://blog.youkuaiyun.com/DarkRabbit
// Sorted Dependency
#pragma once
#include <algorithm>
#include <vector>
#include <stack>
template<typename T>
struct MyItem
{
int key;
T data;
MyItem(){ key = -1; }
MyItem(const int& k) : key(k){ }
MyItem(const int& k, const T& d) : key(k), data(d){ }
};
数据表统一使用了std::vector<MyItem<T>>
,如果你使用静态数组MyItem<T>[]
或指针数组MyItem<T>*
,那么还要传入元素数量size
。
示例所用数据:
-
元素数量为
size = 15
; -
关键字为
key = { 123, 122, 565, 22, 3, 64, 73, 44, 287, 6, 9, 83, 25, 42, 13 }
。
文章目录
1 简单选择排序简述 (Simple Selection Sort)
- 在 n-i 个关键字中选择出最小的;
- 它不是这组数据第一个数据,则与第一个数据交换;
- 在数据中排除掉它,再选择第一个关键字;
- 重复这个过程。
简单排序是真的简单,不再多说。
详细过程:
key = { 123, 122, 565, 22, 3, 64, 73, 44, 287, 6, 9, 83, 25, 42, 13 }
简单选择排序:
0: 3 122 565 22 123 64 73 44 287 6 9 83 25 42 13
1: 3 6 565 22 123 64 73 44 287 122 9 83 25 42 13
2: 3 6 9 22 123 64 73 44 287 122 565 83 25 42 13
3: 3 6 9 13 123 64 73 44 287 122 565 83 25 42 22
4: 3 6 9 13 22 64 73 44 287 122 565 83 25 42 123
5: 3 6 9 13 22 25 73 44 287 122 565 83 64 42 123
6: 3 6 9 13 22 25 42 44 287 122 565 83 64 73 123
7: 3 6 9 13 22 25 42 44 287 122 565 83 64 73 123
8: 3 6 9 13 22 25 42 44 64 122 565 83 287 73 123
9: 3 6 9 13 22 25 42 44 64 73 565 83 287 122 123
10: 3 6 9 13 22 25 42 44 64 73 83 565 287 122 123
11: 3 6 9 13 22 25 42 44 64 73 83 122 287 565 123
12: 3 6 9 13 22 25 42 44 64 73 83 122 123 565 287
13: 3 6 9 13 22 25 42 44 64 73 83 122 123 287 565
2 堆排序简述 (Heap Sort)
堆排序,也称二叉堆排序,它是利用堆的运算来进行排序。
通常有两种形式:
-
小根堆
-
大根堆
由于小根堆记录关键字是从大到小,所以我们使用大根堆。
假设数据表为顺序存储,如下图,其排序过程:
-
从右向左依次对非叶结点的结点进行大根堆。即73不动、64与83交换、3:与9交换、……,直到123结束,得到大根堆;
-
然后对数据表从后往前依次执行如下过程
- 交换 0 与 i 的位置(确定最大值下标);
- 对 0 到 i-1 的元素再次大根堆(排除最大值下标)。
详细过程:
key = { 123, 122, 565, 22, 3, 64, 73, 44, 287, 6, 9, 83, 25, 42, 13 }
大根堆:
1: 123 122 565 22 3 64 73 44 287 6 9 83 25 42 13
2: 123 122 565 22 3 83 73 44 287 6 9 64 25 42 13
3: 123 122 565 22 9 83 73 44 287 6 3 64 25 42 13
4: 123 122 565 287 9 83 73 44 22 6 3 64 25 42 13
5: 123 122 565 287 9 83 73 44 22 6 3 64 25 42 13
6: 123 287 565 122 9 83 73 44 22 6 3 64 25 42 13
7: 565 287 123 122 9 83 73 44 22 6 3 64 25 42 13
交换 0 和 i , 后对 0 到 i-1 大根堆:
8: 287 122 123 44 9 83 73 13 22 6 3 64 25 42 565
9: 123 122 83 44 9 64 73 13 22 6 3 42 25 287 565
10: 122 44 83 25 9 64 73 13 22 6 3 42 123 287 565
11: 83 44 73 25 9 64 42 13 22 6 3 122 123 287 565
12: 73 44 64 25 9 3 42 13 22 6 83 122 123 287 565
13: 64 44 42 25 9 3 6 13 22 73 83 122 123 287 565
14: 44 25 42 22 9 3 6 13 64 73 83 122 123 287 565
15: 42 25 13 22 9 3 6 44 64 73 83 122 123 287 565
16: 25 22 13 6 9 3 42 44 64 73 83 122 123 287 565
17: 22 9 13 6 3 25 42 44 64 73 83 122 123 287 565
18: 13 9 3 6 22 25 42 44 64 73 83 122 123 287 565
19: 9 6 3 13 22 25 42 44 64 73 83 122 123 287 565
20: 6 3 9 13 22 25 42 44 64 73 83 122 123 287 565
21: 3 6 9 13 22 25 42 44 64 73 83 122 123 287 565
3 性能分析 (Performance Analysis)
排序方法 | 最好时间 | 最差时间 | 平均时间 | 辅助空间 | 稳定性 |
---|---|---|---|---|---|
简单选择排序 | O(n2) | O(n2) | O(n2) | O(1) | 不稳定 |
堆排序 | O(n log2n) | O(n log2n) | O(n log2n) | O(1) | 不稳定 |
4 简单选择排序C++代码 (Simple Selection Sort C++ Code)
// Author: https://blog.youkuaiyun.com/DarkRabbit
// Selection Sort
template<typename T>
void SelectionSort(std::vector<MyItem<T>>& list)
{
for (int i = 0; i < list.size() - 1; i++)
{
int keyIndex = i;
for (int j = i + 1; j < list.size(); j++)
{
if (list[keyIndex].key > list[j].key)
{
keyIndex = j;
}
}
if (keyIndex != i)
{
std::swap(list[keyIndex], list[i]);
}
}
}
5 堆排序C++代码 (Heap Sort C++ Code)
// Author: https://blog.youkuaiyun.com/DarkRabbit
// Heap Sort
// 求大根堆
template<typename T>
void MaxHeap(std::vector<MyItem<T>>& list, int start, int end)
{
if (list.empty())
{
return;
}
int parent = start;
int left;
int right;
int selected;
while (left < size)
{
// 求左右孩子
left = 2 * parent + 1;
right = left + 1;
// 选择左右孩子key'大的
selected = left;
if (right < size && list[left].key < list[right].key)
{
selected = right;
}
if (list[parent].key > list[selected].key) // 如果父结点大返回
{
return;
}
else // 交换父结点
{
std::swap(list[parent], list[selected]);
parent = selected;
}
}
}
template<typename T>
void HeapSort(std::vector<MyItem<T>>& list)
{
if (list.empty())
{
return;
}
int size = list.size();
// 最后一个非叶结点开始,
for (int i = size / 2 -1; i >= 0; i--)
{
MaxHeap(list, i, size - 1);
}
for (int i = size - 1; i > 0; i--)
{
std::swap(list[0], list[i]); // 确定最大值下标
MaxHeap(list, 0, i - 1); // 排除最大值后大根堆
}
}