算法1
注意:
① 注意注释中的3个问题
② 插入操作就是先复制再up() down()
// down操作
public static void down(int i){
int t = i;
// 这里得n要和“问题2”下面一行中arr[n]的n对应起来,如果使用size,那么这两个地方都要使用size。否则出现“问题2”的错误
if(2*i <=n && arr[t] > arr[2*i]) t = 2*i;
if(2*i+1 <= n && arr[t] > arr[2*i+1]) t = 2*i+1;
if(t != i){
int temp = arr[i];
arr[i] = arr[t];
arr[t] = temp;
down(t);
}
}
// 完整代码
import java.util.*;
public class Main{
static int[] arr; // 全局
static int n;
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
int m = sc.nextInt();
arr = new int[n+1];
// 先都加进来
for(int i = 1; i <= n; i++){
arr[i] = sc.nextInt();
}
// 从n/2处开始排序
for(int i = n/2; i > 0; i--){
down(i);
}
//问题1: 从小到大输出时候不是这么输出:
// for(int i = 1; i <= m; i++){
// System.out.print(arr[i] + " ");
// }
// 需要依次删除最小的数(arr[1]),即把最大数放到头顶,然后down()
// int size = n;// 代表着队列最后一个元素的idx
while(m-- > 0){
System.out.print(arr[1] + " ");
// 问题2: 自己写时候写成了arr[1] = arr[size];但是在down() 中使用的是n,这样会导致被排除的无效数(范围超过size,但是在n内)再次进入有效数的范围。
arr[1] = arr[n];
n--;
down(1);
}
}
public static void down(int i){
int t = i;
// 问题3:这里得n要和“问题2”下面一行中arr[n]的n对应起来,如果使用size,那么这两个地方都要使用size。否则出现“问题2”的错误
// 和左子节点比较大小,t为小的那个的idx
if(2*i <=n && arr[t] > arr[2*i]) t = 2*i;
// 和右子节点比较大小,t为小的那个的idx
if(2*i+1 <= n && arr[t] > arr[2*i+1]) t = 2*i+1;
// 不等则说明左右子节点中有比当前节点值小的,那么交换。
if(t != i){
int temp = arr[i];
arr[i] = arr[t];
arr[t] = temp;
down(t);
}
}
}