堆排序
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆可以看成是一个完全二叉树的结构,并同时满足子结点的键值或索引总是小于(或者大于)其父节点。
1.堆
堆(Heap)是计算机中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵完全二叉树的数组对象。
堆总是满足下列性质:
①堆中某个节点的值总是不大于或不小于其父节点的值;
②堆总是一棵完全二叉树。
大堆:父节点的键值或索引总是大于其左右孩子的键值或索引的堆。
小堆:父节点的键值或索引总是小于其左右孩子的键值或索引的堆。如下图二叉树便是一个小堆:
2.索引"i"
2.1 这里我们可以回顾一下二叉树有关的性质:
性质1:在二叉树的第i层上至多有2i-1个节点(i>=1)。
性质2:深度为k的二叉树至多有2k-1个节点(k>=1)。
性质3:对任何一颗二叉树,如果其终端节点数为n0,度为2的 节点数为n2,则n0 = n2+1.
性质4:具有n个结点的完全二叉树深度为[log2(n+1) ]([x]表示不 大于 x的最大整数)。
性质5:如果对一颗有n个结点的完全二叉树(其深度为[log2(n+1) ]) 的结点按层序编号(从第1层到第[log2(n+1) ]层,每层从左到 右),对任意一个结点i(1<=i<=n)有:
1).如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则其双亲是结 点[i/2]
2).如果2i>n,则结点i无左孩子(结点i为叶子结点);否则其左孩 子是结点2i。
3).如果2i+1>n,则结点i无右孩子;否则其右孩子是结点2i+1。
2.2 堆排序中"i"
查找数组中某个数的父节点和左右孩子,假设已知数组索引为i的数,那么
1.父结点索引:(i-1)/2
2.左孩子索引:2i+1
3.右孩子索引:2i+2
这里左孩子索引是2i+1而不是2i的原因是数组中索引从0开始,右孩子索引同理需要加1。
3.堆排序步骤
①将待排序的数组构造成大堆,此时整个数组的最大值元素便放在了堆顶,即数组中对应下标为0的元素。
②将此时用来构造大堆的数组中的第一个元素与最后一个元素交换位置,即上一步找到的最大元素沉淀到用来构造大堆的数组的最后位置处。
③通过以上两步,找到了n个元素中最大的元素并将其放到了最后位置,接下来对剩余n-1个元素进行重复以上步骤,递归之后,直到n个元素排好顺序。
4.复杂度:
堆排序的时间复杂度为:O(nlogn)
堆排序是就地排序,空间复杂度为常数:O(1)
5.代码实现:
public class HeapSort {
//大堆(根节点大于子节点)和小堆(根节点小于子节点)
/**
* 测试函数
* @param args
*/
public static void main(String[] args) {
i