堆排序的C++实现


堆排序的时间复杂度O(n)=nlog n,它实际上是简单选择排序的一个改进算法。为了了解这一算法,需要对大顶堆和小顶堆的性质有一定了解。这里不再赘述。

堆排序借用了完全二叉树的性质,通过将数组构造成具有特殊性质的完全二叉树(大顶堆和小顶堆),根节点就是最大值或最小值,我们将根节点与堆(元素个数为k)得最后一个元素进行交换,并将最后一个元素排除在堆之外,此时得到的新堆(元素个数为k-1)明显不再是一个大顶堆或小顶堆,需要对其进行重新构造。接下来便是堆排序的精髓了,理解了这点,便能明白为何堆排序的时间复杂度为nlogn。新堆除了根节点root外全部符合顶堆的性质,以大顶堆为例,设根节点的左右孩子为LChild和RChild,将root,LChild,RChild进行比较,假设LChild的值大于RChild的值(根节点一定小于它的左右孩子节点中的一个),将LChild和root进行交换,此时得到的新root值便是最大值,但经过此次调整,新root的左子树却不一定符合顶堆的性质,需要再次进行调整,但右子树之前就符合顶堆的性质,无需进行调整也符合顶堆的性质。对左子树进行调整时,可将左孩子作为根节点,重复上面的步骤,由于每次只需进行左或右子树的调整,运行次数小于等于log n,对数的底为2。就这样看来,堆排序实际上就如同冒泡排序一样,每次循环找出最值,放在最后面,循环n次即可完成排序。

为了对一个杂乱的数组进行堆排序,实际上需要两步,1.将数组变成大顶堆或小顶堆 2.每次交换根节点和最后一个元素,再将最后一个元素排除堆之外,对新堆进行调整,不断重复。具体源码如下:

#include <iostream>
#include <vector>

using namespace std;
/*************************************************************
由于树的节点从1开始,而数组从0开始,因此凡遇到与arrays[]有关,
都是代表下标+1 个节点,如arrays[j-1]代表二叉树中第j个节点
*************************************************************/

void HeapBuildFromArray(vector<int> &arrays)     //这个函数可以和下面的函数写成一个,为了便于理解,特意写成两个函数
{
    int length=arrays.size();
    for(int j=length/2;j>0;j--)                 //先从最后一个非叶子节点开始构造,这样在进行其他非叶子节点的调整时,除该节点外,其
    {                                           //他均符合顶堆的定义
        int temp;
        temp=arrays[j-1];
        int nums=j;
        for(int i=2*nums;i<=length;i=2*i)         //以第j个节点为根节点,构造顶堆,直到结构符合顶堆性质,结束调整
        {                                         //对于完全二叉树而言,节点*2就代表此节点的左孩子节点
            if(i<length&&arrays[i-1]<arrays[i])   //当右孩子节点比左孩子节点的值大时,便将i变更为右孩子节点
            {
                i++;
            }
            if(temp>=arrays[i-1])                 //说明不需要再进行调整,此时以节点j为根节点的二叉树调整完毕
                break;
            arrays[nums-1]=arrays[i-1];
            nums=i;
        }
        arrays[nums-1]=temp;
    }
}
void HeapBuild(vector<int> &arrays,int length)
{
    int temp;
    temp=arrays[0];
    int nums=1;
    for(int i=2*nums;i<=length;i=2*i)          //进行堆的构造时,只需对左右子树的其中一边进行调整,与上面的第二层循环代码相同
    {
        if(i<length&&arrays[i-1]<arrays[i])
        {
            i++;
        }
        if(temp>=arrays[i-1])
            break;
        arrays[nums-1]=arrays[i-1];
        nums=i;
    }
    arrays[nums-1]=temp;
}
void HeapSort(vector<int> &arrays)
{
    HeapBuildFromArray(arrays);
    int length=arrays.size();
    for(int i=length;i>1;i--)
    {
        swap(arrays[0],arrays[i-1]);
        HeapBuild(arrays,i-2);
    }
}
int main()
{
    vector<int> arrays={4,8,2,3,7,5,9,1,6,3,6,10,-1};
    HeapSort(arrays);
    for(auto c:arrays)
        cout<<c<<endl;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值