堆排序学习总结


基本思想

堆是一种完全二叉树, 分为大顶堆和小顶堆.

本篇博客我们默认要进行一个升序排序, 那么我们要构建一个大顶堆

堆排序的算法思想就是先构建一个大顶堆之后, 堆顶元素就是该数列最大值, 然后我们将其(即array[0])和数组末尾元素(即array[i])交换, 然后将剩下的元素(即array[0] 到 array[i - 1])重新进行调整为一个大顶堆, 再进行交换(即array[0] 和 array[i - 1]), 直至排序完毕

根据算法思想我们可以推出, 堆排序是选择排序的一种

选择排序的思想就是:
每次挑选出一个最大 / 最小值, 组成一个有序的子序列

时间复杂度

堆排序的时间复杂度是O(n logn)

初始建堆的过程时间复杂度为O(n)
堆排序过程中对交换后的剩余元素进行堆重建的过程时间复杂度为O(logn)

代码实现


//堆排序
//i结点的父节点下标为(i - 1) / 2,其左子结点下标为2 * i + 1,右子结点下标为2 * i + 2

//调整元素使其成为一个大顶堆/小顶堆
//i是指向的是第i个非叶子结点
void heap_adjust(vector<int>& arr, int i, int len) 
{
    int tmp = arr[i];   //保存当前结点值
    for (int j = 2 * i + 1; j < len; j = 2 * j + 1)   //遍历其子结点
    {
        //j是值较大的子结点下标
        if (j + 1 < len && arr[j] < arr[j + 1]) 
            j++;    
        //如果当前结点比其最大子结点大,就不用调整,break
        if (tmp >= arr[j]) 
            break;
        //将当前结点等于其最大子结点,这时这两个结点值是一样的
        arr[i] = arr[j];
        //改变当前结点指向其最大子结点
        i = j;
    }
    //交换,其最大子结点等于刚才的当前结点
    arr[i] = tmp;
}

void heap_sort(vector<int>& arr) 
{
    //从第一个非叶子结点开始调整
    //即从下往上,从右到左,将每个非叶子结点当做根节点
    //将其和其子树调整为大顶堆
    for (int i = arr.size() / 2 - 1; i >= 0; i--)
        heap_adjust(arr, i, arr.size());
    
    //不停交换堆顶元素和数组尾元素,再将剩下的元素重新调整编程大顶堆
    for (int i = arr.size() - 1; i > 0; i--) 
    {
        swap(arr[0], arr[i]);	//交换堆顶元素和数组末尾元素
        heap_adjust(arr, 0, i);	//对剩下的元素重新进行调整为大顶堆
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值