基数排序(RedixSort)

来源:互联网 发布:js indexof函数 编辑:程序博客网 时间:2024/06/02 01:46

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

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

#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