堆排序详解

思想:堆排序是一种将a[1...n]看成一棵树,利用完全二叉树中双亲结点和孩子结点的关系,在当前无序区中选择关键字最大或者最小的元素。

  堆排序分为:

    大根堆:a[i]>=a[2*i]、a[i]>=[2*i+1]

    小根堆:a[i]<=a[2*i]、a[i]<=a[2*i+1]

  如下图:大根堆[20,17,8,1,16,3]、小根堆[3,7,8,17,16,28]

  

示例:53 17 78 9 45 65 87 32

  1、建立大根堆:

  ①从最下面的第一个根结点开始,如下图i=4,将其和它的最大的子节点交换,因为9只有一个左结点23,直接交换

  

  ②i=3,78的两个结点中87最大,将78和87交换

  

  ③i=2,17的两个结点中45最大,将45和17交换

  

   ④i=1,53的两个节点中,87大于35,交换87和53,此时i=3,继续比较,53的两个结点78最大,将78与53交换。

    

   最后得到大根堆为:

  

  2、得到排序数组

  ①将根和最后一个结点交换,再将1~7调整为大根堆

  

  ②将根和该堆的最后一个节点交换(注意这里87已经不属于堆),即交换78和53,再进行①操作,直到最后得到排序数组

代码实现(c++)

#include <bits/stdc++.h>
using namespace std;

void buildHeap(int *a,int n,int i)
{
    int temp;
    while(2*i<n)
    {
        //取左右结点中值最大的结点和父节点比较
        if(2*i+1<n&&2*i+2<n) temp=(a[2*i+1]>a[2*i+2])?(2*i+1):(2*i+2);
        else if(2*i+1<n) temp=2*i+1;
        else break;
        if(a[temp]>a[i])
        {
            swap(a[i],a[temp]);
            i=temp;//以该节点为父节点,建立大根堆
        }
        else break;
    }
//    for(int i=0;i<n;i++) cout<<a[i]<<' ';
//    cout<<endl;
}

int main()
{
    int n=8;
    int a[n]={53,17,78,9,45,65,87,32};
    while(n)
    {
        //创建大根堆
        for(int i=n/2-1;i>=0;i--)
        {
            buildHeap(a,n,i);
        }

        for(auto i:a) cout<<i<<' ';
        cout<<endl;
        //每次将根和最后的结点交换
        swap(a[0],a[n-1]);
        //将剩下的数字创建大根堆
        n--;
    }
    return 0;
}

输出为:

 

 

 

    

 

posted @ 2018-08-30 11:15  ybf&yyj  阅读(493)  评论(0编辑  收藏  举报