偷看()或不偷看()

Posted

技术标签:

【中文标题】偷看()或不偷看()【英文标题】:To peek() or not to peek() 【发布时间】:2016-03-21 12:13:25 【问题描述】:

我有 PriorityQueue 使用示例,它产生

3

1

1

1

5

0

这是代码

import java.util.*;

class Someclass


public static class IntegerWr 
    implements Comparable<IntegerWr>

    Integer val;

    IntegerWr(Integer val)
    
        this.val = val; 
    

    public void change(Integer nval)
     
        this.val = nval;
    

    @Override
    public int compareTo(IntegerWr iw)
    
        return val.compareTo(iw.val);
    
    @Override public String toString()
    
        return ""+val;
    

    public static void main (String[] args) 
    
        PriorityQueue<IntegerWr> pq = new PriorityQueue<>();
        pq.add(new IntegerWr(3));
        System.out.println(pq.peek());
        IntegerWr iw1 = new IntegerWr(1);        
        pq.add(iw1);
        System.out.println(pq.peek());
        pq.add(new IntegerWr(4));
        System.out.println(pq.peek());
        pq.add(new IntegerWr(2));
        System.out.println(pq.peek()); //must output 1, and does so
        iw1.change(5);                 //change value of element that is actually on peek
        System.out.println(pq.peek()); //outputs 5 which is unexpected
        pq.add(new IntegerWr(0));
        System.out.println(pq.peek()); 
    

似乎 PriorityQueue 仅在插入时订购。使用什么方法来获取实际的 peek()?

【问题讨论】:

"似乎 PriorityQueue 仅在插入时订购。"——确实如此。队列怎么知道你修改了某个元素?例如,如果您将项目添加到列表中,然后对其进行排序,然后更改其某些值以破坏顺序,您难道不希望列表以某种方式考虑它吗?.. 【参考方案1】:

您正在更改存储在队列中的对象内部的值。 队列对对象的内容一无所知。 因此,当您在队列中的对象上调用方法时(如在 'iw1.change(5)' 中),队列中的任何内容都不知道。 您需要存储一个替换对象,以便队列对元素重新排序。

【讨论】:

可以poll()该项目,修改它,然后offer()它回到队列以保持正确的顺序。【参考方案2】:

代替iw1.change(5); 做:

pq.remove(iw1);
iw1.change(5);
pq.add(iw1);

【讨论】:

对象的变化发生在某个时间。优先级队列构建一次,寿命更长。 change() 可能会在以后的任何时间发生。如果对象被更改,PriorityQueue peek() 不会给出正确的(通过存储对象的自然排序)结果。 :// @willmore 同样适用于 java 中具有某种排序的所有类型的集合,一旦将对象添加到此类对象,就无法更改构成排序条件的对象的属性收藏。 (这甚至适用于某些集合,例如没有特定顺序的 Maps)【参考方案3】:

PriorityQueue 是队列的一个实现。如果我们查看Queue interface,它有 peek()、poll()、remove() 方法。

peek() 方法返回但不移除队列的头部。

poll() 方法移除并返回队列的头部。从队列中删除的确切元素是队列的排序策略的函数。

import java.util.*;

class Someclass


public static class IntegerWr 
    implements Comparable<IntegerWr>

    Integer val;

    IntegerWr(Integer val)
    
        this.val = val; 
    

    public void change(Integer nval)
     
        this.val = nval;
    

    @Override
    public int compareTo(IntegerWr iw)
    
        return val.compareTo(iw.val);
    
    @Override public String toString()
    
        return ""+val;
    

    public static void main (String[] args) 
    
        PriorityQueue<IntegerWr> pq = new PriorityQueue<>();
        pq.add(new IntegerWr(3));
        System.out.println(pq.peek());
        IntegerWr iw1 = new IntegerWr(1);        
        pq.add(iw1);
        System.out.println(pq.peek());
        pq.add(new IntegerWr(4));
        System.out.println(pq.peek());
        pq.add(new IntegerWr(2));
        System.out.println(pq.peek()); //must output 1, and does so
        iw1.change(5);                 //change value of element that is actually on peek
        System.out.println(pq.peek()); //outputs 5 which is unexpected
        pq.add(new IntegerWr(0));
        System.out.println(pq.peek()); 

        System.out.println("Elements ordered");
        Object o = null;
        while ((o = pq.poll()) != null) //poll() method removes and return
                                        //the head of the queue.
                                        //Exactly which element is removed 
                                        //from the queue is a function 
                                        //of the queue's ordering policy
        
            System.out.println(o);
        
    

输出

3

1

1

1

5

0

Elements ordered

0

2

3

4

5

按顺序获取 PriorityQueue 的元素,请使用poll()

【讨论】:

以上是关于偷看()或不偷看()的主要内容,如果未能解决你的问题,请参考以下文章

得到细胞索引 - 偷看和流行

你偷看的小黄片,全被监视了

你偷看的小黄片,全被监视了

你偷看的小黄片,全被监视了

别偷看!不能说的秘密-华为BGP路由技术

程序员偷看了老板的微信分组,惊呆了……