堆排序

前言

本文主要介绍堆的构造, 元素在堆中的上浮操作以及下沉操作,最后讲述基于这些操作的堆排序, 不对优先队列作介绍。

一、堆是什么?

  • 印象中的堆
    印象中的堆是这样的
印象中的堆

其实数据结构中的堆也很相似,只是节点之间多了一些逻辑的关系。

  • 数据结构中的堆

数据结构中的堆节点和节点间多了一些必要的逻辑关系, 方便我们遍历。堆中有顶点,每一个节点(图片中的块)一般都有两个子节点,当然最下的节点可能没有子节点。可以从顶向下一次编号,采用1开始。

数据结构中的堆
  • 节点之间的序号关系
    不难看出节点中的序号关系如下图
节点关系

当然从0开始编号关系也类似。

二、堆节点swim上浮

swim操作可以对堆中的任何节点进行操作, 比如函数写位swim(int k) k是要swim操作的节点序号。

节点关系

逻辑

比如Swim(5) 即 T, 就是T和它的上层父节点P比较。如果T大,T就和P交换, 一直和上边父节点比较, 比过了就向上交换,比不过就停下来, 这很像武林中的登塔闯关, 和一个一个的高手比较如果能打过就能继续向上(比不过的下去),比不过就停下来。

节点关系

代码描述

swim(int k){
    while(k>1 && less(k/2, k))
    {
       exch(k/2,k);
       k = k/2;
    }
}

代码中k = k/2 就利用了节点序号之间的关系。

三、堆的sink下沉操作

下沉节点

逻辑

sink(5),就是该元素和下边的元素比较, 如果比下边的小就交换(如果比两个都小就和两个钟大的那一个交换),一直往下,找到两个都比他小的就停止。保证三个节点的有序, 子节点比父节点小的三角原则。

代码描述

void sink(int k){
    while(2*k <= N){
        int j = 2*k;
        if(j < N && less(j, j+1)) j++;
        if(!less(k, j)) break;
        exch(k, j);
        k = j;
    }
}

代码中k = k/2 就利用了节点序号之间的关系。

四、利用sink使堆有序化

思路:sink一次可以让子节点有序化(子节点小于父节点)同理,依次sink,就可以使整个堆有序,堆有序是堆排序的前提。


排序示例

按照分析只需要执行:

  • sink(5)
  • sink(4)
  • sink(3)
  • sink(2)
  • sink(1)

五、堆排序

经过上边的有序我们都已经知道什么是堆, 怎么让堆有序化,下面直接进入堆排序。

核心思想

1.取出最值
2.加入新的值

这种思想可以运用在优先队列上。

比如对数组 {40,70,20,60,50,10,10,30,80} 进行从小到大排序, 把最小值拿到最上边,最大值放后边。找出最大值,放数组后边, 对剩余数组构成的有序堆再尾节点和顶节点交换,下沉使其有序

思考:数组怎么转化为堆呢?一图就明白了。

  • 1数组转为无序堆


    数组转为无序堆结构
  • 2堆有序化依次

  • 3抽出值调整堆
    给出如下排序过程。


    1抽出最值->剩下的调整堆有序化
2抽出剩下的最值->剩下的调整堆有序化

3抽出剩下的最值->剩下的调整堆有序化

4重复使其全部有序

Code

    int a[9] = {40, 70, 20, 60, 50, 10, 10, 30, 80};
    int len = 9;
    for (int i = len/2 - 1; i>=0; i--) {
        sink(a, i, len);
    }
    //1.堆已经有序
    printOutcome(a, N);
    
    //2.重复交换顶底 再sink
    while (len > 1) {
        exchange(a, 0, --len);
        sink(a, 0, len);
    }

开始标号用1和0,有些许差异在代码上。但是1的话会给数组0位置留一个哨兵项。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 数据结构与算法--优先队列和堆排序 在某些数据处理的例子中,总数据量太大,无法排序(甚至无法全部装进内存)。例如,...
    sunhaiyu阅读 1,053评论 0 2
  • 二叉堆 堆有序定义:当一颗二叉树的每个节点都大于等于它的两个子节点时, 被称为堆有序。二叉堆定义: 二叉堆是一组能...
    leoLy阅读 2,081评论 0 2
  • 堆排序可以做什么 首先应该弄清楚堆排序可以解决什么问题,答案是显而易见的:排序。说得通俗点儿就是对一组无序的数字进...
    Springlord888阅读 30,430评论 11 52
  • 1. 优先队列 说堆排序之前,我们要从一种特殊的数据结构——优先队列说起。优先队列最大的两个特征:插入元素和删除最...
    Xerrard阅读 358评论 0 1
  • 更详细的讲解和代码调试演示过程,请点击链接 做过系统编程的人都知道,几乎任何系统都会提供一种时钟机制,也就是Set...
    望月从良阅读 833评论 0 1