排序算法之七 堆排序(Heap Sort)

概述

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

算法描述

  1. 将待排序的元素序列(R1,R2….Rn)构建成最大堆,此堆为初始的无序区。(关于最大堆的详细构建过程请点这里
  2. 将最大堆的堆顶元素R1(当前堆树中的最大值)与最后一个元素Rn交换。此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];
  3. 由于交换后新的堆顶R1可能违反了最大堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)重新调整为最大堆,然后再次将R1与无序区最后一个元素交换,得到新的无序区(R1,R2,……Rn-2)和有序区(Rn-1,Rn)。不断重复此过程直到无序区的元素个数为1;

堆排序是不稳定的排序算法,不稳定发生在堆顶元素与A[i]交换的时刻。
比如序列:{ 10, 4, 6, 4 },堆顶元素是10,堆排序下一步将10和第二个4进行交换,得到序列 { 4, 4, 6, 10 },再进行堆调整得到{ 6, 4, 4, 10 },重复之前的操作最后得到{ 4, 4, 6, 10 }从而改变了两个4的相对次序。

堆排序C/C++代码:

void Swap(int arr[], int i, int j)
{
    int temp=arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}


/**
* 将父节点为aar[i]的子树调整为最大堆
* @param arr 堆数组
* @param size 堆数组长度
* @param i 节点索引
*/
void AdjustHeap(int arr[],int size,int i)
{
    int left_child = 2*i+1;    //左子节点索引
    int right_child = 2*i+2;   //右子节点索引
    int max = i;               //选出当前结点与其左右孩子三者之中的最大值
    if (left_child < size && arr[left_child] > arr[max]) {
        max = left_child;
    }

    if (right_child < size && arr[right_child] > arr[max]) {
        max = right_child;
    }

    if (max != i) {
        Swap(arr, i, max);    //将最大值节点与父节点互换
        AdjustHeap(arr, size, max); //递归调用,继续从当前节点向下进行堆调整
    }
}

/**
* 根据输入的数组构建一个最大堆
* @param arr 堆数组
* @param size 堆数组长度
* @return 堆数组长度
*/
int BuildMaxHeap(int arr[], int size) {
    //对每一个非叶节点开始向下进行最大堆调整
    for (int i = size / 2 - 1; i >= 0; i--)
    {
        AdjustHeap(arr, size, i);
    }
    return size;
}


/**
* 堆排序
* 最差时间复杂度 O(nlogn)
* 最优时间复杂度 O(nlogn)
* 平均时间复杂度 O(nlogn)
* 空间复杂度     O(1)
* 稳定性         不稳定
* @param arr 数组
* @param size 长度
*/
void HeapSort(int arr[], int size)
{
    int heap_size = BuildMaxHeap(arr, size);
    while (heap_size > 1) {  //堆(无序区)元素个数大于1,未完成排序
        //将堆顶元素与堆的最后一个元素进行交换,并从堆中去掉最后一个元素
        //由于交换后的新的堆顶可能违反堆的性质,所以需要对该堆进行重新调整为最大堆
        //此处交换操作很有可能把后面元素的稳定性打乱,所以堆排序是不稳定的排序算法
        Swap(arr, 0, --heap_size);
        AdjustHeap(arr, heap_size, 0); // 从新的堆顶元素开始向下进行堆调整,时间复杂度O(logn)
    }
}

元素序列{ 1, 3, 4, 5, 2, 6, 9, 7, 8, 0 }的堆排序流程示意图如下:
在这里插入图片描述
堆排序后的输出的元素序列为:{9,8,7,6,5,4,3,2,1,0}

发布了87 篇原创文章 · 获赞 28 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/MakerCloud/article/details/86364272
今日推荐