基数排序

来源:互联网 发布:淘宝显示全球购的标志 编辑:程序博客网 时间:2024/06/03 13:04

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)

原创粉丝点击