堆的含义
堆是具有下列性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆。或者每个结点的值都小于或等于其左右孩子节点的值,称为小顶堆。
构建大顶堆基本思想
将待排序的序列构造成一个大顶堆。此时,整个序列的最大值就是堆顶的根节点。将它移走(其实就是与其堆数组的末尾元素进行交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造为一个堆,这样就会得到n个元素中的次大值。反复执行,得到有序序列。
实例图
阿里笔试的一题,给定一个数组7 6 3 5 4 1 2,请问3的交换次数是几次?要是熟悉堆排序的思想的话,这一题就轻而易举了。画个交换图来数一数吧。答案是2次。
堆排序实现
堆排序,就是利用堆进行排序的方法。它不是说在排序的过程中真建一棵树,而是利用节点在树中的位置,比如这里我要进行排序的是数组,而是将数组的下标与节点的位置想对应,通过树来完成堆排序。
// 为了与树中节点的位置一一对应,将数值存储的时候可以从下标1的位置开始
void HeapSort(int[] array)
{
int length = array.length;
int start = length / 2;// 堆排序的过程中,每次都是对有叶子节点的父节点进行排序
for (int i = start; i > 0; i--)
{
HeapAdjust(array, i, length);//进行节点间位置的调整
}
//构建大顶堆后,将根节点与最后一个节点进行互换。
for(int j=length;j>1;j--)
{
int tmp=array[j];
array[j]=array[1];
array[1]=tmp;
HeapAdjust(array, 1, j-1);//将1到j-1重新调整为大顶堆
}
}
void HeapAdjust(int[] array, int i, int length)
{
// TODO Auto-generated method stub
int temp=array[i];
for (int j = 2*i; j <=length; j*=2)//i节点作为父节点时,它的孩子节点是2*i
{
if(j<length&&array[j]<array[j++])j++;//如果右孩子节点大于左孩子节点,j++
//如果父节点的值大于右节点的值,则不用调换,给循环结束
if(temp>=array[j])break;
//子节点比父节点的值要大,进行调换,这里使用的是将子节点的值赋给父节点(父节点的值已经放在temp中)
array[i]=array[j];
i=j;//如果i值不是叶子节点的位置,它需要继续比较,直至叶子节点
}
array[i]=temp;
}