码迷,mamicode.com
首页 > 编程语言 > 详细

排序算法:堆排序

时间:2016-05-18 19:41:07      阅读:175      评论:0      收藏:0      [点我收藏+]

标签:

堆排序

1. 堆:
    1. 一种完全二叉树。
    2. 每个结点的值都大于或等于其左右子结点的值,大顶堆。
    3. 小顶堆同理。
2. 是简单选择排序的一种改进:把每次比较的结果用堆来保存起来。
3. 堆排序(大顶堆):
    1. 将待排序列构造成一个大顶堆。
    2. 将堆顶和待排序列最后一个元素交换,也就是保存起来。
    3. 将剩余的序列(去除最后一个元素)重新构造成一个堆。
    4. 重复23 。

4. 待排序列构造初始大顶堆:
    1. 设序列长度length,已经构造好最初的完全二叉树,无序。
    2. 从最下层最右边的非叶子结点开始向左向上。
    3. 二叉树的性质:根节点从序号1开始,设某个结点的序号为k,则其左子树的序号是2k,右子树的序号是2k+1。最下层最右边的非叶子结点就是length/2取整。
    4. 从第【length/2取整】个结点开始,向根节点(序号为1)开始 逐个调整每个子树的三个结点的顺序,让其成为大顶堆。
    5. 交换之后可能造成被交换的孩子节点不满足堆的性质,因此每次交换之后要重新对被交换的孩子节点进行调整
    6. 最后调整到根节点时候,整个树就是一个大顶堆。

复杂度

1. 构建堆:O(n)
2. 重建堆:O(nlogn),调整的是根节点的左子树或者右子树,而调整的次数也就是该二叉树目前的深度,也就是【log2n】+1,每次都要调整,一共调整n-1次,所以复杂度就是O(nlogn)。
3. 总复杂度:O(nlogn)
4. 对原始记录的排序状态不敏感,反正都要构造初始堆。
5. 不稳定。
6. 构建堆需要多次比较,待排序列个数较少的情况不适合。

图示

代码实现

//构建大顶堆的调整算法
void sift(int r[],int k,int m)
{
    int i = k;
    int j = 2*k;
    while (j<=m)
    {
        if (j<m && r[j]<r[j+1])
        {
            //j指向较大的孩子结点
            j = j + 1;
        }
        if (r[i]<=r[j])
        {
            int temp = r[i];
            r[i] = r[j];
            r[j] = temp;
            //根节点的调整会影响孩子结点,所以一直调整到m
            i = j;
        j = 2*i;
        }
        else
        {
            break;
        }

    }
}
//堆排序
void HeapSort(int r[ ], int n)
{
    int i;
    for (i=n/2; i>=1; i--)       //初始建堆,从最后一个非终端结点至根结点
    {
    sift(r, i, n) ;     
    }
    for (i=1; i<n; i++)        //重复执行移走堆顶及重建堆的操作
    {
        int temp = r[1];
        r[1] = r[n-i+1];
        r[n-i+1] = temp;
        sift(r, 1, n-i);
    }
}

用例:

int a[] = {0,36,30,18,40,32,45,22,50};
    int i ;
    for (i = 1;i<9;i++)
    {
        cout<<a[i]<<" ";
    }
    cout<<endl;

    HeapSort(a,8);
    for (i = 1;i<9;i++)
    {
        cout<<a[i]<<" ";
    }

排序算法:堆排序

标签:

原文地址:http://blog.csdn.net/songzige/article/details/51404455

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!