桶排序 JAVA

思路:

  1. 已知待排序数组arr。创建桶数组 ListNode[] buckets(arr.length),定义每个桶容纳的数据区间长度为 bucketLEN = (max - min + 1) / arr.length + 1, 对于第 i 区间数据区间为 [bucketLEN * i, (i+1)*bucketLEN-1)
  2. 对每个桶进行排序,即对每个单链表进行排序(leetcode 148
  3. 从小到大遍历桶,将数据合并到 arr 中

时间复杂度:

分析参考:https://blog.csdn.net/zihonggege/article/details/104781491/

性能分析:

经过上面的分析,你应该懂得了桶排序的思想。不过你可能会有一个疑问:每个桶内再用其他的排序算法进行排序(比如快排),这样子时间复杂度不还是 O(nlogn) 吗?请看下面这段分析。

如果要排序的数据有 n 个,我们把它们分在 m 个桶中,这样每个桶里的数据就是 k=n/m 。每个桶内排序的时间复杂度就为 O(k*logk)。m 个桶就是 m * O(k * logk) = m * O((n / m) * log(n / m))=O(n * log(n / m))。当桶的个数 m 接近数据个数 n 时,log(n/m)就是一个较小的常数,所以时间复杂度接近 O(n)。


public class BucketSort {

    public static void main(String[] args) {
        // test cases
        int[][] nums = {{31, 33, 27, 15, 42, 11, 40, 5, 19, 21}, {98, 34, 100, 36, 44, 64, 3, 99, 59},
                {66, 62, 4, 65, 49, 71, 71, 24, 12}, {14, 3, 58, 23, 12, 66, 11, 45, 36},
                {55, 64, 35, 24, 85, 73, 33, 85, 46}, {94, 76, 23, 36, 57, 26, 8, 92, 17},
                {85, 68, 52, 34, 53, 93, 4, 37, 34}, {70, 9, 15, 42, 31, 16, 72, 61, 62},
                {11, 38, 34, 21, 81, 9, 45, 68, 11}, {20, 83, 27, 6, 69, 26, 5, 31, 8},
                {74, 97, 11, 60, 1, 68, 14, 27, 46}, {5, 8, 7, -5, 9, 2, 0, 8, 3, 20}};

        // test each case by bucket sort
        for (int[] num : nums) {
            System.out.println("before: " + Arrays.toString(num));

            bucketSort(num);

            System.out.println("after: " + Arrays.toString(num));
            System.out.println("----------------");
        }
    }

    public static void bucketSort(int[] arr) {

        if (arr.length == 0) return;
        int min = Integer.MAX_VALUE;
        int max = Integer.MIN_VALUE;

        for (int n : arr) {
            min = Math.min(min, n);
            max = Math.max(max, n);
        }

        // n-th bucket ===>> [n * bucketLEN, (n+1)*bucketLEN - 1)
        int bucketLEN = (max - min + 1) / arr.length + 1;

        // number of bucket
        ListNode[] buckets = new ListNode[arr.length];

        // iterate over source array, put them into buckets array
        int index;
        for (int n : arr) {

            // find target bucket
            index = (n - min) / bucketLEN;

            // put element into buckets[index]
            if (index >= arr.length)
                throw new RuntimeException("bad buckets!");
            else if (buckets[index] == null) {
                buckets[index] = new ListNode(n);
            } else {
                // put new node at the 0 position of the bucket
                buckets[index] = new ListNode(n, buckets[index]);
            }

        }

        // sort every bucket separately
        for (int i = 0; i < arr.length; i++) {

            // list merge sort
            buckets[i] = sortList(buckets[i]);
        }

        // combine buckets into array
        index = 0;
        ListNode cur;
        for (int i = 0; i < arr.length; i++) {
            cur = buckets[i];
            while (cur != null) {
                arr[index++] = cur.val;
                cur = cur.next;
            }
        }

    }

    static class ListNode {
        int val;
        ListNode next;

        ListNode() {
        }

        ListNode(int val) {
            this.val = val;
        }

        ListNode(int val, ListNode next) {
            this.val = val;
            this.next = next;
        }
    }


    // prepare before sort
    public static ListNode sortList(ListNode head) {

        // use dummy node, more easily
        HEAD_DUMMY = new ListNode(-1);
        TAIL_DUMMY = new ListNode(-1);

        sort(head); // do sort list

        return HEAD_DUMMY.next;
    }

    //dummy node
    static ListNode HEAD_DUMMY, TAIL_DUMMY;

    /**
     * merge sort on list.
     * use fast-slow-pointers method to positioning middle node in the list.
     * fast-slow-pointers method:
     * 1. define two pointers, iterating over the list from front to end
     * 2. fast pointer moves two step while slow pointer moves one step every time util faster can't move,
     * 3. in the end, slow pointer points to the middle of the list.
     * <p>
     * finally: headDummy.next is the real head, and tailDummy.next is the real tail.
     */
    public static void sort(ListNode head) {
        // base cases
        if (head == null || head.next == null)
            HEAD_DUMMY.next = TAIL_DUMMY.next = head;//when number of list node = 0 or 1
        else if (head.next.next == null) {//when number of list node = 2
            if (head.val > head.next.val) {
                head.next.next = head;
                head = head.next;
                head.next.next = null;
            }
            HEAD_DUMMY.next = head;
            TAIL_DUMMY.next = head.next;
        } else {//when number of list node >= 3, like 3->4->5...

            // split list by fast-slow-pointer method
            ListNode fast = head.next.next, slow = head.next;
            while (fast.next != null && fast.next.next != null) {
                fast = fast.next.next;
                slow = slow.next;
            }

            // ===>  head->..->slow->null,  tmp->...->null
            ListNode tail, tmp = slow.next;
            slow.next = null;

            //left half list
            sort(head);
            head = HEAD_DUMMY.next;
            tail = TAIL_DUMMY.next;

            //right half list
            sort(tmp);

            //merge left and right part of list
            HEAD_DUMMY.next = mergeTwoLists(head, HEAD_DUMMY.next);
            TAIL_DUMMY.next = (tail.val > TAIL_DUMMY.val) ? tail : TAIL_DUMMY;
        }

    }

    // merge two list
    public static ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode head, cur = new ListNode(-1);
        head = cur;
        while (true) {
            if (l1 == null || l2 == null) {
                cur.next = (l1 == null) ? l2 : l1;
                break;
            } else {
                if (l1.val < l2.val) {
                    cur.next = l1;
                    l1 = l1.next;
                } else {
                    cur.next = l2;
                    l2 = l2.next;
                }
                cur = cur.next;
            }
        }
        return head.next;
    }

}
posted @ 2021-10-26 11:14  egu0o  阅读(116)  评论(0编辑  收藏  举报