这里先简单说下最大堆的基本性质:数组
了解以上基本性质以后,就能够先看一下如何对一个序列作最大堆的初始化。3d
思路:过程就像冒泡同样,从最序号最大的父节点开始,查看是否知足最大堆,若是不知足,则调整(调整以后,还要查看被调整的节点是否依然知足最大堆性质,若是不知足,则须要往下遍历调整,这部分在后面的举例中会有说明),若是知足,则继续查看前一个父节点是否知足,直接最终的0节点。code
例如:这里有个数组:x[] = {2 5 3 9 7 1 6},则对应树为:
blog
该序列长度为7,最大下标为6,则最大的父节点下标就是: (6 - 1)/ 2 是2(基本性质第三条),对应的数值是3,
他的左孩子是1,右孩子是6,右孩子比父节点大,因此应该调整一下这两个节点,获得:
排序
该节点调整完以后,再查看前一个父节点,下标为1,对应的数值为5,
他的左孩子是9,右孩子是7,不知足,因此父节点应该与左孩子进行交换,获得:
string
继续往前,再前面一个父节点下标为0,数值为2,左孩子是9,右孩子是6,不知足最大堆,父节点与左孩子交换,获得:
io
交换以前,左孩子为9,如今左孩子为2,致使这个左孩子不知足最大堆性质,由于这个左孩子的左孩子大于左孩子,因此,这里就出现了上面括号中所说的:调整完以后,还要查看被调整的节点是否依然知足最大堆的性质。
这里还要对调整以后的节点继续调整:
class
至此,一个最大堆就初始化完成了!二叉树
其实,明白了最大堆怎么构造出来的以后,堆排序就很容易了。
想想,最大堆构造出来以后,其实就直接获得了最大值:x[0],
若是把 x[0] 与最后一个数字交换一下,而后对剩下的数字从新按以前的方法构造一下,不就找到了第二大的数字了吗?
此时第二大的数字就是x[0],把它与刚刚参加排序的最后的一个数字交换一下,而后再对剩下的数字排序一下,就能够获得第三大的数字,
这么一直循环,就能够把当前数组排序完成了。
接着刚刚的那个例题,先把9与参与排序的最后一个数字对换,获得:
循环
此时参与排序的,就只有:3,7,6,5,2,1。
由于x[0]被调整了,因此要查看x[0]是否依然最大堆性质,显然是不知足的,因此继续调整x[0],获得:
x[0]与x[1]互换以后,致使被调整的x[1]又不知足最大堆,那就再调整一下:
如今整个树都知足最大堆了,也就获得了如今参与排序的最大值x[0]为7,
因此,x[0]与当前参与排序的最后一位交换,获得:
此时参与排序的,只有:1,5,6,3,2。
按照上面步骤再次循环,这里就不写了,直接放图:
上代码:
#include <stdio.h> #include <string.h> #include <stdlib.h> void swap(int *array, int i, int j) { int temp = array[i]; array[i] = array[j]; array[j] = temp; return; } // 对当前父节点进行排序 // 查看该父节点是否知足最大堆,若是不知足则调整子节点 void sort (int *array, int father, int len) { for (int lchild =father*2+1; lchild<len; lchild=father*2+1) { int k = lchild; // 先用k指向左孩子 int rchild = lchild + 1; if ((rchild < len) && (array[rchild] > array[lchild])) { k = rchild; // 若是有右孩子,且右孩子比左孩子还大,则更新k } // 这里的k,指向了左右孩子中较大的那个 if (array[k] > array[father]) { swap(array, k, father); // 交换父亲和孩子的数值 father = k; // 这里就是查看被调整以后的节点k,是否依然知足最大堆 } else { break; // 当前节点不须要被调整 } } return; } void print(int *array, int len) { for (int i=0; i<len; i++) { printf("%d ", array[i]); } printf("\n"); } int main(void) { int x[] = {2,5,3,9,7,1,6}; int len = sizeof(x)/sizeof(int); print(x, len); // 先输出原始序列 // 最大子节点下标为len-1,因此它的父节点是 (len-1-1) / 2 for (int i = (len - 2)/2; i>=0; i--) { sort(x, i, len); } print(x, len); // 输出初始化以后的最大堆 for (int i=(len-1); i>0; i--) { swap(x, 0, i); // 把最大的一个值放到末尾,而后对剩余的数组进行排序 sort(x, 0, i); } print(x, len); // 输出排序以后的序列 return 0; } 最终输出为: 2 5 3 9 7 1 6 9 7 6 5 2 1 3 1 2 3 5 6 7 9