堆排序

8 篇文章 0 订阅

N个元素称为堆,若它的元素序列k[1],k[2],k[3].....K[n]满足 

       k[i]<=k[2i]  ,k[i]<=k[2i+1]     1<=i<=n/2

则称之为最小堆(min_heaps),  如果满足

      k[i]>=k[2i]  ,k[i]>=k[2i+1]     1<=i<=n/2

则称之为最大堆(min_heaps)。

================

下面左边的图表示最大堆,右边表示堆在数组中的存取情况

下面以最大堆为例,说明堆的操作。

一:堆的上移动操作

如果修改堆中某个元素,使得它的值大于父节点的,这就破坏了最大堆的性质,因此需要对堆实现上移操作。

//对下标为i的数进行上移动操作,flag标记修改后的值是否大于父节点
void sift_up(int *H,int i)
{
    bool flag=true;
    while(flag &&i!=1)
    {
        if(H[i]>H[i/2])
            swap(H[i],H[i/2]);
        else
            flag=false;
        i=i/2;
    }
}
二:堆的下移操作

如果修改堆中某个元素,使得它的值小于孩子节点,这就破坏了最大堆的性质,因此需要对堆实现下移操作。

//形参m为堆元素个数
 
void sift_down(int *H,int m,int i)
{
    bool flag=true;
    while(flag && (i=2*i)<=m)
    {
        if(i+1<=m && H[i+1]>H[i])  //选取需要下移的节点的左右孩子节点中较大的那个元素
            i++;
        if(H[i]>H[i/2])  //此时的i/2即为我们需要下移的元素,如果它比它的左右孩子节点中较大的那个要小,那么两者互换
            swap(H[i],H[i/2]);
        else  flag=false;
    }
}

三:堆的删除操作
如果我们要删除下标为 i 的元素,那么我们可以用堆中最后1个元素替代i,然后对这个替代后的元素执行上移或者下移操作

//删除堆中下表为i的元素,最后元素个数由m带回
void heap_delete(int *H,int i ,int &m)
{
    if(i>m)
        cout<<"overflow"<<endl;
    else
    {
        int a,b;
        a=H[i];
        b=H[m];
        H[i]=b;
        m--;
        if(a>b)
        {
            sift_down(H,m,i);
        }
        else
        {
            sift_up(H,i);
        }
 
    }
}
四:堆的插入操作
插入到堆最后1个元素后面,然后对该元素执行上移操作

//形参m为堆元素的个数,num为插入的数
void Insert(int *H,int &m,int num)
{
    m++;
    H[m]=num;
    sift_up(H,m);
}
五:堆的建立
把要建立成堆的元素依次调用上面的插入函数,一个一个插入,就成了堆

// A为需要建立堆的数组,H为所建立的堆,g为A中的数组元素个数,m为堆的元素,最后该参数返回堆的元素个数
//堆是从H[1]开始存储元素
void make_heap(int *A,int *H,int g,int &m)
{
    m=0;
    for(int i=0;i<g;i++)
    {
        Insert(H,m,A[i]);
    }
}

六:堆的排序
假设堆有n个元素,由于堆的第一个元素一定是最大的元素,因此可以让第一个元素和第n个元素互换,然后对第一个元素执行下操作。接着,对n-1个元素执行相同的操作,让第一个元素与第n-1个元素互换,然后对第一个元素执行下移操作,依次类推,最后的堆就是从小到大排序好的堆。

//堆排序,m为堆的元素个数
void heap_sort(int *H,int m)
{
    int i;
    for(i=m;i>0;i--)
    {
        swap(H[i],H[1]);
        sift_down(H,i-1,1); //注意第2个参数为i-1,不是m,是对接下来的i-1个堆元素进行操作
    }
}

完整的代码如下:

#include<iostream>
using namespace std;
 
void swap(int &a,int &b)
{
    int c;
    c=a;
    a=b;
    b=c;
}
 
//对下标为i的数进行上移动操作
void sift_up(int *H,int i)
{
    bool flag=true;
    while(flag &&i!=1)
    {
        if(H[i]>H[i/2])
            swap(H[i],H[i/2]);
        else
            flag=false;
        i=i/2;
    }
}
 
//形参m为堆元素个数
 
void sift_down(int *H,int m,int i)
{
    bool flag=true;
    while(flag && (i=2*i)<=m)
    {
        if(i+1<=m && H[i+1]>H[i])  //选取需要下移的节点的左右孩子节点中较大的那个元素
            i++;
        if(H[i]>H[i/2])  //此时的i/2即为我们需要下移的元素,如果它比它的左右孩子节点中较大的那个要小,那么两者互换
            swap(H[i],H[i/2]);
        else  flag=false;
    }
}
 
 
//形参m为堆元素的个数,num为插入的数
void Insert(int *H,int &m,int num)
{
    m++;
    H[m]=num;
    sift_up(H,m);
}
 
// A为需要建立堆的数组,H为所建立的堆,g为A中的数组元素个数,m为堆的元素,最后该参数返回堆的元素个数
//堆是从H[1]开始存储元素
void make_heap(int *A,int *H,int g,int &m)
{
    m=0;
    for(int i=0;i<g;i++)
    {
        Insert(H,m,A[i]);
    }
}
 
//删除堆中下表为i的元素,最后元素个数由m带回
void heap_delete(int *H,int i ,int &m)
{
    if(i>m)
        cout<<"overflow"<<endl;
    else
    {
        int a,b;
        a=H[i];
        b=H[m];
        H[i]=b;
        m--;
        if(a>b)
        {
            sift_down(H,m,i);
        }
        else
        {
            sift_up(H,i);
        }
 
    }
}
 
//堆排序,m为堆的元素个数
void heap_sort(int *H,int m)
{
    int i;
    for(i=m;i>0;i--)
    {
        swap(H[i],H[1]);
        sift_down(H,i-1,1); //注意第2个参数为i-1,不是m,是对接下来的i-1个堆元素进行操作
    }
}
 
 
void main()
{
    int A[5]={34,11,242,22,4};
    int H[6]; 
    int m,i;
    make_heap(A,H,5,m);
    for(i=1;i<=m;i++)
    {
        cout<<H[i]<<"  ";
    }
    cout<<endl;
    cout<<"上移操作:"<<endl;
    H[5]=999;
    sift_up(H,5);
        for(i=1;i<=m;i++)
    {
        cout<<H[i]<<"  ";
    }
    cout<<endl;
    cout<<"下移操作:"<<endl;
    H[1]=1;
    sift_down(H,m,1);
        for(i=1;i<=m;i++)
    {
        cout<<H[i]<<"  ";
    }
    cout<<endl;
    cout<<"元素删除操作,删除堆顶元素"<<endl;
    heap_delete(H,1,m);
        for(i=1;i<=m;i++)
    {
        cout<<H[i]<<"  ";
    }
    cout<<endl;
    cout<<"堆排序:"<<endl;
 
 
    heap_sort(H,m);
        for(i=1;i<=m;i++)
    {
        cout<<H[i]<<"  ";
    }
    cout<<endl;
    system("pause");
}

时间复杂度为O(nlogn)
————————————————
版权声明:本文为CSDN博主「李总LKC」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u014309268/article/details/39688805

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值