【问题标题】:peek() method in Queue interfaceQueue 接口中的 peek() 方法
【发布时间】:2015-04-10 05:53:53
【问题描述】:

来自Java documentation

remove() 和 poll() 方法删除并返回队列的头部。

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

从第二点开始,它说方法peek()返回队列的头元素,那么它为什么在下面的程序中不返回队列的头元素?

public class PQ {

public static void main(String[] args) {
    PriorityQueue<String> pq = new PriorityQueue<String>();
    pq.add("carrot"); 
    pq.add("apple"); 
    pq.add("banana");
    System.out.println(pq.poll() + ":" + pq.peek()); // prints apple and banana rather than apple and apple
}
}

一旦第一个元素(胡萝卜)被删除,苹果就成为队列的头(根据队列中的FIFO)所以peek()方法应该返回苹果对吗?

示例2:

public class PQ {

public static void main(String[] args) {
    PriorityQueue<String> pq = new PriorityQueue<String>();
    pq.add("carrot"); 
    pq.add("apple"); 
    pq.add("banana");
    System.out.println(pq); // prints [apple, carrot, banana] -> it should be [apple, banana, carrot] right? if it is following natural sorting order
}
}

【问题讨论】:

  • PriorityQueue 对元素进行排序,这意味着您的队列的顺序是(头)applebananacarrot(尾)。因此,对poll() 的调用将删除并返回头部(apple),使banana 成为新的头部,如以下对peek() 的调用所示。
  • 所以PriorityQueue 不遵循FIFO?
  • @kittu 正确;它遵循自然顺序。
  • @Vulcan 在PriorityQueue比较的情况下,自然排序是否意味着字典顺序?
  • 是的自然排序顺序 lexicographical 在字符串的情况下排序。

标签: java scjp


【解决方案1】:

因为你先轮询

System.out.println(pq.poll() + ":" + pq.peek());

因为它是一个优先队列元素被存储为

carrot -> banana -> apple

当您 poll() 时,您将获得 apple 并从队列中删除。在哪个队列头之后是banana,这正是您在peek() 时得到的。

请查看更新问题中的示例 2。排序很奇怪

这只是你没想到的。你可以看到documentation

方法 iterator() 中提供的迭代器不能保证以任何特定顺序遍历优先级队列的元素。如果需要有序遍历,可以考虑使用 Arrays.sort(pq.toArray())。

如果您阅读 java 优先级队列使用的优先级堆数据结构,您会更好地理解这一点。您应该使用poll(), peek() 方法来获取有序数据。

【讨论】:

  • Thankur:请参阅上面的 Balaji Katika 回答,关于元素排序,我对您和他的回答感到困惑
  • 默认情况下它采用自然排序。如果您不希望这样,您可以在构造函数 public PriorityQueue(int initialCapacity,Comparator&lt;? super E&gt; comparator) 中传递自己的比较器
  • 如果您不提供比较器,则使用自然排序。对于一个能够自然排序的类,它应该实现Comparable 接口。由于您使用的是 String 和 String 实现 Comparable 您不必担心。
  • 我想问的是:元素是否存储为 carrot -&gt; banana -&gt; appleapple -&gt; banana -&gt; carrot ?因为它是一个 PriorityQueue?
  • apple 将是您队列的第 0 个索引。因此,如果您想到一个典型的队列,apple 将是头部,banana 之后是 carrot 之后。
【解决方案2】:

您使用的是 PriorityQueue 而不是 java.util.Queue(常规队列) PriorityQueue 根据 Comparable::compareTo() 方法的实现对元素进行排序,这是 String.class 的自然排序(字母顺序)。

因此,队列中的元素将是 apple-banana-carrot。 输出符合预期

【讨论】:

    【解决方案3】:

    您已经通过引用文档自己回答了这个问题。

    您的优先队列包含

    apple, banana, carrot
    

    poll 返回 "apple" 然后删除它。所以现在队列是

    banana, carrot
    

    peek 然后返回“香蕉”

    【讨论】:

      【解决方案4】:

      POLL() 方法将从队列中删除该元素并将元素返回给调用方法。 PEEK() 方法将只返回该元素。 参考这个 POLL() 和 PEEK() 方法的实现代码:

      public E poll() {
              if (this.size == 0)
                  return null;
              int i = --this.size;
              this.modCount += 1;
              Object localObject1 = this.queue[0];
              Object localObject2 = this.queue[i];
              this.queue[i] = null; 
              if (i != 0)
                  siftDown(0, localObject2);
              return localObject1;
      }
      
      public E peek() {
              return ((this.size == 0) ? null : this.queue[0]);
      }
      

      【讨论】:

        【解决方案5】:

        Queue 接口定义了一些作用于列表第一个元素的方法,它们的行为方式不同。这些方法是:

        peek()
        element()
        poll()
        remove()
        

        peek() 此方法检索队列的第一个元素的值,而不将其从队列中删除。对于方法的每次调用,我们总是得到相同的值,并且它的执行不会影响队列的大小。如果队列为空,则 peek() 方法返回 null。

        element() 该方法的行为类似于 peek(),因此它再次检索第一个元素的值而不删除它。然而,与 peek 不同的是,如果列表为空, element() 会抛出 NoSuchElementException。

        poll() 该方法通过从队列中删除队列的第一个元素来检索队列的第一个元素的值。 .在每次调用时,它都会删除列表的第一个元素,如果列表已经为空,则返回 null 但不会引发任何异常。

        remove() 该方法的行为类似于 poll() 方法,因此它会删除列表的第一个元素,如果列表为空,则会抛出 NoSuchElementException

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-01-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-11-30
          相关资源
          最近更新 更多