堆排序

在《算法导论》第3版第6章讲解了堆排序算法

与归并排序一样,但不同于插入排序的是,堆排序的时间复杂度是O(nlogn)。
而与插入排序相同,但不同于归并排序的是,堆排序同样具有空间原址性:任何时候都只需要常数个额外的元素空间存储临时数据。
因此,堆排序是集合了归并排序、插入排序优点的一种排序算法。

堆排序引入了一种算法设计技巧:使用一种称为“堆”的数据结构来进行信息管理。
堆不仅用在堆排序中,而且它也可以构造一种有效的优先队列。

虽然“堆”这一词源自堆排序,但是目前它已经被引申为“垃圾收集存储机制”,例如在Java和Lisp中所定义的。强调一下,我们使用的堆指的是堆数据结构,而不是垃圾收集存储。

堆排序的过程:
1:初始时候,利用 build_max_heap 将输入数组 A[0..n-1] 建成最大堆
2:因为数组中的最大元素总在根结点 A[0] 中,把它与 A[n-1] 互换,从而让该元素放到正确的位置。
3:这时候,从堆中去掉结点 n-1(–heap_size),剩余的结点中,原来根的孩子结点仍然是最大堆,而新的根结点
可能会违背最大堆的性质。为了维护最大堆的性质,我们要做的是调用 max_heapify(A,i),从而在 A[0..n-2] 上构造一个新的最大堆。
4:不断重复这一过程,直到堆的大小从n-1降到2

代码如下

#include <iostream>

using namespace std;

int heap_size = 0;

// 父结点下标
int parent(int i)
{
    return (i - 1) / 2;
}

// 左孩子下标
int left(int i)
{
    return 2 * i + 1;
}

// 右孩子下标
int right(int i)
{
    return 2 * i + 2;
}

// max_heapify 通过让 A[i] 的值在最大堆中“逐级下降”,从而使得以下标 i 为根结点的子树重新遵循最大堆的性质
void max_heapify(int A[], int i)
{
    int l = left(i);
    int r = right(i);

    int largest = i;
    if (l < heap_size && A[l] > A[i])
        largest = l;

    if (r < heap_size && A[r] > A[largest])
        largest = r;

    if (largest != i)
    {
        swap(A[i], A[largest]);
        max_heapify(A, largest);
    }
}

void max_heapify_iterative(int A[], int i)
{
    bool flag = true;

    while (i < heap_size && flag)
    {
        int l = left(i);
        int r = right(i);

        int largest = i;
        if (l < heap_size && A[l] > A[i])
            largest = l;

        if (r < heap_size && A[r] > A[largest])
            largest = r;

        if (largest != i)
        {
            swap(A[i], A[largest]);
            i = largest;
        }
        else
            flag = false;
    }
}

// 建堆,用自底向上的方法利用过程 max_heapify 把一个大小为 len 的数组 A[0..len-1] 转换为最大堆
void build_max_heap(int A[], int len)
{
    heap_size = len;
    for (int i = (len - 1) / 2; i >= 0; --i)
    {
        max_heapify(A, i);
        // max_heapify_iterative(A, i);
    }
}

void heapsort(int A[], int len)
{
    build_max_heap(A, len);
    for (int i = len - 1; i >= 1; --i)
    {
        swap(A[0], A[i]);
        --heap_size;
        max_heapify(A, 0);
    }
}

int main()
{
    int A[] = { 100, -3, 10, -1, 0, 1000, 200 };
    int len = sizeof(A) / sizeof(A[0]);
    if (len <= 0)
        return 0;

    heapsort(A, len);
    for (int i = 0; i < len; ++i)
        cout << A[i] << endl;

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值