zoukankan      html  css  js  c++  java
  • 堆排序

    原理

    其实就是一种特殊的完全二叉树,分为大顶堆和小顶堆

    大顶堆就是指父节点  >= 左右孩子结点, 而左右孩子结点之间的大小关系随意。小顶堆反之。

    堆排序基本思路

    就是先把序列构建成大顶堆序(升序用大顶堆)

    然后大顶堆的根节点和最后一个结点交换位置,将最大元素沉到数组末端

    这样一来每交换一次就得到当前序列的最大值,并把它放在了最后面,接着把剩下的序列继续构建成大顶堆,重复上面动作,直到序列只剩一个。

    复杂度

    时间复杂度

    分为两部分:初始化建堆和重建堆。

    初始化堆的时间复杂度:O(n)

    重建堆的时间复杂度:O(nlgn)

    故:

    最好情况:O(nlgn)

    最坏情况:O(nlgn)

    平均情况:O(nlgn)

    不稳定

    空间复杂度

    O(1)

    代码

    堆排序

    import java.util.Comparator;
    
    public class MyHeap<T> {
    
        private T[] heap;
    
        private Comparator<? super T> comparable;
    
        public MyHeap(T[] heap, Comparator<? super T> comparable) {
            this.heap = heap;
            this.comparable = comparable;
            initHeap();
        }
    
        public MyHeap(Comparator<? super T> comparable) {
            this.comparable = comparable;
        }
        
        public static void main(String[] args) {
            Integer[] heap = { 6, 4, 7, 2, 9, 15, 11, 10, 18 };
            Comparator<Integer> comparator = new Comparator<Integer>() {
                @Override
                public int compare(Integer o1, Integer o2) {
                    return o1 - o2;
                }
            };
    
            MyHeap<Integer> myHeap = new MyHeap<Integer>(heap, comparator);
            for (int i : heap) {
                System.out.print(i + " ");
            }
    
            System.out.println();
    
            myHeap.sort();
            for (int i : heap) {
                System.out.print(i + " ");
            }
            System.out.println();
        }
    
        public void initHeap() {
            //for (int i = 0; i <= heap.length >> 1 - 1; i++) {//这么写不行
            //从最后一个节点array.length-1的父节点(array.length-1-1)/2开始,直到根节点0,把最大的值弄到根节点
            for (int i = heap.length >> 1 - 1; i >= 0; i--) {
                adjustHeap(heap, i, heap.length);
            }
        }
    
        public void adjustHeap(T[] heap, int i, int heapSize) {
            int left = (i << 1) + 1;
            int right = (i << 1) + 2;
    
            int temp = i;
            if (left < heapSize && comparable.compare(heap[left], heap[i]) > 0) {
                temp = left;
            }
            if (right < heapSize && comparable.compare(heap[right], heap[temp]) > 0) {
                temp = right;
            }
    
            if (temp != i) {
                swap(temp, i);
                adjustHeap(heap, temp, heapSize);
            }
        }
    
        /**
         * 对堆进行排序 (堆排序)
         */
        public void sort() {
    // buildHeap(); 
            for (int i = heap.length - 1; i > 0; i--) {
                swap(0, i);
                adjustHeap(heap, 0, i);
            }
        }
    
        public void swap(int a, int b) {
            T temp = heap[a];
            heap[a] = heap[b];
            heap[b] = temp;
        }
    }

    topN

    因为每一次调整,都是调整出一个最大(小)的数来,所以,可以控制调整的次数。

    甚至可以连第一次都不用全部调整全部的数据。可以先调整N个数,其他的数,再比较一下,是不是可能加到这N个数中,再调整。

    public class MyHeapTest {
    
        public static void main(String[] args) {
            Integer[] heap = { 6, 4, 7, 2, 9, 15, 11, 10, 18 };
    
            Integer[] result = topN(heap, 3);
            for (int integer : result) {
                System.out.print(integer + ",");
            }
        }
    
        public static Integer[] topN(Integer[] n, int size) {
            if (size >= n.length) {
                return n;
            }
    
            Integer[] result = new Integer[size];
            for (int i = 0; i < size; i++) {
                result[i] = n[i];
            }
    
            Comparator<Integer> comparator = new Comparator<Integer>() {
                @Override
                public int compare(Integer o1, Integer o2) {
                    return o2 - o1;// 这是最小堆的写法,最大堆相反,并改变下面的。。
                }
            };
    
            MyHeap<Integer> myHeap = new MyHeap<Integer>(result, comparator);
            for (int i = 0; i < size; i++) {
                System.out.print(result[i] + " ");
            }
            System.out.println();
    
            for (int i = size; i < n.length; i++) {
                if (n[i] > result[0]) {// ....改变这里
                    result[0] = n[i];
                    myHeap.adjustHeap(result, 0, size);
                }
            }
    
            return result;
        }
    }

    优化点

    传入的待排序数据,直接从最后一个节点的父节点开始向上调整。如上面的代码。

    这样不用浪费额外空间,一遍一遍地将最大(小)值找到。

  • 相关阅读:
    PyCharm设置中文字体
    pycharm中设置鼠标滚动放大和缩小页面
    cas5.3.2单点登录-自定义登录页面(十四)
    P1616疯狂的采药
    P2430严酷的训练
    P1164小A点菜
    P1015回文数
    P2871 手链
    《学习OpenCV》课后习题解答6
    《学习OpenCV》课后习题解答5
  • 原文地址:https://www.cnblogs.com/fanguangdexiaoyuer/p/10543988.html
Copyright © 2011-2022 走看看