算法导论读后感-之堆,堆排序,堆排序的应用

来源:互联网 发布:数码宝贝网络侦探进化 编辑:程序博客网 时间:2024/06/09 23:18

算法中(二叉)堆的概念:(二叉)堆是一个数组,它巧妙的利用的数组的下标来维护了堆中数据的关系。
具体关系如下:

PARENT(i) = floor(i/2) LEFT(i) = i*2RIGHT(i) = i*2+1*(注:为了高效,实际编码中,通常用移位来代替乘除2)*

通过上述公式,很高效方便的得到堆中具有父子关系的节点的位置关系。
堆分为两种:
1. 最大堆 PARENT >= LEFT && PARENT >= RIGHT
2. 最小堆 PARENT <= LEFT && PARENT <= RIGHT

以下内容以最大堆为例进行讲解:

Key Point 1: 维护堆的性质:
堆中的元素要遵循堆的性质,维护某个元素堆的性质的算法如下:

MAX_HEAPIFY(A,i)     //表示在堆A中,维护下标为i的元素的堆的性质verify 2*i, 2*i+1, avoid array overflowmaxIdxIn3 = MAX(A[i],A[2*i],A[2*i+1])if (maxInxIn3 == i)    return;else    swap(A[i],A[maxIdxIn3])    MAX_HEAPIFY(A,maxIdxIn3)

显然,维护一个元素的堆的性质,算法复杂度为 O(lgn).

Key Point 2: 建堆:
对于堆,我们容易证明,所有有子节点的节点必然在数组的前半部分。即:index

BUILD_MAX_HEAP(A)for (i=arraySize/2, i>=0; i--)    MAXHEAPIFY(A,i)

因此,建立堆的算法复杂度为O(nlgn)

Key Point 3: 堆排序
假设我们已经建立好了一个堆,由于根节点总是最大值,所以我们每次取出根节点,排序算法也就完成了。该算法的关键是取出根节点后,将最后位置的节点交换到根节点,然后进行一次MAX_HEAPIFY.

HEAPSORT(A)GETROOTfor(i=length downto 1)    A[0] = A[length];    length--;    MAX_HEAPIFY(A,0)

可以看到,堆排序的算法复杂度为O(nlgn)

Key Point 4: 堆排序的应用 – 优先队列
堆排序算法虽然较为高效,但单纯的排序算法,表现稍差于快速排序。因此并不常用于平凡的排序。该数据结构与算法在计算机算法中,最常见应用于优先队列。比如消息优先级队列。
试想,服务器短接受消息,首先将消息放入消息队列中,等待时机进行处理。而消息因为业务不同,具有不同的优先级,则服务器在每收到一个消息时,将该消息插入到队列尾部,然后将其向上追溯,插入到合适位置即可。而服务器处理消息时,只需要取第一个元素,因为它总是优先级最高的。显然,入队列并排序和出队列的算法复杂度均为O(lgn)。该算法的高效在于不需要因为一次插入删除而对所有元素进行重新排列,因此,非常高效。

算法如下:
插入:
A[length+1] = newValue;
while (i>1)
if (A[parent]< newValue)
Swap(A[parent], newValue)
i = PARENT(i)

处理算法:
GETROOT
SWAP(A[0], A[length])
MAX_HEAPIFY(A,0)