算法学习之排序算法:堆排序

要了解堆排序,首先要了解堆的概念,因为本文主要研究堆排序的算法,此处对数据结构堆只是给出概念:n个元素的序列{k1,k2,...kn},当且仅当满足如下关系时,称之为堆。

k[i] <= k[2i]且k[i] <= k[2i+1] (或
k[i] >= k[2i]且k[i] >= k[2i+1])

比如:序列96、83、27、38、11、09(或12、36、24、85、47、30、53、91)都是堆。

如果将堆对应的一维数组看成是一个二叉树,则堆的含义表明:完全二叉树中所有非终端结点的值均不大于(或不小于)其左、右孩子结点的值。将上面的一维数组形式的堆改写成二叉树形式的堆如下:

96                                                                   12

/       \                                                              /       \

83        27                                                       36        24

/     \     /                                                          /     \      /    \

38   11  9                                                       85    47   30   53

/

91

由上面给出的一维数组的堆和二叉树堆例子可以看出,若序列{k1,k2,...kn}是堆,则堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值)。

堆排序的过程:若在输出堆顶的最小值之后,使得剩余n-1个元素的序列重又简称一个堆,则得到n个元素中的次小值。依次反复执行,使能得到一个有序序列。

实现堆排序需要解决两个问题:

1、由一个无序序列建成一个堆。

2、在输出堆顶元素之后,调整剩余元素成为一个新的堆。

下面以序列{49、38、65、97、76、13、27、49}为例,分析如何进行建初始堆以及输出堆顶元素后如何调整建新堆。

从一个无序序列建堆的过程就是一个反复“筛选”的过程。若将此序列看成是一个完全二叉树,则最后一个非终端结点是第[n/2]个元素,由此“筛选”只需从第[n/2]个元素开始。以构造“最小值堆”为例:

49

/        \                                        图a:因为n/2向下取整是4,第4个元素的值是97,

38         65                                    在最小值堆中非终端结点的值应该小于它

/      \      /    \                                    的左右孩子的值,此处97>49,因此将97与49交换。

97     76  13    27                                 得到图b。

/

49

(a)

49

/        \                                        图b:按照顺序筛选第3个元素65,

38        
65                                              因为65>13,所以将65与13交换,得到图c。

/      \      /
   \

49     76  13    27

/

97

(b)

49

/        \                                        图c:按照顺序筛选第2个元素38,

38
        13                                              因为38不大于其左右孩子,则筛选序列不变,得到图d。

/      \      /    \

49     76  65    27

/

97

(c)

49

/        \                                        图d:按照顺序筛选第1个元素49,

38        
13                                              因为49>13,所以交换之,

/      \      /    \                                             又因为交换后的元素49仍然大于27,

49     76  65    27                                         继续与27进行交换,得到图e,即为构造的堆。

/

97

(d)

13

/        \                                        图e:构造的堆。

38         27

/      \      /    \

49     76  65    49

/

97

(e)

构造出新堆之后,就可以选取堆顶的元素作为最小值,然后重新调整输出堆顶元素之后的剩余元素成为一个新的堆。从而取出次小值。仍然以上面构造出的堆为例:

13

/        \                                        图a:取出构造的堆顶元素13作为排序后

38         27                                             有序序列的第一个元素:{13}。

/      \      /    \                                            输出堆顶元素13之后,以堆中最后一个元素97替代之。

49     76  65    49                                        得到图b。

/

97

(a)

97

/        \                                        图b:将97置于根结点之后,它的左右子树(图中的绿色与红色标记)

38         27                                             仍然为堆。仅需要自上之下调整,使整个数为堆即可。首先以堆

/      \      /    \                                            顶元素和其左右子树根结点的值比较,由于右子树根结点的值

49     76  65    49                             
          小于左子树根结点的值且小于根结点的值,则将27和97交换之。

得到图c。

13

(b)

27

/        \                                        图c:由于97替代了27之后破坏了右子树的“堆”,则需要进行和上述

38         97                                             相同的调整,直至叶子结点,得到图d。

/      \      /    \

49     76  65    49

13

(c)

27

/        \                                        图d:此时的二叉树是一个堆,堆顶为n-1个元素中的最小值。取出

38         49                                             该n-1个元素中的最小值(n个元素中的次小值)。

/      \      /    \                                            重复前面的步骤,依次得到最小的值。从而完成堆排序。

49     76  65    97

13   27

(d)

注意:堆排序方法对记录数较少的文件并不值得提倡,但对n较大的文件还是很有效的。堆排序在最坏的情况下,其              时间复杂度为O(nlogn)。相对于快速排序来说,这是堆排序的最大优点。另外,堆排序仅需一个记录大小供交            换用的辅助存储空间。

时间: 2024-10-04 16:09:32

算法学习之排序算法:堆排序的相关文章

算法学习之排序算法:插入排序(直接插入排序、折半插入排序、2-路插入排序)

引言: 插入排序作为最简单易于理解的排序算法,基本实现比较简单.本文详细介绍直接插入排序,并给出实现,简单的介绍折半插入排序,并给出2-路插入排序和表插入排序两种插入排序,但并未给出具体实现. 一.直接插入排序 直接插入排序的基本操作是将一个记录插入到已排好序的有序表中,从而得到一个新的.记录数增1的有序表. 算法描述: 步骤1.将待排序的一组记录中的第1个记录拿出来作为一组有序的记录(当然此时该组记录仅有1个记录). 步骤2.依次将待排序的一组记录中的记录拿出来插入到前面已排好序的记录中. 步

算法学习之排序算法(五)(高速排序)

1.算法思想 设要排序的数组是A[0]--A[N-1],首先随意选取一个数据(通常选用数组的第一个数)作为重要数据,然后将全部比它小的数都放到它前面.全部比它大的数都放到它后面.这个过程称为一趟高速排序.值得注意的是,高速排序不是一种稳定的排序算法.也就是说,多个同样的值的相对位置或许会在算法结束时产生变动. 一趟高速排序的算法是: 1)设置两个变量i.j.排序開始的时候:i=0.j=N-1. 2)以第一个数组元素作为重要数据,赋值给key.即key=A[0]. 3)从j開始向前搜索,即由后開始

[算法学习笔记]排序算法——堆排序

堆排序 堆排序(heapsort)也是一种相对高效的排序方法,堆排序的时间复杂度为O(n lgn),同时堆排序使用了一种名为堆的数据结构进行管理. 二叉堆 二叉堆是一种特殊的堆,二叉堆是完全二叉树或者是近似完全二叉树.二叉堆满足堆特性:父节点的键值总是保持固定的序关系于任何一个子节点的键值,且每个节点的左子树和右子树都是一个二叉堆. 如上图显示,(a)是一个二叉堆(最大堆), (b)是这个二叉堆在数组中的存储形式. 通过给个一个节点的下标i, 很容易计算出其父节点,左右子节点的的下标,为了方便,

算法学习之排序算法:归并排序

"归并"的含义是将两个或两个以上的有序表组合成一个新的有序表.无论是顺序存储还是链表存储结构,都可在O(m+n)的时间量级上实现. 归并排序又是一类不同的排序方法.假设初始序列含有n个记录,则可看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到n/2个为2或1的有序子序列:再两两归并,....... ,如此重复,直至得到一个长度为n的有序序列为止. 初始关键字:[49]   [38]   [65]   [97]   [76]   [13]   [27] A       A

算法学习之排序算法(三)(选择排序法)

1.引言 选择排序工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完. 选择排序是不稳定的排序方法.选择排序是和冒泡排序差不多的一种排序.和冒泡排序交换相连数据不一样的是,选择排序只有在确定了最小的数据之后,才会发生交换.怎么交换呢?我们可以以下面一组数据作为测试: 2, 1, 5, 4, 9 第一次排序:1, 2, 5, 4, 9 第二次排序: 1, 2, 5, 4, 9 第三次排序: 1, 2, 4, 5, 9 第四次排序:

算法学习之排序算法:选择排序

选择排序:每一趟在n-i+1(i=1,2,...,n-1)个记录中选取关键字最小的记录作为有序序列中第i个记录. 一.简单选择排序 一趟选择排序操作: 通过n-i次关键字间的比较,从n-i+1个记录中选出关键字最小的记录,并和第i(1<=i<=n)个记录交换之. 对L[1...n]中记录进行简单选择排序的算法为:令i从1至n-1,进行n-1趟选择操作.简单选择排序过程中,所需进行记录移动的操作次数较少,然而,无论记录的初始排列如何,所需关键字间的比较次数相同.因此,总的时间复杂度为O(n^2)

算法学习之排序算法:快速排序

快速排序:快速排序是对冒泡排序的一种改进.它的基本思想是,通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序. 一趟快速排序的具体做法: 1.附设两个指针low和high,它们的初值分别为low和high,设枢轴记录的关键字为pivotkey. 2.首先从high所指位置起向前搜索找到第一个关键字小于pivotkey的记录和枢轴记录互相交换. 3.从low所指位置起向后搜索,找到第一个关键字大于piv

算法学习之排序算法(四)(希尔排序)

1.算法思想 先将整个待排元素序列分割成若干个子序列(由相隔某个"增量"的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序.因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上比前两种方法有较大提高. 希尔(Shell)排序又称为缩小增量排序,它是一种插入排序.它是直接插入排序算法的一种威力加强版. 希尔排序的基本思想是 把记录按步长 gap 分组,对每组

算法学习之排序算法:希尔排序

希尔排序又称"缩小增量排序",它的基本思想是:先将整个待排记录序列分割成若干子序列分别进行直接插入排序,待整个序列中的记录"基本有序"时,再对记录进行一次直接插入排序. 希尔排序的一个特点是:子序列的构成不是简单地"逐段分割",而是将相隔某个"增量"的记录组成一个子序列.这就使得希尔排序中关键字较小的记录不是一步一步地往前挪动,而是一次按照"增量"的大小跳跃式地往前移,从而使得在进行最后一趟增量为1的插入排