基数排序

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)

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值