基数排序算法

基数排序

基数排序是一种非比较形的排序算法,是一种稳定排序算法,其原理是将整数按位数(从个位、十位、百位顺序)切割成不同的数字,分别按照位数上的值将元素放到不同的“桶子”中,如果数字当前位数上没有值,则补0。
直到最高位切割完成,则数据排序完成。

1,23,90,324,567,876,26,78,83,45,67,57,33

如上需要排序的数组最大位数为 百位,则需要先从 个位、然后十位、最后百位,分三次排序

首先按照个位上的数值,
将 1,23,90,324,567,876,26,78,83,45,67,57,33
顺序将每个数放入对应的格子内

个位0123456789
个位901233244587656778
个位832667
个位3357

不需要排序,从左到右顺次将每一列的数值拿出来
90,1,23,83,33,324,45, 876,26,567,67,57, 78

然后按照十位上的数值,
将 90,1,23,83,33,324,45, 876,26,567,67,57, 78
顺序将每个数放入对应的格子内
如果某一位上没有说数值,则补0,比如 1 的十位是 0, 则将1 填到 十位为0 的列

十位0123456789
十位1233345575678768390
十位3246778
十位26

不需要排序,从左到右顺次将每一列的数值拿出来
1,23,324,26,33,45,57,567,67,876,78,83,90

然后按照百位上的数值,顺序将每个数放入对应的格子内
如果某一位上没有说数值,则补0,比如 1 的百位是 0, 则将1 填到 百位为0 的列

百位0123456789
百位1324567876
百位23
百位26
百位33
百位45
百位57
百位67
百位78
百位83
百位90

不需要排序,从左到右顺次将每一列的数值拿出来
1,23,26,33,45,57,67,78,83,90,324,567,876

到此数组已经排好序了,中间没有经过任何比较

代码如下

void Start()
    {
        int[] arr = new int[] { 543, 159, 343, 287, 694, 315, 873, 96};
        RadixSort(arr);
    }

    public void RadixSort(int[] arr)
    {
        int maxBit = 1;
        int value = 10;
        // 获取数组中最大元素位数
        for (int i = 0; i < arr.Length; ++i)
        {
            while(arr[i] >= value)
            {
                value *= 10;
                ++maxBit;
            }
        }

        int digit = 1;
        int[] tempArr = new int[arr.Length];
        while (maxBit > 0)
        {
            maxBit--;
            // 用来技术的数组,记录 digit(个、十、百)位上每一位个数
            // 比如总计五个数字:23、53、 63、73、 55、65
            // 当 digit 表示个位时:
            // 个位 是 3 的记作 countArr[3] = 4 包含 (23、53、 63、73 四个数字)
            // 个位 是 5 的记作 countArr[5] = 2 包含 (55、65 两个数字)
            
            // 当 digit 表示十位时:
            // 十位是 2 的记作  countArr[2] = 1 包含 (23 一个数字)
            // 十位是 5 的记作  countArr[5] = 2 包含 (53、55 两个数字)
            // 十位是 6 的记作  countArr[6] = 2 包含 (63、65 两个数字)
            // 十位是 7 的记作  countArr[7] = 1 包含 (73 一个数字)
            int[] countArr = new int[10];
            // 逻辑一
            for (int i = 0; i < arr.Length; ++i)
            {
                // arr[i] 的 digit位(1 个位、10 十位、100 百位)上的值
                // 以此值作为 countArr 的索引,索引数+1
                int index = arr[i] / digit % 10;
                countArr[index]++;
            }

            // 逻辑二
            for (int i = 1; i < countArr.Length; ++i)
            {
                // 计算每个索引上的数据存放的最大位置下标
                // 以上面  digit 表示十位时 为例
                // 十位是 2 的有 1 个, 在数组中存取位置是 第 0 下标
                // 十位是 5 的有 2 个,在数组中存取位置是 第 1 - 2 下标
                // 十位是 6 的有 2 个,在数组中存取位置是 第 3 - 4 下标
                // 十位是 7 的有 1 个,在数组中存取位置是 第 5 下标
                countArr[i] += countArr[i - 1];
            }

            for (int i = arr.Length - 1; i >= 0; --i)
            {
                int number = arr[i] / digit % 10;
                int index = countArr[number] - 1;
                tempArr[index ] = arr[i];
                countArr[number ]--;
            }

            // 将临时数据拷贝回 arr
            for (int i = 0; i < tempArr.Length; ++i)
            {
                arr[i] = tempArr[i];
            }
            digit *= 10;
        }
    }

逻辑讲解

逻辑一 部分
for (int i = 0; i < arr.Length; ++i)
{
// arr[i] 的 digit位(1 个位、10 十位、100 百位)上的值
// 以此值作为 countArr 的索引,索引数+1
int index = arr[i] / digit % 10;
countArr[index]++;
}

按照每一位上的数值,统计该位置上的个数
1, 23, 90, 324, 567, 876, 26, 78, 83, 45, 67, 57, 33
以个位数为例:
index = 23 % 10 = 3
countArr[index]++;
就是记录 个位为 3 的添加一个

最终
countArr[0] = 1 :个位为0 的数有 1 个, 90
countArr[1] = 1 :个位为1 的数有 1 个, 1
countArr[2] = 0 :个位为2 的数有 0 个,
countArr[3] = 3 :个位为3 的数有 3 个, 23,83,33
countArr[4] = 1 :个位为4 的数有 1 个, 324,
countArr[5] = 1 :个位为5 的数有 1 个, 45,
countArr[6] = 2 :个位为6 的数有 2 个, 876, 26
countArr[7] = 3 :个位为7 的数有 3 个, 567,67,57
countArr[8] = 1 :个位为8 的数有 1 个, 78
countArr[9] = 0 :个位为9 的数有 0 个,

逻辑二 部分
for (int i = 1; i < countArr.Length; ++i)
{
// 计算每个索引上的数据存放的最大位置下标
countArr[i] += countArr[i - 1];
}

先说第一轮排序后的结果
90,1,23,83,33,324,45,876, 26, 567,67,57,78

最终
countArr[0] = 1 :个位为0 的数有 1 个,90, 最后一个,个位包含 0 的 90 应该排在第 (1 - 1) = 0 个位置
countArr[1] = 2 :个位为1 的数有 1 个, 1, 最后一个,个位包含 1 的 1 应该排在第 (2 - 1) = 1 个位置
countArr[2] = 2 :个位为2 的数有 0 个, 最后一个,个位包含 2 的应该排在第 (2 - 1) = 2 个位置,其实没有个位包含 2 的

解释一下:
个位为 0 的 90,占了 1 个位置
个位为 1 的 1,占了 1 个位置
个位为 3 的 23,83,33,占了 3 个位置,1 + 1 + 3 = 5,所以最后一个,个位包含 3 的 33 应该排在第 (5 - 1)= 4 个位置

countArr[3] = 5 :个位为3 的数有 3 个, 23,83,33, 最后一个,个位包含 3 的 33 应该排在第 (5 - 1)= 4 个位置
countArr[4] = 6 :个位为4 的数有 1 个, 324, 最后一个,个位包含 4 的 324 应该排在第 (6 - 1)= 5 个位置
countArr[5] = 7 :个位为5 的数有 1 个, 45, 最后一个,个位包含 5 的 45 应该排在第 (7 - 1)= 6 个位置
countArr[6] = 9 :个位为6 的数有 2 个, 876, 26 最后一个,个位包含 6 的 26 应该排在第 (9 - 1)= 8 个位置
countArr[7] = 12 :个位为7 的数有 3 个, 567,67,57 最后一个,个位包含 7 的 57 应该排在第 (12 - 1)= 11 个位置
countArr[8] = 13 :个位为8 的数有 1 个, 78 最后一个,个位包含 8 的 78 应该排在第 (13 - 1)= 12 个位置
countArr[9] = 13 :个位为9 的数有 0 个, 最后一个,个位包含 9 的应该排在第 (13 - 1)= 12 个位置,其实没有个位包含 9 的

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值