排序之堆排序详解

堆排序思路:

   1、将数据存在数组的1~n的编号中

    2、根据元素的个数算出满二叉树的高度,记录为k

    3、从第k-1层的每个节点开始处理,将以每个节点为根节点的子树变成大顶堆

        (这里使用exchange()函数,该函数将在该节点、左右子女节点中找出值最大的节点,用flags记

         录其编号,将j节点的值交换为最大值,交换之后再进行堆调整,即为递归调用exchange()函数)

     4、对初始堆进行堆排序,将根节点的值换到末尾,每交换一次,剩余的元素进行堆调整,保证其为大顶堆

堆排序分析:

          堆排序方法对记录数较少的文件并不值得提倡,但对n较大的文件还是很有效的。因为其运行时间主要耗

费在建初始堆和调整建新堆时进行的反复“筛选”上。堆排序在最坏的情况下,其时间复杂度也为O(nlogn)。相对

于快速排序来说,这是堆排序的最大优点。此外,堆排序仅需一个记录大小的供交换用的辅助存储空间。

#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int a[100];
void sort1(int *a, int n);
int main()
{
    int n;
    while(cin >> n)
    {
        for(int i = 1; i <= n; i++)
           cin >> a[i];
        sort1(a, n);
        for(int i = 1; i <= n; i++)
           cout <<"  " << a[i];
        cout << endl;
    }
}


void exchange(int *a, int j, int num)
{//将树中以j为顶点的子树变成大顶堆 
    int flags = j;
    if(2 * j <= num && a[2 * j] > a[flags])
    {
        flags = 2 * j;
    }
    if(2 * j + 1 <= num && a[2 * j + 1] > a[flags])
    {
        flags = 2 * j + 1;
    }
    if(j != flags)
    {
        int temp = a[j];
        a[j] = a[flags];
        a[flags] = temp;
        exchange(a, flags, num);
    }
}

void sort1(int *a, int n)
{
    /*先将其变成大顶堆*/
    int k;
    for(int i =  0;  ; i++)
    {//将其转换成二叉树需要多少层 
        if(n >= pow(2, i) && n < pow(2, i + 1))
        {
            k = i + 1;
            break;
        }
    }
    for(int i = k - 1; i >= 1; i--)
    {//从底层开始,使得非叶子节点的值大于其左右子女节点 
        for(int j = pow(2, i - 1); j < pow(2, i); j++)
        {
            exchange(a, j, pow(2, k) - 1);
        }
    }
    int num = n;
    for(int i = 1; i < n; i++)
    {//进行堆排序 
        int temp = a[1];
        a[1] = a[n - i + 1];
        a[n - i + 1] = temp;
        num--;
        exchange(a, 1, num);
    }
}

 

 

     

posted @ 2018-02-14 19:59  hui666  阅读(540)  评论(0)    收藏  举报