堆排序算法 主要是要先把数组看成二叉树
然后把二叉树变成一个大顶堆(任何一个节点大于它的左右节点,但是左右节点两者的大小不确定)
然后把大顶堆的第一个元素和最后一个元素换位,依次类推,最后就的得出一个有规律的数组
package datastructure.tree;
/*
@CreateTime 2021/9/5 10:27
@CreateBy cfk
堆排序算法
*/
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class HeapSort {
public static void main(String[] args) {
int[] arr = {4,-1,6,0,8,5,9};
int tmp = 0;
// ajustHeap(arr, 1, arr.length);
// ajustHeap(arr, 0, arr.length);
// System.out.println(Arrays.toString(arr));
//根据升序和降序选择生成大顶堆和小顶堆
//arr.length/2-1为最后一个非叶子节点
for (int i = arr.length/2-1; i >= 0; i--) {
ajustHeap(arr,i,arr.length);
}
System.out.println(Arrays.toString(arr));
//上面得出大顶堆 已经确定了一个最大值 所以这里的次数会减一
for (int j = arr.length-1; j > 0; j--) {
tmp = arr[0];
arr[0] = arr[j];
arr[j] = tmp;
//从0开始是因为数组已经是大顶堆了,把最大值换位置后,第二第三大的值会重新选举最大的值
ajustHeap(arr,0,j);
}
System.out.println(Arrays.toString(arr));
}
//测试8000000数据的性能 2s
/* public static void main(String[] args) {
int tmp = 0;
int[] arr = new int[8000000];
for (int i = 0; i < 8000000; i++) {
arr[i] = (int) (Math.random()*8000000);
}
System.out.print("排序前");
Date date1 = new Date();
SimpleDateFormat sdf1 = new SimpleDateFormat("yyy-MM-dd HH:mm:ss");
String timeBefore1 = sdf1.format(date1);
System.out.println(timeBefore1);
for (int i = arr.length/2-1; i > 0 ; i--) {
ajustHeap(arr,i,arr.length);
}
for (int i = arr.length-1; i > 0; i--) {
tmp = arr[0];
arr[0] = arr[i];
arr[i] = tmp;
ajustHeap(arr,0,i);
}
System.out.print("排序后");
Date date2 = new Date();
SimpleDateFormat sdf2 = new SimpleDateFormat("yyy-MM-dd HH:mm:ss");
String timeBefore2 = sdf2.format(date2);
System.out.println(timeBefore2);
// System.out.println(Arrays.toString(arr));
}*/
/*
4
6 8
5 9
*/
//此方法将数组调整成为大顶堆
/**
*
* @param arr 传入数组
* @param i 传入调整的非叶子节点
* @param length 传入调整的数组的长度
* @return 在这里不需要返回值,因为可以直接调整数组,让数组内容发生改变
*/
public static void ajustHeap(int[] arr,int i,int length){
int tmp = arr[i];
for (int j = 2*i+1; j < length; j=2*j+1) {
//通过循环遍历把j指针指向下一位 如果左节点比右节点小的话
//这里j+1判不判断都可以 判断了如果j+1大于length的话直接就可以退出循环了 提高了效率
if (j+1<length && arr[j]<arr[j+1]){
j++;
}
//判断当前非叶子节点和其子节点数值大小变化
if (tmp<arr[j]){
arr[i] = arr[j];
//把i指向j是为了继续循环判断,i赋值后就继续往i下的子树进行循环,直到最后
i = j;
}else {
break;
}
}
arr[i] = tmp;
}
}