算法导论--堆排序

堆排序涉及到一个数据结构就是“堆”,所以我们先从“堆”开始讲起。

一、堆

堆的存储方式其实就是一个数组,而堆的逻辑结构是一个完全二叉树(什么是完全二叉树请自行百度)。

这里写图片描述

如图(a)是一个完全二叉树,树的父节点都比孩子节点要大,这个就是“大根堆”,如果树的父节点都比孩子节点小,那么就是一个“小根堆”。而图(b)则表示了一个图(a)是如何存储的。

这样就很容易计算每个节点的父节点,左孩子节点,右孩子节点。
例如索引是i的节点:
父节点: i/2
左孩子:i*2
右孩子: i*2+1

大根堆化

为了保持大根堆的性质,我们称这个程序的名称为MAX-HEAPFY。其实就是假设一个节点的左孩子子树,和右孩子子树都满足了大根堆的性质,但是这个节点可能比它的孩子要小,所以需要进行节点位置的调整,这个过程称为“大根堆化”。伪代码如下:
这里写图片描述
这里写图片描述

来来来算一下时间复杂度:从这个过程来看,最坏的情况下:是根节点的元素移动到叶子节点。所以也就是执行了lgn次,也就是说,最坏情况下的时间复杂度是log2(n)。

生成大根堆

接下来的问题就是用“大根堆化”这个方法从一个无序的数组生成一个“大根堆”。容易知道,数组A[n/2+1]以及之后的元素都是叶子节点。所以我们可以用自底向上的方法生成一个大根堆。伪代码如下:
这里写图片描述
这个伪代码的讲解书上讲的比较繁琐,这里简单讲一下,其实就是自底向上的不断的生成子大根堆,然后最后到根节点。直接上图说话:
这里写图片描述
时间复杂度也可以简单说一下,每一次的大根堆化的上界是O(log2(n)),然后总共执行了n/2次所以整个的执行时间是O(nlog2(n))

堆排序

伪代码如下:
这里写图片描述
先生成一个大根堆,然后将第一个元素与最后一个元素交换位置,这样最大值就放在最后了,再执行一次“大根堆化”然后递归执行上述过程就行了。

堆排序是一个非常棒的算法,但是在实践过程中,经常被快速排序在性能上被快速排序击败。但是堆排序有其他更好性质就是可以作为优先级队列来使用。这里只简单说一下:
返回最大元素:直接返回第一个元素A[1]
返回最大元素并移除:拿到第一个元素的引用, 然后将A[1]和最后一个元素互换位置,执行大根堆化, length = length -1
插入元素:将元素插入到尾部,然后将元素跟自己父节点比较,如果大于父节点则互换位置,递归执行
增加元素的key:将元素跟自己父节点比较,如果大于父节点则互换位置,递归执行。
具体参加《算法导论》6.3节

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章