
常见的排序算法可以根据其实现原理分为以下几类,每种算法都有其特定的应用场景和性能特点:
1. 比较排序(基于元素比较)
-
冒泡排序(Bubble Sort)
- 原理:通过相邻元素交换,逐步将最大值“冒泡”到数组末尾。
- 时间复杂度:平均和最坏情况 (O(n^2)),最好情况 (O(n))(已排序时)。
- 特点:简单但效率低,稳定排序。
-
选择排序(Selection Sort)
- 原理:每次选择最小元素放到已排序区间的末尾。
- 时间复杂度:始终 (O(n^2))。
- 特点:不稳定,适合小规模数据。
-
插入排序(Insertion Sort)
- 原理:逐个将元素插入已排序区间的正确位置。
- 时间复杂度:平均和最坏 (O(n^2)),最好 (O(n))(已排序时)。
- 特点:稳定,适合小规模或部分有序数据。
-
快速排序(Quick Sort)
- 原理:分治法,选择一个基准元素,将数组分为两部分递归排序。
- 时间复杂度:平均 (O(n \log n)),最坏 (O(n^2))(如已排序且基准选择不当)。
- 特点:高效且原地排序,不稳定,实际应用广泛。
-
归并排序(Merge Sort)
- 原理:分治法,将数组分为两半分别排序后合并。
- 时间复杂度:始终 (O(n \log n))。
- 特点:稳定,但需要额外空间,适合链表或外部排序。
-
堆排序(Heap Sort)
- 原理:利用堆结构(完全二叉树)实现选择排序。
- 时间复杂度:始终 (O(n \log n))。
- 特点:原地排序,不稳定,适合大数据量。
-
希尔排序(Shell Sort)
- 原理:改进的插入排序,通过分组逐步缩小间隔排序。
- 时间复杂度:(O(n \log n)) 到 (O(n^2)),取决于增量序列。
- 特点:不稳定,适合中等规模数据。
2. 非比较排序(基于元素分布特性)
-
计数排序(Counting Sort)
- 原理:统计元素出现次数,适用于整数且范围较小的情况。
- 时间复杂度:(O(n + k))((k) 为数据范围)。
- 特点:稳定,需额外空间。
-
桶排序(Bucket Sort)
- 原理:将元素分到多个桶中,分别排序后合并。
- 时间复杂度:平均 (O(n + k)),最坏 (O(n^2))。
- 特点:适合均匀分布的数据。
-
基数排序(Radix Sort)
- 原理:按位数从低位到高位依次排序(通常基于计数排序)。
- 时间复杂度:(O(n \times k))((k) 为最大位数)。
- 特点:稳定,适合整数或字符串排序。
3. 代码(10种排序)
#include "include/header.h"
using namespace std;
// random_shuffle
void random_shuffle(vector<int> &vec) {
srand(time(NULL));
for (int i = 0; i < vec.size(); i++) {
int j = rand() % vec.size();
swap(vec[i], vec[j]);
}
}
void print(const vector<int> &vec) {
for (int i = 0; i < vec.size(); i++) {
cout << vec[i] << " ";
}
cout << endl;
}
// 冒泡排序
void bubble_sort(vector<int> &vec) {
Timer t("bubble_sort");
int len = vec.size();
for (int i = 0; i < len; i++) {
for (int j = 0; j < len - i - 1; j++) {
if (vec[j] > vec[j + 1]) {
swap(vec[j], vec[j + 1]);
}
}
}
}
// 选择排序
void select_sort(vector<int> &vec) {
Timer t("select_sort");
int len = vec.size();
for (int i = 0; i < len; i++) {
int min_index = i;
for (int j = i + 1; j < len; j++) {
if (vec[j] < vec[min_index]) {
min_index = j;
}
}
swap(vec[i], vec[min_index]);
}
}
// 插入排序
void insert_sort(vector<int> &vec) {
Timer t("insert_sort");
int len = vec.size();
for (int i = 1; i < len; i++) {
int j = i;
int temp = vec[i];
while (j > 0 && temp < vec[j - 1]) {
vec[j] = vec[j - 1];
j--;
}
vec[j] = temp;
}
}
// 希尔排序
void shell_sort(vector<int> &vec) {
Timer t("shell_sort");
int len = vec.size();
for (int gap = len / 2; gap > 0; gap /= 2) {
for (int i = gap; i < len; i++) {
int j = i;
int temp = vec[i];
while (j >= gap && temp < vec[j - gap]) {
vec[j] = vec[j - gap];
j -= gap;
}
vec[j] = temp;
}
}
}
// 归并排序
void merge_sort(vector<int> &vec) {
Timer t("merge_sort");
int len = vec.size();
vector<int> temp(len);
function<void(int, int)> merge_sort_range = [&](int left, int right) {
if (left >= right)
return;
int mid = left + (right - left) / 2;
merge_sort_range(left, mid);
merge_sort_range(mid + 1, right);
int i = left, j = mid + 1, k = 0;
while (i <= mid && j <= right) {
if (vec[i] <= vec[j]) {
temp[k++] = vec[i++];
} else {
temp[k++] = vec[j++];
}
}
while (i <= mid) {
temp[k++] = vec[i++];
}
while (j <= right) {
temp[k++] = vec[j++];
}
for (int i = 0; i < k; i++) {
vec[left + i] = temp[i];
}
};
merge_sort_range(0, len - 1);
}
// 快速排序
void quick_sort(vector<int> &vec) {
Timer t("quick_sort");
int len = vec.size();
function<void(int, int)> quick_sort_range = [&](int left, int right) {
if (left >= right)
return;
int i = left, j = right, pivot = vec[left + (right - left) / 2];
while (i <= j) {
while (vec[i] < pivot)
i++;
while (vec[j] > pivot)
j--;
if (i < j) {
swap(vec[i++], vec[j--]);
} else if (i == j) {
i++;
}
}
quick_sort_range(left, j);
quick_sort_range(i, right);
};
quick_sort_range(0, len - 1);
}
// 堆排序
void heap_sort(vector<int> &vec) {
Timer t("heap_sort");
int len = vec.size();
function<void(int, int)> heapify = [&](int start, int end) {
int dad = start;
int son = dad * 2 + 1;
while (son <= end) {
if (son + 1 <= end && vec[son] < vec[son + 1]) {
son++;
}
if (vec[dad] > vec[son]) {
return;
} else {
swap(vec[dad], vec[son]);
dad = son;
son = dad * 2 + 1;
}
}
};
for (int i = len / 2 - 1; i >= 0; i--) {
heapify(i, len - 1);
}
for (int i = len - 1; i > 0; i--) {
swap(vec[0], vec[i]);
heapify(0, i - 1);
}
}
// 计数排序
void count_sort(vector<int> &vec) {
Timer t("count_sort");
int len = vec.size();
int max_val = *max_element(vec.begin(), vec.end());
int min_val = *min_element(vec.begin(), vec.end());
vector<int> count(max_val - min_val + 1, 0);
for (int i = 0; i < len; i++) {
count[vec[i] - min_val]++;
}
int index = 0;
for (int i = 0; i < count.size(); i++) {
while (count[i]-- > 0) {
vec[index++] = i + min_val;
}
}
}
// 桶排序
void bucket_sort(vector<int> &vec) {
Timer t("bucket_sort");
int len = vec.size();
int max_val = *max_element(vec.begin(), vec.end());
int min_val = *min_element(vec.begin(), vec.end());
int bucket_size = 5;
int bucket_num = (max_val - min_val) / bucket_size + 1;
vector<vector<int>> buckets(bucket_num);
for (int i = 0; i < len; i++) {
int index = (vec[i] - min_val) / bucket_size;
buckets[index].push_back(vec[i]);
}
for (int i = 0; i < bucket_num; i++) {
sort(buckets[i].begin(), buckets[i].end());
}
int index = 0;
for (int i = 0; i < bucket_num; i++) {
for (int j = 0; j < buckets[i].size(); j++) {
vec[index++] = buckets[i][j];
}
}
}
// 获取某个数字在特定位数上的值
int getDigit(int number, int digit) {
return (abs(number) / static_cast<int>(pow(10, digit))) % 10;
}
// 基数排序函数
void radix_sort(vector<int> &arr) {
Timer t("radix_sort");
if (arr.empty())
return;
// 找到最大绝对值
int maxAbsValue = *max_element(arr.begin(), arr.end(), [](int a, int b) {
return abs(a) < abs(b);
});
// 计算最大位数
int maxDigits = 0;
while (maxAbsValue > 0) {
maxAbsValue /= 10;
maxDigits++;
}
// 进行基数排序
for (int digit = 0; digit < maxDigits; digit++) {
vector<vector<int>> buckets(20); // 20个桶,-9到9的数字
// 将数字放入相应的桶中
for (int number : arr) {
int d = getDigit(number, digit);
if (number < 0) {
buckets[9 + d].push_back(number); // 负数放在前面
} else {
buckets[d].push_back(number); // 正数放在后面
}
}
// 清空原数组并按桶的顺序重新填充
arr.clear();
for (const auto &bucket : buckets) {
for (int number : bucket) {
arr.push_back(number);
}
}
}
}
int main(int argc, char const *argv[]) {
vector<int> vec = ReadBigArrayFromFile(10000);
// bubble_sort(vec);
random_shuffle(vec);
bubble_sort(vec);
// select_sort(vec);
random_shuffle(vec);
select_sort(vec);
// insert_sort(vec);
random_shuffle(vec);
insert_sort(vec);
// shell_sort(vec);
random_shuffle(vec);
shell_sort(vec);
// radix_sort(vec);
random_shuffle(vec);
radix_sort(vec);
// merge_sort(vec);
random_shuffle(vec);
merge_sort(vec);
// quick_sort(vec);
random_shuffle(vec);
quick_sort(vec);
// heap_sort(vec);
random_shuffle(vec);
heap_sort(vec);
// count_sort(vec);
random_shuffle(vec);
count_sort(vec);
// bucket_sort(vec);
random_shuffle(vec);
bucket_sort(vec);
return 0;
}
运行结果:
Read vector size: 10000
函数 bubble_sort 执行时间: 674464 微秒
函数 select_sort 执行时间: 222103 微秒
函数 insert_sort 执行时间: 151351 微秒
函数 shell_sort 执行时间: 2780 微秒
函数 radix_sort 执行时间: 125 微秒
函数 merge_sort 执行时间: 3115 微秒
函数 quick_sort 执行时间: 2148 微秒
函数 heap_sort 执行时间: 4681 微秒
函数 count_sort 执行时间: 2563 微秒
函数 bucket_sort 执行时间: 7571 微秒
4. 其他或混合排序
- TimSort(Python、Java 默认排序算法):结合归并排序和插入排序,优化了实际数据的有序性。
- 内省排序(Introsort):结合快速排序、堆排序和插入排序,避免快速排序的最坏情况。
5. 选择排序算法的考虑因素
- 数据规模:小数据用简单排序(如插入排序),大数据用 (O(n \log n)) 算法(如快排、归并)。
- 内存限制:原地排序算法(如快排、堆排序)适合内存紧张场景。
- 稳定性需求:如归并排序、计数排序适合需要保持相等元素顺序的场景。
- 数据特性:非比较排序在特定数据分布下效率更高(如整数、范围有限)。
2358

被折叠的 条评论
为什么被折叠?



