线性时间非比较类排序之基数排序

基数排序

基数排序是桶排序的扩展,因此又称“桶子法”,它是通过键值的部分信息,将要排序的元素分配至某些“桶”中,以达到排序的作用。

1. 算法思想

将各元素按位数切割成不同的数字,然后分别根据每个位数的比较结果进行排序。

2. 算法步骤

  1. 确定待排序序列的最大位数。
  2. 将所有待排序元素统一为最大数位长度(左补0)。
  3. 从最低位到最高位分别进行排序。
  4. 当最高位排序完成后,原数组变成有序序列。

3.算法分析

基数排序的执行效率非常高。我们要做的仅仅是把原始数据项从数组复制到链表中,然后再复制回去。如果待排序序列有10个数据项和 5个数位,则只需要10×2×5=100次复制:如果待排序序列有 100个数据和5个数位,则需要100×2×5=1000次复制⋯⋯复制次数和数据项的个数成正比,即O(n)。这简直就是最高效率的排序算法。
但是,当数据项增加 10倍时,一切就不一样了。关键字必须增加一位,多了一轮排序。复制的次数和数据项的个数与关键字长度成正比,可以认为关键字的长度是n的对数,因此在大多数情况下,基数排序的执行效率倒退为 O ( n l o g 2 n ) O(nlog_2 n) O(nlog2n),和快速排序差不多。
快速排序参考这篇文章
空间复杂度很好算,它是在分配元素时使用的桶空间,即10n,达此全间复杂度为O(n)。

4.算法代码

算法代码如下:
Python

# -*- coding: utf-8 -*-

# 基数排序
def radix_sort(arr) :
    maximum = max (arr) # 确定待排序数组中的最大位数
    d = 0 #d 为最大位数,初始为0
    while maximum != 0: # != ——不等于
        maximum = maximum // 10
        d += 1
    for i in range(d): # d轮排序
        s = [[] for k in range(10)] # 因为每一位数字都是0~9,所以建10个桶
        for j in arr:
            s[int(j /(10 ** i))%10].append(j) # 从个位数开始逐一进行分桶排序
        arr = [a for b in s for a in b] # 用10个桶回填原数组
    return arr

# 调用 radix-sort函数
print(radix_sort([34, 21, 13, 2, 5, 1,55,3, 1, 8]))

Java

  public static List<Integer> radixSort(List<Integer> arr) {
        int maximum = findMax(arr); // 确定待排序数组中的最大值
        int d = 0; // d 为最大位数,初始为0

        while (maximum != 0) {
            maximum /= 10;
            d++;
        }

        for (int i = 0; i < d; i++) { // d轮排序
            List<List<Integer>> buckets = new ArrayList<>();
            for (int k = 0; k < 10; k++) {
                buckets.add(new ArrayList<>());
            }

            for (int j : arr) {
                int digit = getDigit(j, i);
                buckets.get(digit).add(j);
            }
            arr = new ArrayList<>(); // 使用新的 ArrayList 替换旧的,以避免 UnsupportedOperationException
            for (List<Integer> bucket : buckets) {
                arr.addAll(bucket);
            }

        }

        return arr;
    }

    private static int findMax(List<Integer> arr) {
        int max = Integer.MIN_VALUE;
        for (int num : arr) {
            max = Math.max(max, num);
        }
        return max;
    }

    private static int getDigit(int number, int index) {
        int digit = number / (int) Math.pow(10, index);
        digit %= 10;
        return digit;
    }

        @Test
        void contextLoads () {
            List<Integer> arr = List.of(34, 21, 13, 2, 5, 1, 55, 3, 1, 8);
            arr = radixSort(arr);
            System.out.println(arr);
        }

5.输出结果

代码输出结果如下:
在这里插入图片描述

6. 算法过程分解

在这里插入图片描述

  • 17
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

忆梦九洲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值