基数排序(RedixSort)

一. 目的与说明
进行基数排序练习。基数排序是对整数的每一位进行稳定排序。多次排序后,数据呈现有序状态。注意必须是稳定排序。可以推广到浮点数。

二. 代码实现
定义进制常量

#define NUMBER_SYSTEM 10

定义获取数字位数与制定位的数字

        //获取整数位数
        int GetDigitWidth(int nNum){
            int nWidth(0);
            do{
                nNum = nNum /10;
                nWidth++;
            } while (nNum);
            return nWidth;
        }
        //获取数字的某位上的数字,该算法不高效,仅演示用
        int GetBitDigit(int nNum,int nBit){
            int nBase(1),nBitDigit;
            for (int i = 1; i < nBit; i++){
                nBase = nBase * 10;
            }
            nBitDigit = (nNum / nBase) % 10;
            return nBitDigit;
        }

MSD实现,从高位排序到低位

        //Most Sigificant Digit  first RadixSort,最高位有效数字优先的基数排序
        //数位排序采用计数排序
        void MSDRadixSort(T testArray[], int nSize){
            LogInfo<T> log = LogInfo<T>();
            log.ShowState("原始数组为:");
            log.ShowArray(testArray, nSize);
            //一次遍历获取最大值
            T TMax = testArray[0];
            for (int i = 0; i < nSize; i++){
                if (testArray[i]>TMax){
                    TMax = testArray[i];
                }
            }
            //获取最大位数
            int nWidth = GetDigitWidth(TMax);
            MSDRadixSortSub(testArray, 0, nSize - 1, nWidth);
            log.ShowState("最终数组为:");
            log.ShowArray(testArray, nSize);
        }   
        //Most Sigificant Digit  first RadixSort,最高位有效数字优先的基数排序
        //数位排序采用计数排序
        void MSDRadixSortSub(T testArray[], int nBegin,int nEnd,int nBit){
            //初始化计数器
            T Count[NUMBER_SYSTEM];
            int i(0),j(0);
            for (i = 0; i < NUMBER_SYSTEM; i++)
                Count[i] = T(0);
            //分配桶
            T* testOut = new T[nEnd - nBegin + 1];
            //计数器
            for (i = nBegin; i <= nEnd; i++)
                Count[GetBitDigit(testArray[i], nBit)]++;
            //位置计算
            for (i = 1; i < NUMBER_SYSTEM; i++)
                Count[i] = Count[i]+Count[i-1];
            //根据位置大小产生排序
            for (i = nEnd; i >= nBegin; i--){
                j = GetBitDigit(testArray[i],nBit);
                testOut[Count[j] - 1] = testArray[i];
                Count[j]--;
            }
            //将排序后的元素放回原桶
            for (i = nBegin; i <= nEnd; i++)
                testArray[i]=testOut[i-nBegin];
            delete[] testOut;
            int nPosBegin, nPosEnd;
            if (nBit > 1){
                for (i = 0; i < NUMBER_SYSTEM; i++){
                    nPosBegin = Count[i];
                    nPosEnd = Count[i + 1] - 1;
                    //第i个位置有数据
                    if (nPosBegin < nPosEnd){
                        MSDRadixSortSub(testArray, nPosBegin, nPosEnd, nBit - 1);
                    }
                }
            }
        }

LSD实现,从最低位排序到最高位

        //Last Sigificant Digit  first RadixSort,最低位有效数字优先的基数排序
        //数位排序采用计数排序
        void LSDRadixSort(T testArray[], int nSize){
            LogInfo<T> log = LogInfo<T>();
            log.ShowState("原始数组为:");
            log.ShowArray(testArray, nSize);
            //一次遍历获取最大值
            T TMax = testArray[0];
            for (int i = 0; i < nSize; i++){
                if (testArray[i]>TMax){
                    TMax = testArray[i];
                }
            }
            //获取最大位数
            int nWidth = GetDigitWidth(TMax);
            //从最低有效位开始进行计数排序
            for (int i = 1; i <= nWidth;i++)
                LSDRadixSortSub(testArray, nSize, i);
            log.ShowState("最终数组为:");
            log.ShowArray(testArray, nSize);
        }

        //Last Sigificant Digit  first RadixSort,最低位有效数字优先的基数排序
        //数位排序采用计数排序
        void LSDRadixSortSub(T testArray[], int nSize, int nBit){
            //初始化计数器
            T Count[NUMBER_SYSTEM];
            int i(0), j(0);
            for (i = 0; i < NUMBER_SYSTEM; i++)
                Count[i] = T(0);
            //分配桶
            T* testOut = new T[nSize];
            //计数器
            for (i = 0; i <nSize; i++)
                Count[GetBitDigit(testArray[i], nBit)]++;
            //位置计算
            for (i = 1; i < NUMBER_SYSTEM; i++)
                Count[i] = Count[i] + Count[i - 1];
            //根据位置大小产生排序
            for (i = nSize-1; i >= 0; i--){
                j = GetBitDigit(testArray[i], nBit);
                testOut[Count[j] - 1] = testArray[i];
                Count[j]--;
            }
            //将排序后的元素放回原桶
            for (i = 0; i <nSize; i++)
                testArray[i] = testOut[i];
            delete[] testOut;
        }

测试代码

int main()
{
    using namespace Test;
    using namespace MyAlgorithm;
    using namespace std;

    LogInfo<int> log = LogInfo<int>();
    Sort<int> sortTest = Sort<int>();
    log.ShowState("测试LSD基数排序");
    log.ShowLine();
    log.ShowState("测试正序数组========================");
    log.ShowLine();
    TestDataCreator<int, N_MAX> testArray = TestDataCreator<int, N_MAX>(PositiveArray);
    sortTest.LSDRadixSort(testArray.GetArray(), testArray.GetSize());
    log.ShowState("测试降序数组========================");
    log.ShowLine();
    testArray = TestDataCreator<int, N_MAX>(NegativeArray);
    sortTest.LSDRadixSort(testArray.GetArray(), testArray.GetSize());
    log.ShowState("测试随机数组========================");
    log.ShowLine();
    testArray = TestDataCreator<int, N_MAX>(RandomArray);
    sortTest.LSDRadixSort(testArray.GetArray(), testArray.GetSize());
    int nWait;
    cin >> nWait;
    return 0;
}

结果输出
这里写图片描述

三. 遇到问题
1、MSD实现缓存数组没有减去下标nBegin,导致下标越界。产生古怪数据。
2、对LSD算法存在疑问

四. 经验总结
1、LSD实现,必须要求稳定排序,才能排序成功。
2、MSD实现的稳定性依赖于每位数字排序算法的稳定性。
3、时刻注意下标问题。
4、本例数位排序采用了计数排序。该算法稳定依赖于倒序定位。
5、基数排序依靠计数内排序的复杂度分析:算法稳定。空间复杂度O(N+K),时间复杂度O(d(N+K)).
五. 后续任务
进行桶排序练习。

六. 参考文献
1、算法导论
2、 八大排序算法 http://blog.csdn.net/abcbig/article/details/42774333
3、基数排序http://www.cnblogs.com/Braveliu/archive/2013/01/21/2870201.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值