package com.algorithm.sort;
import java.util.Scanner;
/**
* 堆排序
* 算法思路:
* 一维数组除了能表示线性结构外,还能表示完全二叉树
* 选择排序的思想是,固定位置比较n-1次,获得数字,固定下一个位置,比较n-2次。。。
* 但是这样,后面的比较有重新比较,有的数字是比较过的。
* 而堆排序正是利用树形结构,对比较过的进行保存。省去了没必要的重复比较。
* 最大堆:任意的f(i)>f(2*i+1),f(2*i+2)
* 最小堆:任意的f(i)<f(2*i=1),f(2*i+2)
* 本代码使用最大堆,即采用从小到大排序
* 就是第一次初始化堆,将最大值放到根结点,然后从树的最后一个倒着处理(将根结点即剩余数的最大值放到最后一个位置即倒着排序)
* 1.初始化堆
* 1.1从最后一个父节点i起,f(i),f(2*i+1),f(2*i+2)取最大的与f(i)交换,(即调为最大堆)
* 1.2 i--
* 1.3调整过后,可能有的子节点与父节点交换以后,该子节点本身作为父节点,可能会打乱曾经调整过的
* ,但只是影响左子树或者右子树,我们只需要循环对该子树进行调整最大堆就行了, 因为该子树的兄弟子树
* 是调整过的,不必调整.
* 2.通过初始化堆,可以根节点就是剩下的k个数字(初始剩下的有n个数字,排一次序,剩下的数字少一个,即k--)中最大的数字,
* 而k之后的数字是排好序的,只需要将根节点跟k位置的数字交换,那么f(n),f(n-1)..f(k)就是倒数最大的数字的有序序列。
* 经过交换数字,根节点的最大堆性质又被打乱,那么按照1.3的步骤继续调整堆。
* 循环步骤2,直到k=1的时候,就排好序了
* @author mooner
*
*/
public class HeapSort {
public static void main(String[] args){
while(true){
System.out.println("\n请输入数字个输入");
int n = new Scanner(System.in).nextInt();
int[] num = new int[n];
for(int i = 0; i < num.length;i++){
num[i] = new Scanner(System.in).nextInt();
}
System.out.println("堆排序前:");
for(int i=0;i<num.length;i++){
System.out.print(num[i]+"\t");
}
System.out.println();
System.out.println("堆排序后:");
sort(num);
for(int i=0;i<num.length;i++){
System.out.print(num[i]+"\t");
}
}
}
/**
* 堆排序
* @param arr 待排序的数组
*/
public static void sort(int[] arr){
//初始化堆。从最后一个父节点开始,倒着调整堆
for(int i = arr.length/2-1; i>=0 ; i--){
adjust(arr,i,arr.length-1);
}
for(int j = arr.length - 1; j >= 1 ; j--){
int tmp = arr[0];
arr[0] = arr[j];
arr[j] = tmp;
adjust(arr,0,j-1);
}
}
/**
* 调整堆
* 值调整当前父节点的位置和父节点的子树,不负责调整父节点的兄弟节点或者父节点的父节点
* @param arr 调整的数组
* @param parent 父节点
* @param last 最后一个叶子节点的位置
*/
public static void adjust(int[] arr,int parent,int last){
//定义较大的节点的位置,默认为左孩子节点
int maxIndex = 2*parent+1;
while(maxIndex <= last){ //节点在调整范围
if(maxIndex < last){ //存在右孩子节点
//比较左右孩子
if(arr[maxIndex] < arr[maxIndex+1]){
maxIndex++;
}
}
//将最大的孩子节点跟父节点比较,如果父节点小,则交换
if(arr[parent] < arr[maxIndex]){
int tmp = arr[parent];
arr[parent] = arr[maxIndex];
arr[maxIndex] = tmp;
parent = maxIndex; //交换后可能造成孩子节点不满足最大堆,那么继续往下迭代
maxIndex = parent * 2 +1;
}else{
break;
}
}
}
}