堆排序是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
堆排序的过程:
1、将原始数组安排到一个二叉树中,这里用数据
6 | 9 | 7 | 3 | 5 | 2 |
---|
构造的过程 将数组的第一个元素作为根节点(记根节点下标为 i),两个子节点 的下标分别是 2 * i 和 2 * i+1,以次类推将数组构造成以下的二叉树。
2、进行上浮排序,即每次将最大的元素移动到最顶端,构造大根堆。
3、删除最大值,然后继续进行第二步,直到数组有序。这里我们将数最大值移动到数组的尾部。
黑色的为数值,红色的是数字在数组中的下标。
排序的过程就是不断的构造大根堆的过程。从当前二叉树的第一个非叶子节点开始,依次向上,将每个节点和他的子节点构造成一个大根堆( 根节点>左子节点&& 根节点>又子节点)。
非叶子节点是指:当前节点至少存在一个子节点。 在上图中 非叶子节点是 6 、9、 7 。
开始构造大根堆。
从后向前,第一个非叶子节点 7 ,判断 7、 5、两个元素是否满足大根堆。这里 7>5 满足大根堆。
第二个非叶子节点 9 判断 9 ,3 ,5 是否满足大根堆。 这里 9>3 && 9>5 满足大根堆。
第三个非叶子节点 6 判断 6 ,9 ,7 是否满足大根堆。 这里 6>9 不满足 我们将 子节点中最大的元素和根节点交换。
第一轮结束后二叉树如图
继续上面构造大根堆的步骤。
7 为根节点的二叉树 满足大根堆
6 为根节点的二叉树 满足大根堆
9 为根节点的二叉树 满足大根堆
所以当前二叉树满足 大根堆。
这时 我们将9 和最后一个元素进行调换。 下一次 9将不参与后面的排序。
循环执行前面的步骤 即可对整个二叉树构造成一个小根堆 ,实现排序。
下面是代码
public class HeapSort {
public static void sort(int[] arr){
int last=arr.length-1;//参与排序的最后一个元素的下标
while(last>0){
int root=last/2-(last%2==0?1:0);//根节点的下标
do{
int left=root*2;//左子节点的下标
int right=root*2+1;//右子节点的下标
if(arr[left]<=arr[root]&&arr[right]<=arr[root]&&root==0){
exchange(arr,last,0);
last--;
break;
}else{
if(right<=last){
max(arr,left,right);
max(arr,root,left);
}
}
if(--root<0){
root=last/2-(last%2==0?1:0);
}
}while(true);
}
}
//交换 数组中的两个数字,并且将大的数字放到 下标为a 的位置
public static void max(int[] arr ,int a, int b){
if(arr[a]<arr[b]){
int tem=arr[a];
arr[a]=arr[b];
arr[b]=tem;
}
}
//交换数组中的两个数字。
public static void exchange(int[] arr,int a,int b){
int tem=arr[a];
arr[a]=arr[b];
arr[b]=tem;
}
}
在以上代码中,每次构造大根堆的初始位置为 第一个非叶子节点。
int root=last/2-(last%2==0?1:0);