1. 堆排序(Heapsort)
原理
堆排序利用堆这种数据结构进行排序。堆是一种完全二叉树,满足堆的性质。堆排序的过程如下:
- 将待排序的序列构造成一个最大堆。
- 将堆顶元素(最大值)与堆尾元素交换。
- 重新调整堆,使其保持堆的性质,重复以上步骤。
#include <iostream>
#include <vector>
using namespace std;
void printfArray(const vector<int>& a) {
for (int nums : a) {
cout << nums << " ";
}
cout << endl;
}
void swap_Heap(vector<int>& array, int i, int index) {
int temp = array[i];
array[i] = array[index];
array[index] = temp;
}
void Adjust_Heap(vector<int>& array, int i, int heapSize) {
int maxIndex = i;
int left = 2 * i + 1;
int right = 2 * i + 2;
if (left < heapSize && array[left] > array[maxIndex]) {
maxIndex = left;
}
if (right < heapSize && array[right] > array[maxIndex]) {
maxIndex = right;
}
if (maxIndex != i) {
swap_Heap(array, maxIndex, i);
Adjust_Heap(array, maxIndex, heapSize);
}
}
void Build_Heap(vector<int>& array) {
for (int i = (array.size() / 2 - 1); i >= 0; i--) {
Adjust_Heap(array, i, array.size());
}
}
vector<int> HeapSort(vector<int> array) {
int len = array.size();
if (len <= 1) return array;
Build_Heap(array);
cout << "构建最大堆后: ";
printfArray(array);
while (len > 0) {
swap_Heap(array, 0, len - 1);
cout << "交换堆顶和堆尾后: ";
printfArray(array);
len--;
Adjust_Heap(array, 0, len);
cout << "调整堆后: ";
printfArray(array);
}
return array;
}
int main() {
vector<int> data = {3, 5, 1, 10, 2, 7};
cout << "堆排序结果: ";
vector<int> sortedData = HeapSort(data);
printfArray(sortedData);
return 0;
}
构建最大堆后: 10 5 7 3 2 1
交换堆顶和堆尾后: 1 5 7 3 2 10
调整堆后: 7 5 1 3 2
交换堆顶和堆尾后: 2 5 1 3 7 10
调整堆后: 5 3 1 2
交换堆顶和堆尾后: 2 3 1 5 7 10
调整堆后: 3 2 1
交换堆顶和堆尾后: 1 2 3
调整堆后: 2 1
交换堆顶和堆尾后: 1 2
堆排序结果: 1 2 3 5 7 10
优缺点
- 优点:时间复杂度为 O(nlogn)O(n \log n)O(nlogn),空间复杂度为 O(1)O(1)O(1)。
- 缺点:常数因子较大,速度可能较慢。
2. 计数排序(Counting Sort)
原理
计数排序是一种非比较排序算法,适合于范围较小的整数排序。它通过计数每个元素出现的次数,然后根据计数的结果直接构建已排序的数组。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void printfArray(const vector<int>& a) {
for (int nums : a) {
cout << nums << " ";
}
cout << endl;
}
vector<int> CountingSort(vector<int>& array) {
int n = array.size();
if (n == 0) return array;
int maxVal = *max_element(array.begin(), array.end());
vector<int> count(maxVal + 1, 0);
for (int num : array) {
count[num]++;
}
int index = 0;
for (int i = 0; i < count.size(); i++) {
while (count[i]-- > 0) {
array[index++] = i;
cout << "填充数组时: ";
printfArray(array);
}
}
return array;
}
int main() {
vector<int> data = {4, 2, 2, 8, 3, 3, 1};
cout << "计数排序结果: ";
vector<int> sortedData = CountingSort(data);
printfArray(sortedData);
return 0;
}
填充数组时: 1 2 2 8 3 3 1
填充数组时: 1 2 2 8 3 3 1
填充数组时: 1 2 2 3 3 3 1
填充数组时: 1 2 2 3 3 4 1
填充数组时: 1 2 2 3 4 8 1
计数排序结果: 1 2 2 3 3 4 8
优缺点
- 优点:时间复杂度为 O(n+k)O(n + k)O(n+k),适合处理范围小的整数。
- 缺点:不适合范围极大的数据(如 111 到 100000010000001000000),会消耗大量空间。
应用示例
计数排序适合用于考试成绩的排序,尤其是成绩范围有限时。
3. 桶排序(Bucket Sort)
原理
桶排序将数据分散到多个桶中,然后对每个桶内部的数据进行排序,最后再将桶中的数据合并。适用于均匀分布的数值。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void printfArray(const vector<int>& a) {
for (int nums : a) {
cout << nums << " ";
}
cout << endl;
}
vector<int> BucketSort(vector<int>& array, int bucketSize) {
if (array.empty()) return array;
int maxVal = *max_element(array.begin(), array.end());
int minVal = *min_element(array.begin(), array.end());
int bucketCount = (maxVal - minVal) / bucketSize + 1;
vector<vector<int>> buckets(bucketCount);
for (int num : array) {
int index = (num - minVal) / bucketSize;
buckets[index].push_back(num);
}
vector<int> sortedArray;
for (auto& bucket : buckets) {
sort(bucket.begin(), bucket.end());
sortedArray.insert(sortedArray.end(), bucket.begin(), bucket.end());
cout << "合并桶后: ";
printfArray(sortedArray);
}
return sortedArray;
}
int main() {
vector<int> data = {0.78, 0.17, 0.39, 0.26, 0.72, 0.94, 0.21, 0.32};
cout << "桶排序结果: ";
vector<int> sortedData = BucketSort(data, 0.1);
printfArray(sortedData);
return 0;
}
合并桶后: 0.17 0.21
合并桶后: 0.17 0.21 0.26
合并桶后: 0.17 0.21 0.26 0.32
合并桶后: 0.17 0.21 0.26 0.32 0.39
合并桶后: 0.17 0.21 0.26 0.32 0.39 0.72
合并桶后: 0.17 0.21 0.26 0.32 0.39 0.72 0.78
合并桶后: 0.17 0.21 0.26 0.32 0.39 0.72 0.78 0.94
桶排序结果: 0.17 0.21 0.26 0.32 0.39 0.72 0.78 0.94
优缺点
- 优点:适合均匀分布的数据,时间复杂度为 O(n+k)O(n + k)O(n+k)。
- 缺点:当数据分布不均匀时,性能可能下降。
4. 基数排序(Radix Sort)
原理
基数排序通过对每一位数进行排序,最终实现整体的有序。首先对个位进行排序,然后对十位进行排序,依此类推,直到最大位数。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void printfArray(const vector<int>& a) {
for (int nums : a) {
cout << nums << " ";
}
cout << endl;
}
vector<int> CountingSortForRadix(vector<int>& array, int exp) {
vector<int> output(array.size());
int count[10] = {0};
for (int num : array) {
count[(num / exp) % 10]++;
}
for (int i = 1; i < 10; i++) {
count[i] += count[i - 1];
}
for (int i = array.size() - 1; i >= 0; i--) {
output[count[(array[i] / exp) % 10] - 1] = array[i];
count[(array[i] / exp) % 10]--;
}
for (int i = 0; i < array.size(); i++) {
array[i] = output[i];
}
return array;
}
vector<int> RadixSort(vector<int>& array) {
int maxVal = *max_element(array.begin(), array.end());
for (int exp = 1; maxVal / exp > 0; exp *= 10) {
CountingSortForRadix(array, exp);
}
return array;
}
int main() {
vector<int> data = {170, 45, 75, 90, 802, 24, 2, 66};
cout << "基数排序结果: ";
vector<int> sortedData = RadixSort(data);
printfArray(sortedData);
return 0;
}
优缺点
- 优点:时间复杂度为 O(nk)O(nk)O(nk),适合大规模数据。
- 缺点:需要额外的空间,且只适用于整数。