counting_sort
//此算法是稳定的,但是,不是原址排序,k很大时,也是不适合的
void counting_sort(int *arr, int *B, int length, int k){//-----O(length+k)
int C[k + 1];
for (int i = 0; i < k + 1; i++)//O(k)
C[i] = 0;
for (int i = 0; i < length; i++)//O(length)
C[arr[i]]++;
for (int i = 1; i < k + 1; i++)
C[i] = C[i] + C[i - 1];
/*对于每一个arr[i]中的元素来说
C[arr[i]]中存储了 <= arr[i]的元素的个数
*/
for (int i = length; i > 0; i--){//从后往前
B[C[arr[i]]] = arr[i];//arr[i]的位置应该是C[arr[i]]
C[arr[i]]--;//减一,下一个与arr[i]相同的元素会放在前一个位置
//因为是从后往前,因此它是稳定的原本元素的顺序不变
}
}
插入排序和归并排序也是稳定的
堆排和快排是不稳定的
基数排序
从最低有效位开始,根据改位大小排序,对全部位数进行排完序,就完成了 基数排序。
void radix_sort(int *arr, int d, int length){
for(int i = 0; i < d; i++)
//use a stable sort to sort array A on digit i;
}
可任意选择一个稳定的排序算法
当对于counting_sort来说参数k不大时,可选择counting_sort
基数排序复杂度:O(d(n+k))
void get_sort_data(int *arr, int *sort_data, int length, int radix){
if(radix == 1)
for (int i = 0; i < length; i++)//-----------O(length)
sort_data[i] = (arr[i] % 100) % 10;
else if(radix == 2)
for (int i = 0; i < length; i++)
sort_data[i] = (arr[i] % 100) / 10;
else if(radix == 3)
for (int i = 0; i < length; i++)
sort_data[i] = arr[i] / 100;
}
void counting_sort_radix(int *in, int *B, int length, int k, int radix){//-----O(k+length)
int arr[length];
for (int i = 0; i < length; i++)//------------O(length)
arr[i] = in[i];
get_sort_data(in, arr, length, radix);//--------O(length)
int C[k + 1];
for (int i = 0; i < k + 1; i++)//-------------O(k)
C[i] = 0;
for (int i = 0; i < length; i++)//--------O(length)
C[arr[i]]++;
for (int i = 1; i < k + 1; i++)//-------------O(k)
C[i] = C[i] + C[i - 1];
/*对于每一个arr[i]中的元素来说
C[arr[i]]中存储了 <= arr[i]的元素的个数
*/
for (int i = length-1; i >= 0; i--){//从后往前------------------O(length)
B[C[arr[i]]] = in[i];//arr[i]的位置应该是C[arr[i]]
C[arr[i]]--;//减一,下一个与arr[i]相同的元素会放在前一个位置
//因为是从后往前,因此它是稳定的原本元素的顺序不变
}
}
void radix_sort(int *arr, int d, int length){//-------------O(d*(k+length))
int temp[length];
for (int i = 0; i < length; i++)//--------O(length)
temp[i] = arr[i];
int ret[length+1];
for (int i = 0; i < d; i++){//----------O(d) * O(k+length) = O(d*(k+length))
counting_sort_radix(temp, ret, length, 9, i+1);//---------O(k+length)
for (int i = 1; i <= length;i++)//----O(length)
temp[i-1] = ret[i];
}
for (int i = 0; i < length; i++)//-----O(length)
arr[i] = temp[i];
}
void main_counting_sort(){
// int arr[30] = {2, 3, 20, 5, 6, 6, 19, 10, 20, 5, 3, 20};
int arr[30] = {21, 12, 42, 123, 124, 42, 12, 32, 16, 86, 456, 33, 237, 886, 764};
algorithms::radix_sort(arr, 3, 15);
for (size_t i = 0; i < 15; i++)
cout << arr[i] << " ";
cout << endl;
}
算法导论习题8.3-3
证明基数排序是正确的,并且指出在什么地方基数排序需要内层的排序是稳定的?
证明:数学归纳法
d = 1时,只有一个数字,利用内层排序,排完之后就是结果
假设在d-1时已经排完序,
现证在d时排完序之后结果是正确的:
在d-1排完之后,数组中的顺序依据第d-1位,
考虑xd和yd,分别属于第d位的两个数字,
若 xd > yd,则xd位于yd之后
若xd < yd, 则xd位于yd之前
若xd = yd,则根据内层算法确定,相同的元素的位置,这里的counting_sort是稳定的,
所以其相对位置保持不变,其大小顺序就是d-1位上的顺序
且从d=1时是正确的,所以对整个排序是正确的
当某一位上的两个值相同时需要内层算法是稳定的
算法导论8.3-4
说明在O(n)时间内,对n^3-1区间内的n个整数进行排序。
答案:d = 3, 每一位范围从0 - n-1;
复杂度:调用三次counting_sort(arr, B, n, n),每一次复杂度为O(n+n)
因此复杂度为O(n)