堆排序

堆排序算法

  1. 构建最小堆
  2. 取出最小堆第一个元素(最小值)
  3. 剩下的数据构造最小堆(反复执行2,3直到取出所有的值为止)

数组[72,23,5,68,94,16,71,84,76]表示的树构造最小堆:
这里写图片描述
最小堆的元素有如下关系:
- 节点k的左右节点为2*k+1,2*k+2 ,你如节点5(index=2)左边节点71(index=2*2+1),右边节点84(index=2*2+1)

尽管这个图满足乐这个关系,但是不满足另一个关系(这个图不是最小堆):
- 节点的字节点都比节点大。
构造生成的最小堆:
这里写图片描述
如何通过节点k获取父节点信息?
k/2 就是父节点索引(如果除不尽则舍去小数点,代码中因为是整数除,所以不用管。)
非叶子节点的个数length(array)/2-1
构造最小堆,从根节点开始,如果根节点的左子节点小于根节点,就找根节点孩子节点中更小的值,找到后将值和根节点的值交换,然后沿着下一个节点继续查找(查找不需要找叶子节点,因为叶子节点没有孩子,所以只需要查找length(array)/2-1)个节点。这里发现孩子节点中5最小于是交换5和根节点的位置。对于右节点72 的字节点71,84 ,因为左节点71小于该节点72,于是交换72 节点和他的孩子中的最小值16 交换。完成最小堆的构建。

性能分析

对于最小堆(节点数n,根节点为0层,树的高度为h):
- 第i层节点数最多为n+12hin+12h−i,以上面的例子来看:树的最大节点数n为15(将64,72,71 的叶子补齐)。高度h为4。最后一层的元素个数为(n+1)/2^{4-3}=8,导数第二层(n+1)/2^{4-2}=4
- 第i层所做操作最多为第i 层节点数乘上交换次数。比如例子中最后一层无需做任何交换,但是倒数第二层最多每个节点做一次交换,倒数第三层可能除了和倒数第二层交换后,交换到倒数第二层的元素可能还需要和倒数第一层的元素交换,这样需要两次交换。倒数第四层同样的道理需要3次交换。
i 层交换的次数为2i(hi1)2i∗(h−i−1),总的交换次数为:h2i=02i(hi1)=∑i=0h−22i∗(h−i−1)=

i=0h22i(hi1)=20(h1)+21(h2)+22(h3)++2h2=2h2(1+221+322++h22h3+h12h2)<2h2(1+221+322++h22h3+h12h2+h2h1+)=2h21(11/2)2=2h=n∑i=0h−22i∗(h−i−1)=20(h−1)+21(h−2)+22(h−3)+…+2h−2=2h−2(1+2⋅21+3⋅22+…+h−22h−3+h−12h−2)<2h−2(1+2⋅21+3⋅22+…+h−22h−3+h−12h−2+h2h−1+…)=2h−21(1−1/2)2=2h=n

如果往堆里面插入一个元素需要log2(n)log2(n) 次比较n 个元素插入,删除时间nlog2(n)+nlog2(n)nlog2(n)+nlog2(n)O(nlog(n))O(nlog(n))
在上面的例子中总交换次数次数203+212+22320⋅3+21⋅2+22⋅3
总共时间代价为建堆的时间代价O(nlog(n))O(nlog(n)) 和交换的时间代价nn 的总代价为O(nlog2(n))

代码解析

下面的代码中排序只是一个简单的实现,主要是为了展现堆的数据结构和数组实现。
构造函数用一个MaxSize表示当前堆容纳的数组元素的最大数。CurrentSize是当前存放的数据的大小,heapArray存放待排序数据中的所有元素。

#include <iostream>
using namespace std;
class MinHeap{
private:
    int *heapArray;
    int CurrentSize;
    int MaxSize;
    void BuildHeap(int n);

public:
    MinHeap(const int n,const int *a);//构造函数实现创建一个n个元素的堆,最大容量为n+10
    virtual ~MinHeap();//析构函数
    bool isLeaf(int pos) const;//是不是叶子节点(在排序中没有用)但是应该作为堆的一部分才更完三
    int leftchild(int pos) const;//是不是左孩子,这里这个函数也不是必须,主要是用来确定孩子那个更小,将更小的向上siftup
    int parent(int pos) const;//获取当前位置的父节点
    bool Remove(int pos,int & node);//删除位置pos的元素给赋值给node
    bool Insert(const int &newNode);//插入newnode元素
    void RemoveMin(int &min_val);//删除堆的第一个元素(最小值)
    void SiftUp(int position);//向上交换
    void SiftDown(int position);//向下交换
    void show();//方便调试
    void sort();
};
MinHeap::MinHeap(const int n,const int *a) {
    CurrentSize = n;
    MaxSize = CurrentSize+10;
    heapArray = new int[MaxSize];
    int i=0;
    for(int i=0;i<n;i++)
        heapArray[i] = a[i];
    BuildHeap(CurrentSize);
}
MinHeap::~MinHeap() {
    delete [] heapArray;
}
void MinHeap::SiftDown(int position) {
    int i = position;
    int j = 2*i+1;
    int temp = heapArray[i];
    while(j<CurrentSize)
    {
        if(j<CurrentSize-1&&heapArray[j]>heapArray[j+1])
            j++;
        if(temp>heapArray[j])
        {
            heapArray[i] = heapArray[j];
            i = j;
            j = 2*j+1;
        }
        else
            break;
    }
    heapArray[i] = temp;
}
void MinHeap::BuildHeap(int n) {
    CurrentSize = n;
    for(int i=CurrentSize/2-1;i>=0;i--)
    {
        SiftDown(i);
    }
}
void MinHeap::SiftUp(int position) {
    int temppos = position;
    int temp = heapArray[temppos];
    while((temppos>0)&&(heapArray[parent(temppos)]>temp))
    {
        heapArray[temppos] = heapArray[parent(temppos)];
        temppos=parent(temppos);
    }
    heapArray[temppos] = temp;
}
bool MinHeap::Remove(int pos, int &node) {
    if((pos<0)||(pos>=CurrentSize))
        return false;
    int temp = heapArray[pos];
    heapArray[pos] = heapArray[--CurrentSize];
    if(heapArray[parent(pos)]>heapArray[pos])
        SiftUp(pos);
    else
        SiftDown(pos);
    node = temp;
    return true;
}
int MinHeap::parent(int pos) const {
    return pos/2;
}
void MinHeap::RemoveMin(int &min_val) {
    min_val = heapArray[0];
    for(int i=1;i<CurrentSize;i++)
        heapArray[i-1]=heapArray[i];
}
bool MinHeap::isLeaf(int pos) const {
    if(pos*2+1>=CurrentSize)
        return true;
    else
        return false;
}
int MinHeap::leftchild(int pos) const {
    if(pos*2+1<CurrentSize)
        return pos*2+1;
}
bool MinHeap::Insert(const int &newNode) {
    if(CurrentSize == MaxSize)
        return false;
    heapArray[CurrentSize] = newNode;
    SiftUp(CurrentSize);
    CurrentSize++;
}
void MinHeap::show() {
    for(int i=0;i<CurrentSize;i++)
        cout<<heapArray[i]<<" ";
    cout<<"\n";
}
void MinHeap::sort() {
    int min_val;
    for(int i=CurrentSize;i>0;i--)
    {
        BuildHeap(i);
        RemoveMin(min_val);
        cout<<min_val<<" ";
    }
    cout<<"\n";
}
int main()
{
    int a[] = {72,23,5,68,94,16,71,84,76};
    MinHeap m = MinHeap(9,a);
    m.Insert(63);
    m.show();
//    m.sort();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值