您的位置:首页 > 其它

【重新上本科】堆排序【下】

2012-08-21 15:51 155 查看
堆调整函数解决的问题是:当除了堆顶以外的元素都满足堆的条件,如何调整堆顶元素,使整个序列满足堆的条件。堆的条件,是啥?其实堆是棵二叉树,满足父节点的数值比两个儿子节点的数值大。那么如何解决上述问题呢?思路也很简单:将父节点与两个儿子节点比较,找到最大的那个,放到堆顶,将原来堆顶元素放到最大元素的原来位置,然后对这颗子树递归调用堆调整函数。

更一般地说,对于堆中第i个节点,如何调整堆中的元素,满足堆的条件?代码如下:

void MaxHeapfy (int Array[], int i, int iHeapSize) // MaxHeapfy表示维护一个最大堆



int l = 2 * i + 1; // 定位到i的左儿子,为啥这样定位?请翻书看下堆的数组存储

int r = 2 * i + 2; // 定位到i的右儿子

int iMax;

// 这段代码有意思,有看头,其功能是比较元素i和他的两个儿子,找到其中最大的那个,将他的位置记录到iMax中。

// 为啥左儿子的判断既有if又有else,右儿子不用?每个判断都有两个条件,前面是递归是否终止,后面是比较大小。何时、哪个条件不满足,会跳出if条件?这个地方想着简单,不过写的时候,debug了一会儿,才把代码写对。个中细节,还是debug的时候体会吧。

if (l < iHeapSize && Array[l] > Array[i])

iMax = l;

else

iMax = i;

if (r < iHeapSize && Array[r] > Array[iMax])

iMax = r;

if (iMax != i) // 如果堆顶已经是最大元素,则不用调整了,否则,交换堆顶与iMax位置的元素



int iTemp; // 交换元素

iTemp = Array[i];

Array[i] = Array[iMax];

Array[iMax] = iTemp;

MaxHeapfy (iMax, iHeapSize); // 递归,对子树重新建立堆





思路和代码都很简单,需要细想一想的地方就是上面“有看头”的那部分代码。难点主要在于,将选取三个数的最大者与递归终止条件混在一起判断了。

利用上面的调整函数,建立堆就很容易了。堆是用数组存储的,越往后,越是底层节点;接上文,父节点和儿子节点的关系可以用l = 2 * i + 1和l = 2 * i + 2;计算。树是从底向上建立的,倒数第二层节点的位置在数组的中部,就从这里开始。代码如下:

void BuildMaxHeap (int Array[], int iHeapSize)

{

if (iHeapSize <= 1) // 防御性代码

return;

int i = iHeapSize / 2; // 定位到数组中间,这部分是叶子节点的上一层,在此基础上建立二叉树(叶子节点自身就是二叉树了)

for (int j=i; j>=0; j--) // 从后向前遍历

MaxHeapfy (j, iHeapSize); // 自底向上建立堆,直到堆顶(位于数组最前端)

}

好,完事。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: