这里以大根堆为例,着重关注是什么堆化的、以及在堆中插入一个新数后如何进行调堆的操作
代码:
import java.util.Random;
/**
* 堆排序
*/
public class heap {
/**
* 堆排序
*/
public static void heapsort(int[] arr){
if(arr ==null||arr.length<2){
return;
}
//相当于将数组变为大根堆
for (int i=0;i<arr.length;i++){
heapInsert(arr,i);
}
int heapsize=arr.length;
//第一个数和最后一个数进行交换
swap(arr,0,--heapsize);
while (heapsize>0){
heapify(arr,0,heapsize);
swap(arr,0,--heapsize);
}
}
/**
* 交换
* @param a
* @param b
*/
public static void swap(int[] arr,int a,int b){
int temp=arr[a];
arr[a]=arr[b];
arr[b]=temp;
}
/**
* 大根堆调堆(从当前节点向上找父节点依次比较)
* @param arr
* @param index
*/
public static void heapInsert(int[] arr,int index){
while (arr[index]>arr[(index-1)/2]){
swap(arr,index,(index-1)/2);
index = (index-1)/2;
}
}
/**
* 某个数在index位置时判断是否往下移动
* heapify(堆化)
* @param arr 数组
* @param index 父节点
* @param heapsize 堆的大小
*/
public static void heapify(int[] arr,int index,int heapsize){
//左孩子下标
int left = index*2+1;
//如果有左孩子(为什么是左孩子? 答: 那是因为堆是一个完全二叉树,看左孩子是否存在就等于判断下面是否还要孩子)
while (left<heapsize){
//比较两个孩子中最大的一个
int max = left + 1 < heapsize && arr[left+1]>arr[left] ? left+1 : left;
//比较父亲和最大的孩子之间谁大,如果孩子大则交换
max = arr[max] > arr[index] ? max : index;
//说明 父亲节点加上两个孩子节点在内的一个堆里面,父亲就是最大的。所以不需要再进行后续判断
if(max == index){
break;
}
//最大的一个孩子节点和父节点交换
swap(arr,max,index);
//换完父节点之后继续,来到父节点位置
index = max;
//新的左孩子下标
left = index*2+1;
}
}
public static void main(String[] args) {
int[] arr=new int[10];
Random random=new Random();
for(int i=0;i<10;i++){
arr[i]= random.nextInt(10);
}
System.out.println("堆排序前的数为:");
for (int i = 0; i < arr.length; i++) {
System.out.print(" "+arr[i]);
}
heapsort(arr);
System.out.println("\n++++++++++++++++++++++++++++++++++++++++");
System.out.println("堆排序后的数为:");
for (int i = 0; i < arr.length; i++) {
System.out.print(" "+arr[i]);
}
}
}