堆排序(HeapSort)

905 阅读1分钟

冒泡排序及优化

选择排序(SelectionSort)

堆排序(HeapSort)

插入排序及优化

升序

堆排序可以认为是选择排序的一种优化

时间复杂度是O(NlogN),不稳定

核心思想

  1. 对序列进行原地建堆(heapify)。

  1. 将第一个元素与最后一个元素交换位置(大顶堆,交换堆顶元素和堆尾元素)。

  2. 堆的元素减一。

  3. 对堆顶进行一次siftdown操作

  1. 重复上面2~4步,直到堆元素只剩1个。

时间复杂度 : 步骤1 O(n) +步骤5 O(n-1)* 步骤2~4 O(1+1+logn)= O(n)+O(nlogn)=O(nlogn)

代码实现

public class HeapSort extends Sort {

    private int heapSize;

    @Override
    protected void sort() {

        // 原地建堆
        heapSize=array.length;
        for (int i = (heapSize >> 1) - 1; i >= 0; i--) {
            siftDown(i);
        }
        
        while (heapSize > 1) {
            //交换对顶元素和尾部元素,heapSize--
            swap(0, --heapSize );

            //对0位置siftDown,恢复堆的性质
            siftDown(0);
        }

    }

    private void siftDown(int index) {
        Integer element = array[index];

        int half = heapSize >> 1;
        while (index < half) { // index必须是非叶子节点
            // 默认是左边跟父节点比
            int childIndex = (index << 1) + 1;
            Integer child = array[childIndex];

            int rightIndex = childIndex + 1;
            // 右子节点比左子节点大
            if (rightIndex < heapSize &&
                    cmp(array[rightIndex], child) > 0) {
                child = array[childIndex = rightIndex];
            }

            // 大于等于子节点
            if (cmp(element, child) >= 0) break;

            array[index] = child;
            index = childIndex;
        }
        array[index] = element;
    }
}

写了个demo测试了冒泡,选择和堆排序的效率输出结果如下:

【HeapSort】
耗时:0.001s(1ms) 	比较:1.69万	 交换:999
------------------------------------------------------------------
【BubbleSort】
耗时:0.007s(7ms) 	比较:21.52万	 交换:13.87万
------------------------------------------------------------------
【SelectionSort】
耗时:0.007s(7ms) 	比较:49.95万	 交换:999
------------------------------------------------------------------

Process finished with exit code 0

可以看到 选择排序和堆排序元素交换的次数是一样的。

堆排序是不稳定排序,由于是 原地建堆所以空间复杂度是O(1)

参考:小码哥的恋上数据结构第二期