一. 目的与说明
进行基数排序练习。基数排序是对整数的每一位进行稳定排序。多次排序后,数据呈现有序状态。注意必须是稳定排序。可以推广到浮点数。
二. 代码实现
定义进制常量
#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