第二部分--排序和顺序统计学-第6章--堆

说明:该系列博客整理自《算法导论(原书第二版)》,但更偏重于实用,所以晦涩偏理论的内容未整理,请见谅。另外本人能力有限,如有问题,恳请指正!

    堆排序是一种原地排序法,即在任何时候,数组中只有常数个元素存储在输入数组以外。由于该算法具有相当快的运行速度,且原地排序,所以结合了合并排序和插入排序的优点。

1、堆

    (二叉)  数据结构是一种数组对象(如下图所示),它可以被视为一棵完全二叉树。树中每个结点与数组中存放该结点值的那个元素对应。树的每一层都是填满的,最后一层可能除外(最后一层从节点的左子树开始填)。

    堆一般都用数组来表示,表示堆的数组 A 是一个具有两个属性的对象: A.length 是数组中元素的个数, A.heap-size 是存放在 A 中的堆元素个数。虽然A[1...A.length]都可以包含有效值,但A[A.heap-size]之后的元素都不属于相应的堆,所以有 A.heap-size <= A.length 。树的根为 A [ 1 ],给定了某个结点的下标 i ,其父结点 PARENT(i) ,左儿子 LEFT(i) 和右儿子 RIGHT(i) 的下标可以简单的计算出来,公式如下(需要注意的是,在一个好的堆排序的实现中,这三个过程通常是用宏或者内联函数实现):

                PARENT(i) = FLOOR(i / 2)

                LEFT(i) = 2i

                RIGHT(i) = 2i + 1

                最后一个非叶子节点下标为length[A]/2后向下取整

以上公式成立的前提是i从1开始到n。如果i从0开始到n-1,则公式如下:

                PARENT(i) = FLOOR((i-1) / 2)

                LEFT(i) = 2i + 1

                RIGHT(i) = 2i + 2


    二叉堆有两种: 最大堆 和 最小堆 (小根堆)。这两种堆都要满足各自的堆特性。在最大堆中,最大堆特性是指除了根以外的每个结点 i ,有 A [ PARENT(i) ] >= A [ i ],即某个结点的值至多和其父结点一样大,这样,堆中的最大元素就存放在根结点中。最小堆的组织方式刚好相反,最小堆特性是指除了根以外的每个结点 i ,有 A [ PARENT(i) ] <= A [ i ],最小堆的最小元素是在根部。

    算法中使用何种堆在堆排序算法中,我们使用的是最大堆。最小堆通常在构造优先队列时使用,具体将在书中6.5节,优先级队列中讲解。对于某个特定的应用,我们将确切的指明需要的是最大堆还是最小堆;当某一性质既适合最大堆,也适合最小堆时,我们就只使用堆这个词。

    堆可以被看成是一棵树,结点在堆中的高度定义为从本结点到叶子的最长简单下降路径上边的数目;定义堆的高度为树根的高度。因为具有n元素的堆是基于一颗完全二叉树的,所以其高度为 Θ (lg n )。堆结构上的一些基本操作的运行时间至多与树的高度成正比,为 O (lg n )。下面将介绍几个基本过程,并说明它们在排序算法和优先级队列数据结构中如何使用:

        1)、MAX-HEAPOFY 过程,运行时间为 O (lg n ),是保持最大堆性质的关键

        2)、BUILD-MAX-HEAP 过程,以线性时间运行,可以在无序的输入数组上构造出最大堆

        3)、HEAP-SORT 过程,运行时间为 O ( n lg n ),对一个数组进行原地排序

        4)、MAX-HEAP-INSERT , HEAP-EXTRACT-MAX , HEAP-INCREASE-KEY , HEAP-MAXIMUM 过程的运行时间为 O (lg n ),可以让堆结构作为优先级队列使用。

2、保持堆的性质,即MAX-HEAPOFY 过程==>是建堆的基本过程

    MAX-HEAPIFY 过程的输入为一个数组 A 和下标 i 。当 MAX-HEAPIFY 被调用时,我们假定以 LEFT(i) 和 RIGHT(i) 为根的两棵二叉树都是最大堆,但这时 A [ i ]可能小于其子女,这样就违反了最大堆特性。 MAX-HEAPIFY 让 A [ i ]在最大堆中“下降”,使以 i 为根的子树成为最大堆

MAX-HEAPIFY(A, i)

      l = LEFT(i)

      r = RIGHT(i)

      if l <= A.heap-size and A[l] > A[i]

          largest = l

      else

          largest = i

      if r <= A.heap-size and A[r] > A[largest]

          largest = r

      if largest != i

          exchange A[i] with A[largest]

          MAX-HEAPIFY(A, largest)

    下图描述了 MAX-HEAPIFY 的过程。在算法的每一步里,从元素 A [ i ], A [ LEFT(i) ]和 A [ RIGHT(i) ]中找出最大的,并将其下标保存在 largest 中。如果 A [ i ]是最大的,则以 i 为根的子树已是最大堆,程序结束。否则,交换 A [ i ]和 A [ largest ],从而使 i 及其子女满足堆性质。下标为 largest 的结点在交换后的值为 A [ i ],以该结点为根的子树可能又违反了最大堆性质。因而要对该子树递归调用 MAX-HEAPIFY 。

当 MAX-HEAPIFY 作用在一棵以结点 i 为根的,大小为 n 的子树上时,其运行时间为调整元素 A [ i ], A [ LEFT(i) ]和 A [ RIGHT(i) ]的关系时所用的时间 Θ (1),加上对以 i 为结点的某个子结点为根的子树递归调用 MAX-HEAPIFY 所需的时间。 i 结点的子树大小至多为2 n / 3(最坏情况发生在最底层恰好半满的时候),那么 MAX-HEAPIFY 的运行时间可表示为: T ( n ) <= T (2 n / 3) + Θ (1)。该递归式的解为 T ( n ) = O (lg n )。或者说, MAX-HEAPIFY 作用于一个高度为 h 的结点所需的运行时间为 O ( h ),因为数的高度为lg n

2、建堆,即BUILD-MAX-HEAP 过程

    现在可以自底向上地用 MAX-HEAPIFY 来将一个数组 A [ 1 .. n ](此处 n = A.length )变成一个最大堆。因子数组 A [ FLOOR(n / 2) + 1 .. n ]中的元素都是树中的叶子结点,它们都可以看做是只含一个元素的堆,不用再通过MAX-HEAP过程降序来保证堆的性质,所以建堆的循环过程为 FLOOR(A.length / 2)--->1。过程 BUILD-MAX-HEAP 对树中的每一个非叶子结点都调用了一次 MAX-HEAPIFY来建堆 。总结来说建堆的过程就是i从到FLOOR(A.length / 2)到1逐步保持堆特性的过程,即从叶子节点的父节点一级逐级向上保持堆性质的过程

BUILD-MAX-HEAP(A)

    A.heap-size = A.length

    for i = FLOOR(A.length / 2) downto 1

        MAX-HEAPIFY(A, i)

下图给出了 BUILD-MAX-HEAP 过程的一个例子。

    我们可以计算出 BUILD-MAX-HEAP 运行时间的一个简单上界:每次调用 MAX-HEAPIFY 的时间为 O (lg n ),共有 O ( n )次调用,故运行时间是 O ( n lg n )。尽管这个界是对的,但从渐近意义上来说不够紧确。

    实际上,我们可以得到一个更加紧确的界。因为,在树中不同高度的结点处运行 MAX-HEAPIFY 的时间不同,而大部分结点的高度都比较小。关于更紧确界的分析依赖于这样的性质:一个 n 元素堆的高度为FLOOR(lg n ),并且,在任意高度 h 上,至多有CEIL( n / 2( h + 1))个结点。

    MAX-HEAPIFY 作用在高度为 h 的结点上的时间为 O ( h ),可以将 BUILD-MAX-HEAP 的代价表示为上确界:

    最终可以得出 BUILD-MAX-HEAP 过程运行时间的界为

    这说明可以在线性时间内,将一个无序数组建成一个最大堆。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,490评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,581评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,830评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,957评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,974评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,754评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,464评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,847评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,995评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,137评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,819评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,482评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,023评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,149评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,409评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,086评论 2 355

推荐阅读更多精彩内容