zoukankan      html  css  js  c++  java
  • 桶排序 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;
        }
    
    }
    
    沉舟侧畔千帆过,病树前头万木春。
  • 相关阅读:
    如何使用设计模式系列
    网站性能越来越差怎么办
    ASP.NET特殊字符串替换函数
    SQL Server多事务并发问题
    弹出隐藏子菜单
    过滤sql匹配符号 防止sql注入
    统一建模语言UML轻松入门系列
    sql 字符处理函数大全
    并发控制
    类与类之间的关系图
  • 原文地址:https://www.cnblogs.com/engure/p/15464896.html
Copyright © 2011-2022 走看看