关于堆排序,有很多博客都讲得很细很细了。
堆排序是面试经常考查的点,因此我觉得需要把堆排序给啃下来。
然而,图解堆排序的博客很多,思路也是相对来说比较好理解的,但是大多数博客堆排序的代码实在是写得太复杂了,我一个菜鸡实在是很难理解。
于是乎花费了一整个下午的时间,把堆排序的代码给整理出来了,附上详尽的注释。相信看着这份代码,对照着图解,就算是新手也很快就能把堆排序掌握下来啦!
以下附上代码:(可能不是想象的那么优雅,但力求简单易懂好吧!)
package Aug;
import java.util.Arrays;
/**
* 堆排序
* 堆是一种跟完全二叉树很像的数据结构,分为大根堆和小根堆,性质(大根堆)为k[i]>=k[2i]、k[i]>=k[2i+1](1<=i<=2n-1)
* 堆定义包括下列三种操作:最大堆调整、创建最大堆和堆排序
* 堆通常是用数组来实现的 利用数组元素可以快速定位的性质
*
* 步骤:
* 1.先对当前数组建立一个最大堆
* 2.然后迭代前(n-1)个数,继续奖励最大堆,直到剩下长度为1
* ·只需要对非叶子节点做最大堆构建
* ·需要检验左右子节点是否存在
* ·当根节点发生变更时,需要再次对其根节点做最大堆的重新构造
*/
public class HeapSort {
/**
* 堆排序
* @param array
*/
public static void heapSort(int[] array)
{
//创建最大堆:先建立大根堆,使得第一个元素是最大值
BuildHeap(array);
for(int i=array.length-1;i>=0;i--)
{
//数组的第一个元素与后面的元素交换,因为第一个元素总是当前堆的最大元素
int temp=array[0];
array[0]=array[i];
array[i]=temp;
//最大堆调整:交换掉第一个元素后,要对堆进行调整,保证第一个元素仍是最大值
heapify(array,i,0);
}
}
/**
* 创建堆 从底往上进行建堆
* 创建一个堆 需要对每个非叶子节点调用heapify(A,i)
* @param array
*/
public static void BuildHeap(int[] array)
{
for(int i=array.length/2;i>=0;i--) {
//建立堆的过程就是完全二叉树,从下到上调整堆的过程,i=array.length/2开始
//依次向上调整,i=array.length/2是最后一个节点的父节点i=0是第一个节点
heapify(array,array.length,i);
}
}
/**
* 递归的调用heapify方法
* 对某一节点和他的两个子节点进行比较交换使得其符合大根堆的规则
* @param array
* @param n 这里是需要调用heapify方法的节点数量(也就是非叶子节点的数量)
* @param i
*/
public static void heapify(int array[],int n,int i) {
int largest=i;
//left是i的左子节点
int left=2*i;
//right是i的右子节点
int right=2*i+1;
if(left < n && array[largest] < array[left])
{
largest=left;
}
if(right < n && array[largest] < array[right])
{
largest=right;
}
//找出左右孩子节点中的最大者
if(largest!=i)
{
//交换根节点和最大节点的值 使得父节点的值最大
int temp = array[largest];
array[largest] = array[i];
array[i] = temp;
//递归调用 因为子节点也需要满足堆的定义
heapify(array, n, largest);
}
}
public static void main(String[] args) {
int array[]={1,6,5,7,3,8,2,9,4};
heapSort(array);
System.out.println(Arrays.toString(array));
}
}