queue.poll()

    • poll() 是 PriorityQueue 类的方法,用于从队列中取出并移除 优先级最高的元素。由于这里的队列是根据自定义的比较器进行排序的,因此 poll() 会返回队列中优先级最高的元素。
    • 如果队列不为空,poll() 会返回并移除队列中的第一个元素。如果队列为空,则返回 null

      排序发生的时机:

      • 当你向队列中添加元素时,PriorityQueue 会根据比较器自动排序,即插入时就进行排序。
      • 但是,优先队列本身并不会在插入每个元素时进行排序,而是保持一个堆结构,确保每次 poll() 操作(即移除队头元素)时,队头元素是排序后的最小值。
      • 所以在你执行 queue.add(new long[]{arr[i], i}); 时,队列的元素会被按这个规则“排好”。
      • 当你调用 queue.poll() 时,队头元素是最小的,这个操作会自动从队列中移除最小的元素,同时保持队列的排序结构。

        为什么这么做?

        防止重复操作和保证正确性:

        • 在你当前的程序中,元素的值可能会被修改(比如加到邻居元素上),如果没有这段代码,队列中的元素可能会包含已经被修改过的值。比如,如果 arr[index] 被更新成了 -1,但由于队列是基于堆结构的,它仍然存在于队列中,并且被错误地作为最小元素取出进行下一轮的处理。为了避免这种情况,就需要检查队列中的元素是否是最新的值。
        • 如果某个元素的值已经被修改(例如变为 -1),它就不再是原来的有效值,因此不能再被继续处理。通过将其重新加入队列,确保队列中存的是未被更新过的有效数据,并且通过 continue 跳过已更新的元素,从而保证每次操作的正确性。

        结论

        这段代码的目的是确保队列中的元素总是保持最新状态,并且如果某个元素已经被更新过,它不会重复参与计算。通过这种方式,程序能够正确地执行每一轮的操作,避免了可能因为处理过期数据而导致的错误。

import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt() , k = sc.nextInt();
        long[] arr = new long[n];
        //queue存的是数组,在后面将值赋给cur时,cur[0]是值cur[1]是序号
        PriorityQueue<long[]> queue = new PriorityQueue<>(((o1, o2) -> {
            if (o1[0] == o2[0]) return Long.compare(o1[1],o2[1]);
            else return Long.compare(o1[0],o2[0]);
        }));
        for (int i = 0; i < n; i++) {
            arr[i] = sc.nextInt();
            queue.add(new long[]{arr[i],i});
        }
        //关于优先队列的排序的时机:当向队列中添加元素时,优先队列会根据比较器自动排序,即插入时就进行排序
        //但是优先队列本身并不会在插入每个元素时进行排序,它会保持一个堆结构,但是每次poll时,按排序规则移除
        //比如在本题中是移除最小的
//        for(long[] v:queue){
//            System.out.print(Arrays.toString(v)+" ");
//        }System.out.println();
        while (k > 0) {
            //一开始就进行赋值,并弹出队首元素
            long[] cur = queue.poll();
            long value = cur[0];
            int index = (int) cur[1];

//            for(long[] v:queue){
//                System.out.print(Arrays.toString(v)+" ");
//            }System.out.println();
            //因为index和value在原始的数组中是一一对应的,如果不相等,说明发生了修改
            //(说明这个元素的值已经被修改过了,可能已经参与了前面的加法操作(并且被标记为 -1))
            //就将其重新加回队列
            //保证如果队列中出现了已经更新过的元素,它不会继续参与本轮操作,而是等待下一轮被处理。
            if (value != arr[index]) {
//                System.out.printf("符合value != arr[%d]",index);
//                System.out.println();
                queue.add(new long[]{arr[index],index});
//                for(long[] v:queue){
//                    System.out.print(Arrays.toString(v)+" ");
//                }System.out.println();
                continue;
            }
//            System.out.printf("%d arr前:",k);
//            for(int i=0;i<arr.length;i++){
//                System.out.print(arr[i]+" ");
//            }System.out.println();
            //因为是会影响左右两边,所以要向右和向左找
            // 如果要是不符合数组的范围,就相当于出界了,就不找了
            // 向左找
            for (int i = index-1; i >= 0; i--) {
//                System.out.printf("index=%d",i);
//                System.out.println();
                if (arr[i] != -1) {
                    arr[i] += value;
                    break;
                }
            }
//            System.out.printf("%d arr中:",k);
//            for(int i=0;i<arr.length;i++){
//                System.out.print(arr[i]+" ");
//            }System.out.println();
            // 向右找
            for (int i = index+1; i < n; i++) {
                if (arr[i] != -1) {
                    arr[i] += value;
                    break;
                }
            }
//            System.out.printf("%d arr后:",k);
//            for(int i=0;i<arr.length;i++){
//                System.out.print(arr[i]+" ");
//            }System.out.println();
            arr[index] = -1;
            k--;
        }
        for (long x : arr) {
            if (x > -1) System.out.print(x + " ");
        }
    }
}

 

posted on 2025-05-31 17:32  fafrkvit  阅读(36)  评论(2)    收藏  举报