一. 计数排序
- 计数排序
应用前提: 假设n个输入元素中的每一个都是在0到k区间内的一个整数, 其中k为某个整数.
简单介绍: 对每一个输入元素x, 确定小于x的元素个数. 利用这一信息, 就可以直接把x放到它在输出数组中的位置上了. 例如, 如果有3个元素小于x, 就可以直接把x放在第4个输出位置.
运行时间: 当 k = O ( n ) k=O(n) k=O(n)时, 排序的运行时间为 Θ ( n ) \Theta(n) Θ(n). - 计数排序伪代码(截图自算法导论第三版)
- C++实现
#include <iostream>
#include <stack>
using namespace std;
/**
计数排序 2020.04.23
Author: 豆奶
Reference: 算法导论第三版
**/
/**
定义counting_sort函数用递归方法实现计数排序
Input:
A[]:int[],是需要排序的数组. 指针传递,函数内部对A的修改能导致外部A的变化
B[]:int[],是存储排序后的数组. 指针传递,函数内部对B的修改能导致外部B的变化
k: int,是待排序数组的最大值.
n: int,是待排序数组的长度.
Output:
B: int*, 排序后的数组.
**/
void counting_sort(int A[], int B[], int k, int n){
int *C = new int[k+1]; // 因为数组下标是从0开始的, 所以要到k的话, 需要k+1
for(int i=0; i<k+1; i++)
C[i] = 0;
for(int j=0; j<n; j++)
C[ A[j] ] = C[ A[j] ] + 1;
for(i=1; i<k+1; i++)
C[i] = C[i] + C[i-1];
for(j=n-1; j>=0; j--){
B[ C[A[j]]-1 ] = A[j]; // 这里-1是因为数组B的序号是从0开始的, 而伪代码的序号是从0开始的, 详情可看下文的 5.小细节
C[ A[j] ] = C[ A[j] ] - 1;
}
delete[] C;
}
- 测试
int main(){
int A[15]={3, 19, 13, 5, 6, 15, 8, 3, 18, 16, 12, 23, 8, 21, 2};
int length = sizeof(A)/sizeof(A[0]);
//sizeof()函数可以返回数组所占的内存,而sizeof(a[0])返回的是数组第一个元素所占的内存。
int i;
cout<<"A[i]的值为: ";
for(i=0; i<length; i++){
cout<<A[i]<<", ";
}
cout<<endl<<endl;
int k = 23;
int B[15];
counting_sort(A, B, k, length);
cout<<"排序后A[i]的值为: ";
for(i=0; i<length; i++){
cout<<B[i]<<", ";
}
cout<<endl<<endl;
return 0;
}
- 小细节: 一开始写代码进行测试的时候, 发现结果一直不对, 数组B[0]的值一直没有, 仔细看代码才发现, 原来是因为在C++中数组的起始下标是0导致的. 举个例子, 比如C[2] = 1是最小的(即数组最小值为2), 那么此时若按照伪代码写, 则是B[1] = 2, 而实际上, 应该是B[0]=2. 因此需要在编写的时候 -1
二. 基数排序
- 基数排序
简单介绍: 基数排序是先按最低有效位进行排序来解决卡片排序问题的. - 基数排序伪代码
三. 桶排序
- 桶排序
应用前提: 假设输入数据服从均匀分布. 即假设输入是由一个随机过程产生, 该过程将元素均匀, 独立地分布在[0, 1)区间上.
简单介绍: 桶排序将[0, 1)区间划分为n个相同大小的子区间, 或称为桶. 然后, 将n个输入数分别放到各个桶中. 为了得到输出结果, 先对每个桶中的数进行排序, 然后遍历每个桶, 按照次序把各个桶中的元素列出来即可.
时间复杂度: 平均情况下它的时间代价为 O ( n ) O(n) O(n). - 桶排序伪代码
在代码中, 假设输入是一个包含n个元素的数组A, 且每个元素 A [ i ] A[i] A[i]满足 0 ≤ A [ i ] < 1 0 \leq A[i] < 1 0≤A[i]<1.
- C++实现
- 测试
四. 参考文献
- 算法导论第三版