package com.atguigu.tree.threadebinarytree;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
/**
* @author WZ
* @create 2021-10-23 14:07
*/
public class HeapSort {
public static void main(String[] args) {
//要求将数组进行升序排列----大顶锥
// int[] arr=new int[]{4,6,8,5,9};
// headSort(arr);
//测试性能
int []arr=new int[8000000];
for (int i = 0; i < arr.length; i++) {
arr[i]=(int) (Math.random()*8000000);
}
System.out.println("排序前");
Date date = new Date();
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
String str1 = simpleDateFormat.format(date);
System.out.println("排序前的时间是"+str1);
headSort(arr);
Date date1=new Date();
String str2 = simpleDateFormat.format(date1);
System.out.println("排序后的时间是"+str2);
}
//编写一个堆排序的方法
public static void headSort(int arr[]){
int temp=0;
// System.out.println("堆排序");
//分布完成
// adjustHeap(arr,1,arr.length);
// System.out.println("第一步完成局部大顶锥"+ Arrays.toString(arr));//4.9.8.5.6
// adjustHeap(arr,0,arr.length);
// System.out.println("第二步完成局部大顶锥"+ Arrays.toString(arr));//9.6.8.5.4
//完成最终代码,将无序序列建成一个堆,根据升序降序需求选择大顶堆或者小顶堆
for (int i = arr.length/2-1; i >=0; i--) {//arr.length/2-1=5/2-1=2-1=1;先1后0从下至上
adjustHeap(arr,i,arr.length);
}
/*
将堆顶的元素与末尾元素交换,将最大的元素“沉”到数组末端;
重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换的步骤,直到这个序列有序
*/
for (int j = arr.length-1; j >0 ; j--) {//总共5个数,调整4次即可
//开始交换,首尾交换
temp=arr[j];
arr[j]=arr[0];
arr[0]=temp;
adjustHeap(arr,0,j);//写0的目的是始终从顶部开始找
}
// System.out.println("数组="+ Arrays.toString(arr));
}
//将一个数组(二叉树),调整成一个大顶锥的方法
/**
*功能:完成将以i对应的非叶子节点的树调整成大顶锥
* 举例:int arr[]={4,6,8,5,9};=> i先等于1(非叶子节点在数组中的索引为1)进去后,
* 调整数组成{4,9,8,5,6};(从左至右,从下至上进行调整)
* 再次调用,第二次进行调整,应该调整角标为i=0对应非叶子节点为4的数,调整成{9,4,8,5,6}
* 但此次调整会导致字根4,5,6发生变化,继续调整,4,5,6中6最大交换4,6,为{9,6,8,5,4}
*
* @param arr 待调整的数组
* @param i 表示非叶子节点在数组中的索引(是从最后一个非叶子节点开始的)
* @param length 表示对多少个元素进行调整,length在逐渐的减少
*/
public static void adjustHeap(int arr[],int i,int length) {
int temp=arr[i];//先取出当前元素的值,保存在一个临时变量
//开始调整
//k表示以i为非叶子节点的左子节点,最后k表示下次再调整也是左子节点
for (int k = i*2+1; k <length ; k=k*2+1) {
if (k+1<length && arr[k] < arr[k+1]) {//这个说明左子节点的值小于右子节点的值
k++;//在这种情况下让k指向右子节点(k为左子节点,k+1是右子节点)
}
if (arr[k]>temp){//如果子节点大于父节点
arr[i]=arr[k];//把较大的值,赋给当前节点
i=k;//因为k没有完,下面可能还有左子树或者右子树
}else {
break;//如果是小于,直接停止即可,因为是从最后一个非叶子节点开始的,不用判断下面,下面就是有序的。
}
}
//当for循环结束后,我们已经将i为父节点的数的最大值放在了最顶上(局部)
arr[i]=temp;//将temp赋值的放到调整后的位置
}
}