排序算法之堆排序heapSort

堆排序

堆排序是利用堆这种数据结构所设计的一种排序算法。

算法流程

我们以升序为例:
首先我们需要把给定的数组构建成大顶堆,这样数组中最大的数就是大顶堆的根节点,
然后将根节点与堆中最后的元素交换,这样最大的数就到了数组的最后去了,随后我们把数组最后的元素除开,对剩下的元素重新构建大顶堆,构建完毕之后再把堆的最后一个元素与堆的根节点进行交换,这样第二大的元素就放到了倒数第二个位置上,以此类推,直到堆的大小为1时,堆排序就完成了,动图如下:


排升序,建大顶堆
排降序,建小顶堆
所以堆排序的重点和难点就在于如何构建堆,这里我们使用的是下滤操作,即对于一个结点,首先我们需要在它的左孩子和右孩子中找到更大的结点,然后交换这个最大的结点和原来的结点,在对最大的结点进行上述操作,直到原来的结点比它的左右孩子都大。

实现

/**
 * 堆化
 * 将一个数组调整成大顶堆
 */
template<typename T>
void heapify(T* arr, int parent, int size) {
     
    // 把arr[parent]先存一下
    T temp = arr[parent];
    // 首先将max指向左孩子
    int max = parent * 2 + 1;
    // 下滤
    while (max < size) {
     
        int right = max + 1;
        // 如果右孩子比左孩子大,则max指向右孩子
        if (right < size && arr[right] > arr[max])++max;
        // 如果temp没有arr[max]小则直接退出
        if (temp >= arr[max]) break;
        arr[parent] = arr[max];
        // parent指向max
        parent = max;
        // max指向parent的左孩子
        max = 2 * parent + 1;
    }
    arr[parent] = temp;
}

/**
 * 堆排序
 */
template<typename T>
void heapSort(T* arr, int size) {
     
//    构建大顶堆
//    从数组中间位置开始调整
    for (int i = (size - 1) / 2; i >= 0; --i) {
     
        heapify(arr, i, size);
    }
    for (int i = size - 1; i > 0; i--) {
     
//      交换第一个元素和最后一个元素
        swap(arr[0], arr[i]);
//      因为刚才的交换操作破坏了堆结构,因此重新构建大顶堆
        heapify(arr, 0, i);
    }
}

我测试了一下性能,具体结果如下:

数据数量 10 10^2 10^3 10^4 10^5 10^6 10^7
消耗时间(ms) 0.0006 0.0103 0.1123 1.6422 18.7276 236.176 3169.62

可见 堆排序是性能是非常高的,一千万个数几秒就能完成排序。
它和快速排序、归并排序的时间复杂度都是O (nlogn)。

你可能感兴趣的:(排序算法,算法,数据结构,堆排序,排序算法,快速排序)