基数排序及Java实现(学习笔记)

基数排序及Java实现(学习笔记)

1.比较的对象是整数或者可以转化为整数

2.设整数最大位数为d,且是r进制(基数为r)的。

比如d=3,r=10的1个序列[001,100,200,201,210,211]

满足1,2条件的序列才能用基数排序

3.步骤
(1)首先初始化r个队列,[Q0,Q1,Q2,…Qr-1],设序列为[a0,a1,a2,…an-1]

在这里插入图片描述

(2)排序每一趟分为两个步骤,分配和收集,总趟数为r,设当前趟数为i

(3)分配:清空队列[Q0,Q1,Q2,…Qr-1],然后查看每个关键字的第i位,放入对应的队列中

取位的时候分为高位优先(MSD)和低位优先(LSD)
例如:a=123 如果是高位优先,则第1位是1;如果是低位优先,则第1位是3

(4)把队列中的元素首尾相接,连在一起

举例说明:
在这里插入图片描述
4.性能分析

假设元素已经节点化了,是用链式存储的

(1)空间复杂度:需要一个数组来存储r个队列的头尾指针,所以是O( r )

(2)时间复杂度:一共有d趟,对于每一趟的分配是O(n),收集是O( r )(链表的拼接本身是O(1)的),总时间复杂度为O( d*(n+r) )

当最大位数和进制为常数时,时间复杂度认为是O(n)

5.代码实现

(1)这里用int类型举个例子
(2)我的实现空间复杂度更大,因为我假定开始序列是顺序存储的,需要转化一下,需要额外的空间,达到了O( n ),这也比较符合实际情况吧。如果本来就是链式的,空间复杂度就是O( r )了

首先要定义一下链表,为了快速拼接,可以添加节点或者拼接链表

    private static class Node {
    
    
        // 数字
        int elem;
        // 数字按位分解
        int[] bits;
        // 下一个节点
        Node next;
    }

    private static class LinkList {
    
    
        Node head;
        Node tail;

        // 添加节点 时间复杂度:O(1)
        void append(Node node) {
    
    
            if (head == null && tail == null) {
    
    
                head = node;
                tail = node;
                return;
            }
            tail.next = node;
            tail = node;
        }

        // 链表拼接 时间复杂度:O(1)
        void joint(LinkList linkList) {
    
    
            if (linkList.head == null && linkList.tail == null) {
    
    
                return;
            }
            if (head == null && tail == null) {
    
    
                head = linkList.head;
                tail = linkList.tail;
                return;
            }
            if (this.tail != null) {
    
    
                this.tail.next = linkList.head;
            }
            this.tail = linkList.tail;
        }

        // 清空,重复利用
        void clear() {
    
    
            head = null;
            tail = null;
        }

        // 主要调试时候使用
        public String toString() {
    
    
            Node c = head;
            StringBuilder sb = new StringBuilder();
            while (c != tail) {
    
    
                sb.append(c.elem + " ");
                c = c.next;
            }
            if (tail != null) {
    
    
                sb.append(c.elem + " ");
            }
            return sb.toString();
        }
    }

然后定义分解方法(decomposition)(可以把数字按位分解)和整数版本的求指数方法(pow)

    // 求a^b,由于Math.pow()是浮点型不合适
    private static int pow(int a, int b) {
    
    
        int n = 1;
        while (b-- > 0) {
    
    
            n *= a;
        }
        return n;
    }

    // 按位分解

    /***
     *@param elem:待分解元素
     *@param r:进制
     *@param d:最大位数
     *@return 分解结果
     */

    private static int[] decomposition(int elem, int r, int d) {
    
    
        int[] a = new int[d];
        int index = 0;
        for (int i = d - 1; i >= 0; i--) {
    
    
            a[index] = elem / pow(r, i);
            elem -= a[index] * pow(r, i);
            index++;
        }
        return a;
    }

最后写排序方法,先初始化转化为链表,然后是d趟的分配和收集

    public static void radixSort(int[] array, int r, int d) {
    
    
        // 初始化
        LinkList rlt = new LinkList();
        for (int elem : array) {
    
    
            Node node = new Node();
            node.elem = elem;
            node.bits = decomposition(elem, r, d);
            rlt.append(node);
        }
        LinkList[] buckets = new LinkList[r];
        for (int i = 0; i < buckets.length; i++) {
    
    
            buckets[i] = new LinkList();
        }
        // d趟
        for (int i = d - 1; i >= 0; i--) {
    
    
            // 分配
            Node c = rlt.head;
            while (c != rlt.tail) {
    
    
                buckets[c.bits[i]].append(c);
                c = c.next;
            }
            if (c != null) {
    
    
                buckets[c.bits[i]].append(c);
            }
            rlt.clear();
            // 收集
            for (int j = 0; j < buckets.length; j++) {
    
    
                LinkList linkList = buckets[j];
                rlt.joint(linkList);
                linkList.clear();
            }
        }
        Node c = rlt.head;
        int index = 0;
        while (c != rlt.tail) {
    
    
            array[index++] = c.elem;
            c = c.next;
        }
        if(c!=null){
    
    
            array[index++] = c.elem;
        }

    }

JUnit单元测试代码(主函数中运行效果相同):

    @Test
    public void testRadixSort() {
    
    
        int[] a = {
    
    211, 210, 201, 200, 100, 1};
        System.out.println(Arrays.toString(a));
        radixSort(a, 10, 3);
        System.out.println(Arrays.toString(a));
    }

控制台结果:

在这里插入图片描述
转载请注明出处,谢谢合作

猜你喜欢

转载自blog.csdn.net/weixin_42111859/article/details/104196565