优先级队列中的排序与未排序数据为什么un自动排序并排序等待?

时间:2013-05-28 14:26:47

标签: java heap priority-queue

据我所知,min heap是该类使用的结构,因为它的效率。在我看来,当未分类的数据被提供给PQ时,它将它分类到堆中。

但是当根据compareTo方法向升序元素提供它时,它等待在PQ上执行第一个操作后将其排序到堆中。

你知道为什么吗?我不明白为什么它不会像无序数据那样自动排序。

我附上了一个我认为可以证明我的问题的程序。

输出:

未分类的数据:

  

[A,B,D,C,L,F,E,J]

     

A

     

[B,C,D,J,L,F,E]

     

[1,2,4,3,12,6,5,10]

     

1

     

[2,3,4,10,12,6,5]

排序数据:

  

[A,B,C,D,E,F,G,H]

     

A

     

[B,D,C,H,E,F,G]

     

[1,2,3,4,5,6,7,8]

     

1

     

[2,4,3,8,5,6,7]

import java.util.PriorityQueue;

public class Queue2
{
    public static void main(String[] args)
    {
        PriorityQueue<String> pQueue = new PriorityQueue<String>();

        pQueue.add("A");
        pQueue.add("C");
        pQueue.add("F");
        pQueue.add("B");
        pQueue.add("L");
        pQueue.add("D");
        pQueue.add("E");
        pQueue.add("J");
        System.out.println(pQueue); 
        System.out.println(pQueue.remove());
        System.out.println(pQueue);

        System.out.println();

        PriorityQueue<Integer> pQueue2 = new PriorityQueue<Integer>();

        pQueue2.add(1);
        pQueue2.add(3);
        pQueue2.add(6);
        pQueue2.add(2);
        pQueue2.add(12);
        pQueue2.add(4);
        pQueue2.add(5);
        pQueue2.add(10);
        System.out.println(pQueue2); 
        System.out.println(pQueue2.remove());
        System.out.println(pQueue2);

        System.out.println();

        PriorityQueue<String> pQueue3 = new PriorityQueue<String>();

        pQueue3.add("A");
        pQueue3.add("B");
        pQueue3.add("C");
        pQueue3.add("D");
        pQueue3.add("E");
        pQueue3.add("F");
        pQueue3.add("G");
        pQueue3.add("H");
        System.out.println(pQueue3); 
        System.out.println(pQueue3.remove());
        System.out.println(pQueue3);

        System.out.println();

        PriorityQueue<Integer> pQueue4 = new PriorityQueue<Integer>();

        pQueue4.add(1);
        pQueue4.add(2);
        pQueue4.add(3);
        pQueue4.add(4);
        pQueue4.add(5);
        pQueue4.add(6);
        pQueue4.add(7);
        pQueue4.add(8);
        System.out.println(pQueue4); 
        System.out.println(pQueue4.remove());
        System.out.println(pQueue4);

    }
}

2 个答案:

答案 0 :(得分:2)

来自PriorityQueue

的文档
  
    

此队列的头部是指定排序的最小元素。如果多个元素绑定的值最小,则头部是其中一个元素 - 关系会被任意破坏。队列检索操作轮询,删除,查看和元素访问队列头部的元素。

  

并且

  
    

此类及其迭代器实现Collection和Iterator接口的所有可选方法。 方法iterator()中提供的迭代器不保证以任何特定顺序遍历优先级队列的元素。如果需要有序遍历,请考虑使用Arrays.sort(pq.toArray())。

  

这就是为什么当你打印队列(使用System.out)时,会使用内部迭代器,因此没有排序输出的保证......但如果多次使用poll(),你肯定会看到返回的对象两种情况下的有序方式

答案 1 :(得分:0)

所以你知道队列中有一个(二进制)堆,对吗?堆应该遵循两个properties

  • shape属性:树是一个完整的二叉树;也就是说,树的所有级别,除了最后一个(最深)之外都是完全填充的,如果树的最后一级没有完成,那么该级别的节点将从左到右填充。
  • 堆属性:根据为数据结构定义的比较谓词,每个节点大于或等于其子节点。

那么元素是如何插入的?只需做一个BFS,直到你找到一个空位(把元素放在那个位置),或者找到另一个比当前元素大的元素(用新元素替换那个元素并继续使用更大的元素)。

让我们通过两个例子来解决。我将逐级编写树,因此[A][BC][D---]表示以A为根,BCA的树,和D B的孩子。

让我们看一下第一个例子:[A, C, F, B, L, D, E, J]。这就是堆增长的方式:

[A]
[A][C-]
[A][CF]
[A][BF][C---]
[A][BF][CL--]
[A][BD][CLF-]
[A][BD][CLFE]
[A][BD][CLFE][J-------]

现在看看你的排序示例:[A, B, C, D, E, F, G, H]。这就是堆增长的方式:

[A]
[A][B-]
[A][BC]
[A][BC][D---]
[A][BC][DE--]
[A][BC][DEF-]
[A][BC][DEFG]
[A][BC][DEFG][H-------]

实际上,底层数组按排序顺序包含所有元素。


那么,为什么在删除第一个元素时这个顺序会失真?为了满足两个堆属性,空白点重复填充该点的最小子节点。

让我们看一下删除A后的最后一个例子(我用*标记空白点):

[*][BC][DEFG][H-------]
[B][*C][DEFG][H-------]
[B][DC][*EFG][H-------]
[B][DC][HEFG]

这也与您提供的输出相对应。