package com.cisco.www.test;
import java.util.Arrays;
/**
* 将待排序序列构造成为一个大顶堆,此时整个序列的最大值就是堆顶的根节点。
* 将其与堆尾元素进行交换,此时末尾的值就是最大值。然后对剩余n-1个元素重新构成一个堆
* 这个时候会得到n个元素的最小值
* 堆是一个完全二叉树:要么是一个满二叉树,非叶节点孩子都是全的,满二叉树属于完全二叉树
* 一个节点左孩子下标是:2*i+1;右孩子下标是:2*i+2
* 一个节点的父节点的坐标是:(i-1)/2
* 从头至尾只有数组结构,没有树的结构
* 大根堆:在一棵完全二叉树中,每棵子树的头部都是这棵树的最大值就是大根堆
* 怎么把数组变成一个大根堆?建立大根堆?
* 每一步都会形成0到i的大根堆
*/
public class HeapSort {
public static void heapSort(int[] arr){
if(arr==null||arr.length<2){
return;
}
//先插入堆,构造一个大顶堆
for(int i = 0 ; i < arr.length ; i++ ){
heapInsert(arr,i);//0-i
}
int heapSize = arr.length;
//第一个元素和最后一个元素进行交换,开始堆排序
swap(arr,0,--heapSize); //最后位置上的数和0位置上的数进行交换
while (heapSize>0){
heapify(arr,0,heapSize);
swap(arr,0,--heapSize);
}
}
//建立大根堆的过程,时间复杂度O(N^2)
private static void heapInsert(int[] arr, int index) {
//自己的位置和父位置进行比较,如果自己位置的值比父位置的值大,就来到父位置
while (arr[index]>arr[(index-1)/2]){
//如果自己位置的值比父位置的值大,就将自己位置上的值和父位置的值进行交换
swap(arr,index,(index-1)/2);
//然后将索引移到父位置,重新这个过程
index=(index-1)/2;
}
}
private static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
/**
* 在0-heapsize-1的位置上已经形成了堆,再向右就认为是越界的
* @param arr
* @param index
* @param heapSize
*/
public static void heapify(int[] arr,int index , int heapSize){
int left = index*2+1;
while (left<heapSize){ //保证left不越界,如果越界了说明已经是叶结点了,停在那里就可以了
/**
* left+1<heapSize表示右孩子也不越界,并且右孩子的值比左孩子的值要大
* 下面这段代码的意思是左右孩子哪个值大,哪个值就是我们largest值的位置
*/
int largest = left+1<heapSize&&arr[left+1]>arr[left]?left+1:left;//左右孩子比较
largest=arr[largest]>arr[index]?largest:index;//左右孩子节点中较大的那个和父节点进行比较
//如果和较大孩子相比,较大值的是自己,那么就直接break,不用向下沉了
if(largest==index){
break;
}
//当largest!=index的时候
swap(arr,largest,index); //当前的数和左右孩子较大的数进行交换
index=largest; //自己变成了较大孩子的下标
left=index*2+1; //left向下走,重复while循环
}
}
//for test
public static void main(String[] args){
int testTime = 1000000;
int size = 100;
int value = 100;
boolean succeed = true;
for(int i = 0 ; i<testTime ; i++){
int[] arr1 = generateRandomArray(size,value);
int[] arr2 = copyArray(arr1);
heapSort(arr1);
comparator(arr2);
if(!isEqual(arr1,arr2)){
succeed=false;
break;
}
}
System.out.println(succeed?"Nice":"Fucking fucked!");
int[] arr= generateRandomArray(size,value);
printArray(arr);
heapSort(arr);
printArray(arr);
}
private static void printArray(int[] arr) {
if(arr==null){
return ;
}
for(int i= 0 ; i<arr.length;i++){
System.out.print(arr[i]+" ");
}
System.out.println();
}
private static boolean isEqual(int[] arr1, int[] arr2) {
if((arr1!=null&&arr2==null)||arr1==null&&arr2!=null){
return false;
}
if(arr1==null&&arr2==null){
return true;
}
if(arr1.length!=arr2.length){
return false;
}
for(int i = 0 ; i<arr1.length;i++){
if(arr1[i]!=arr2[i]){
return false;
}
}
return true;
}
private static void comparator(int[] arr) {
Arrays.sort(arr);
}
//for test
//随机产生一个0-100长度的随机数组
private static int[] generateRandomArray(int size, int value) {
//生成一个0到100的随机数组
int[] arr = new int[(int)(Math.random()*(size+1))];
for(int i = 0 ; i <arr.length;i++){
arr[i] = (int)((value+1)*Math.random())-(int)(value*Math.random());
}
return arr;
}
//for test
public static int[] copyArray(int[] arr){
if(arr==null){
return null;
}
int[] res = new int[arr.length];
for(int i = 0 ; i <arr.length;i++){
res[i] = arr[i];
}
return res;
}
}