堆排序算法

堆排序算法

可以将堆作为一种数据结构,利用这个数据结构的特点实现排序

堆的性质(最大堆)

  1. 堆的结构与二叉树类似,可以用数组或者Vector实现其结构
  2. 最大堆的根元素比左右儿子都大,且任意子堆都满足该性质
  3. 左右儿子的查找同二叉树,假设以数组的第一个数 arr[0] 作为根结点, arr[i] 的父结点和左右儿子的位置:
    parent(i)=(i1)/2left(i)=2i+1right(i)=2i+2

算法描述

  1. 堆排序思想略微复杂。
    假设堆长度为 n ,按照最大堆的性质,根结点比左右儿子都大,则堆建成之后即可得到堆内最大元素。将最大元素与堆末尾元素交换,对前n1个元素再一次建堆即可得到次大元素…依次递推可实现排序。
    建堆过程是本算法的难点。
  2. 保持堆性质。
    交换最大元素之后,唯有新堆根元素可能不满足最大堆条件。保持函数只是对根和左右儿子操作:根结点若不满足要求,与其左右儿子较大者互换。交换之后的新位置上可能又不满足最大堆条件,则递归调用自己继续与下一层左右儿子互换。直到完成新堆的维护。
  3. 建堆。
    先对部分规则的子堆进行操作保持子堆性质,接下来才进一步看如何从乱序列实现建堆。从最后一个内结点到根结点自底向上逐一调用保持函数即可:先维护子堆,进一步维护上一层堆,直到完成建堆。
  4. 排序。
    需要执行的操作为:每次换出最大的元素,换入原堆末尾元素;并且指定新堆的起始和终止,注意堆大小会逐次减1。

代码实现

#include <iostream>
#include <string>
#include <vector>
using namespace std;
void maxheapify(vector<double> & A, int i, int heapsize)
{
    int lar;
    int l = i*2 + 1;
    int r = i*2 + 2;
    if ((l < heapsize) && (A.at(l) > A.at(i)))
    {
        lar = l;
    }
    else
    {
        lar = i; 
    }
    if ((r < heapsize) && A.at(r) > A.at(lar))
    {
        lar = r;
    }
    cout<<i<<" "<<lar<<endl;
    if (lar != i)
    {
        double temp = A.at(lar);
        A.at(lar) = A.at(i);
        A.at(i) = temp;
        maxheapify(A, lar, heapsize);
    }
}
void buildmax(vector<double> & A)
{
    int heapsize = A.size()-1;
    for (int i=heapsize/2-1; i>=0; --i)
    {
        maxheapify(A, i, heapsize);
    }
}
void heapsort(vector<double> & A)
{
    buildmax(A);
    int heapsize = A.size()-1;
    if (A.size()>1)
    {
        for (int i=A.size()-1; i>=1; --i)
        {
            double temp = A.at(0);
            A.at(0) = A.at(i);
            A.at(i) = temp;
            --heapsize;
            maxheapify(A, 0, heapsize);     
        }
    }
    else
    {
        cout<< A.at(0)<<endl;
    }
}
int main()
{
    double arr[] =  {0.1, 24, 1.8, 3.5, 10, 14, 8, 7, 1, 9, 2, 4, 3, 6};
    int count = (int)(sizeof(arr) / sizeof(arr[0]));
    vector<double> A(arr, arr+count);
    for (int i=0; i<A.size(); ++i)
    {
        cout<<A[i]<<" __ ";
    }
    cout<<endl;
    int p = 0;
    //int r=A.size()-1;
    heapsort(A);
    for (int i=0; i<A.size(); ++i)
    {
        cout<<A[i]<<"  ";
    }
    cout<<endl;
    return 0;
}

复杂度分析

  1. 保持函数维护堆所需时间复杂度为 Θ(lg(n))
  2. 从无序建堆的过程,随着所处里的堆高度 h 增加,每层复杂度也不一样,总复杂度为 h=0lg(n)n2h+1O(h)=O(n)
  3. 堆排序算法总体的复杂度 O(nlg(n))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值