package aaa;
import java.util.*;
/* 堆排序,可以有效的降低时间复杂度
* 建立一个大顶堆并且进行堆排序输出从小到大排序的数
* 时间复杂度为O(NlogN)
* 扩展:如果要求一个数列里面的第k大的数,只需要建立一个大小为k的小顶堆,并且不断调整维护(先选三个数建堆,后面的数逐个插入堆顶并进行删除调整),
* 最后输出对堆顶元素即可
* 同理,求解一个数列里面的第k小的数,只需要建立一个大小为k的大顶堆,
* */
public class Main {
static Scanner in = new Scanner(System.in);
static int n;
static int[] h = new int[1000];
//交换数据值
static void swap(int x ,int y){
int t;
t = h[x];
h[x] = h[y];
h[y] = t;
}
//注意:对于一个完全二叉树而言,第一个非叶子节点编号为n/2,
//构建大顶堆,从第一个非叶子节点开始逐个向下调整
static void create(){
for (int i = n/2; i >= 1; i--) {
shiftDown(i);
}
}
//向下调整,i为当前叶子编号
static void shiftDown(int i){
boolean f = true;//用来判断是否需要继续调整
int t ;
//如果有左子
while(i*2 <= n && f){
//和左子的值进行比较调整,更新t值
if(h[i]<h[i*2])
t = i*2;
else
t = i;
//如果有右子,和右子的值进行比较调整更新t值
if(i*2+1 <= n){
if(h[t]<h[i*2+1])
t = i*2+1;
}
//注意我们寻找的是左右子里面最大的值
//如果当前节点需要调整,交换调整
if(t!=i){
swap(t, i);
i = t;//更新i的值,以便于进行下一次调整(下一层)
}
else
f = false;//如果当前节点不需要调整,退出
}
}
//由于要按照从小到大输出,所以把节点1和节点n交换,n--的意思是最终序列里面的最后的一个数已经确定
//并且重新调整当前堆使之成为大顶堆,以此类推,每次找出当前数里面最大的数
static void heapSort(){
while(n>1){
swap(1, n);
n--;
shiftDown(1);
}
}
public static void main(String[] args) {
n = in.nextInt();
int k = n;//保护n的值,用于输出
for (int i = 1; i <= n; i++) {
h[i] = in.nextInt();
}
create();
heapSort();
for (int i = 1; i <= k; i++){
System.out.print(h[i]+" ");
}
System.out.println();
}
}
两个小错误:一、没有保护n的值; 二、t写成了i,求的是左右子里面最大的