【经典排序算法】5-堆排序

1. 堆排序的思想

  初始时候,堆排序算法利用BUILD-MAX-HEAP将输入数组A[1…n]建成最大堆,其中n=A.length。
  因为数组中的最大元素总在根节点A[1]中,通过把它和A[n]进行互换,可以将该元素放到正确的位置。这时候,如果我们从堆中去掉结点n,剩余的结点中,原来根的孩子结点仍然是最大堆,而新的根节点可能会违背最大堆的性质。
  为了维护最大堆的性质,我们要做的是调用MAX-HEAPIFY(A, 1),从而在A[1…n-1]上构造一个新的最大堆。
  堆排序算法会不断重复这一过程,直到堆的大小从n-1降到2。

HEAPSORT(A)
	BUILD-MAX-HEAP(A)
	for i = A.length downto 2
		exchange A[1] with A[i]
		A.heap-size = A.heap-size - 1
		MAX-HEAPIFY(A, 1)

2. 堆排序的算法步骤

  堆排序(Heap Sort)是指利用堆这种数据结构所设计的一种排序算法。
  堆分为"最大堆"和"最小堆"。最大堆通常被用来进行"升序"排序,而最小堆通常被用来进行"降序"排序。下面以最大堆举例进行介绍。
  最大堆进行升序排序的基本思想:
  ① 初始化堆:将数列nums[1…n]构造成最大堆。
  ② 交换数据:将nums[1]和nums[n]交换,使nums[n]是nums[1…n]中的最大值;然后将nums[1…n-1]重新调整为最大堆。接着,将nums[1]和nums[n-1]交换,使nums[n-1]是nums[1…n-1]中的最大值;然后将nums[1…n-2]重新调整为最大值。依次类推,直到整个数列都是有序的。

3. 堆排序的代码

  C++实现,要注意的是移位运算符<<优先级小于相加操作+,代码如下:


class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        heapSort(nums);
        return nums;
    }

    void maxHeapify(vector<int>& nums, int k, int size) {
        int lson = (k<<1) + 1;
        int rson = (k<<1) + 2;
        int largest = k;
        if (lson <= size && nums[largest] < nums[lson]) {
            largest = lson;
        }
        if (rson <= size && nums[largest] < nums[rson]) {
            largest = rson;
        }
        if (largest!=k) {
            swap(nums[largest], nums[k]);
            maxHeapify(nums, largest, size);
        }
    }

    void buildMaxHeap(vector<int>& nums, int size) {
        for(int i=(size-1)/2; i >= 0; --i) {
            maxHeapify(nums, i, size);
        }
    }

    void heapSort(vector<int>& nums) {
        // build heap
        int size = nums.size()-1;
        buildMaxHeap(nums, size);
        // keep maxHeapify
        for(int i=size; i > 0; --i) {
            swap(nums[i], nums[0]);
            maxHeapify(nums, 0, --size);
        }
    }
};

4. 堆排序的复杂度分析

  • 时间复杂度:O(nlogn)
  • 空间复杂度:O(1)

5. 堆排序的稳定性分析

  堆排序是不稳定的算法。
  堆排序在交换数据的时候,是比较父结点和子节点之间的数据,所以,即便是存在两个数值相等的兄弟节点,它们的相对顺序在排序也可能发生变化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值