堆排序的实现

201 阅读2分钟

堆排序是一种时间复杂度O(lgn),空间复杂度O(1)的排序算法,可以自己实现堆排序,java中的PriorityQueue工具类也直接提供了实现。

自己实现堆排序

public class HeapSort {

    /**
     * 上浮调整
     *
     * @param arr
     */
    public static void upAdjust(int[] arr) {
        int childIndex = arr.length - 1;
        int parentIndex = (childIndex - 1) / 2;
        //temp保存插入的待插入的叶子节点值,用于最后的赋值
        int temp = arr[childIndex];
        while (childIndex > 0 && temp < arr[parentIndex]) {
            arr[childIndex] = arr[parentIndex];
            childIndex = parentIndex;
            parentIndex = (parentIndex - 1) / 2;
        }

        arr[childIndex] = temp;
    }

    /**
     * 下沉调整
     *
     * @param arr         待调整堆
     * @param parentIndex 要下沉的父节点索引
     * @param len         堆的有效大小
     */
    public static void downAdjust(int[] arr, int parentIndex, int len) {
        int childIndex = parentIndex * 2 + 1;
        //temp保存待插入的父节点值,用于最后的赋值
        int temp = arr[parentIndex];
        while (childIndex < len) {
            if (childIndex + 1 < len && arr[childIndex + 1] < arr[childIndex]) {
                childIndex++;
            }

            if (temp <= arr[childIndex]) {
                break;
            }

            arr[parentIndex] = arr[childIndex];
            parentIndex = childIndex;
            childIndex = childIndex * 2 + 1;
        }

        arr[parentIndex] = temp;
    }

    /**
     * 构建堆
     *
     * @param arr
     */
    public static void buildHeap(int[] arr) {
        //从最后一个非叶子节点开始,依次下沉调整
        for (int i = arr.length / 2 - 1; i >= 0; i--) {
            downAdjust(arr, i, arr.length);
        }
    }

    /**
     * 堆排序
     *
     * @param arr
     */
    public static void heapSort(int[] arr) {
        buildHeap(arr);
        for (int i = arr.length - 1; i > 0; i--) {
            int temp = arr[i];
            arr[i] = arr[0];
            arr[0] = temp;

            downAdjust(arr, 0, i);
        }
    }

    public static void main(String[] args) {
        arr = new int[]{7, 1, 3, 10, 5, 2, 8, 9, 6};
        heapSort(arr);
        System.out.println(Arrays.toString(arr));

    }

}

PriorityQueue实现堆排序

        int[] arr = new int[]{7, 1, 3, 10, 5, 2, 8, 9, 6};
        PriorityQueue<Integer> queue = new PriorityQueue<Integer>((k1,k2) -> k2-k1);
        for (int i : arr) {
            queue.offer(i);
        }
        int[] res = new int[9];
        int j = 0;
        while (!queue.isEmpty()) {
            res[j++] = queue.poll();
        }
        System.out.println(Arrays.toString(res));

TopK问题

问题:有n个数,找出其中最小的k个数,例如,输入[4,5,1,6,2,7,3,8],则最小的4个数是1,2,3,4

解法:

 public int[] getLeastNumbers(int[] arr, int k) {
        if (k == 0) {
            return new int[0];
        }
        // 使用一个最大堆(大顶堆)
        // Java 的 PriorityQueue 默认是小顶堆,添加 comparator 参数使其变成最大堆
        Queue<Integer> heap = new PriorityQueue<>(k, (i1, i2) -> Integer.compare(i2, i1));

        for (int e : arr) {
            // 当前数字小于堆顶元素才会入堆
            if (heap.isEmpty() || heap.size() < k || e < heap.peek()) {
                heap.offer(e);
            }
            if (heap.size() > k) {
                heap.poll(); // 删除堆顶最大元素
            }
        }

        // 将堆中的元素存入数组
        int[] res = new int[heap.size()];
        int j = 0;
        for (int e : heap) {
            res[j++] = e;
        }
        return res;
    }

参考:

1.程序员小灰《什么是二叉堆》

2.mp.weixin.qq.com/s/je3GvIBPL…