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

堆排序是一种基于完全二叉树的排序算法,通过构建最大堆进行排序。它首先将待排序序列构建成最大堆,然后将堆顶元素与末尾元素交换,再对剩余元素重新调整为最大堆,如此反复,最终实现排序。堆排序是不稳定的排序算法,不保证相等元素的相对顺序。示例中给出了堆排序的C/C++代码,以及一个具体的堆排序流程示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

堆排序(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}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值