2011-11-14 106 views
18
for (Event e : pq) 

no itera en el orden de prioridad.¿Cómo iterar sobre PriorityQueue?

while(!pq.isEmpty()){ 
    Event e = pq.poll(); 
} 

Esto funciona pero vacía la cola.

+1

¿Cómo es que vacía la cola? 'peek()' no elimina elementos. –

+2

'peek()' no debería eliminar el objeto –

+4

peek() continúa volviendo el cabezal – simpatico

Respuesta

19

Desde el Javadocs:

The Iterator provided in method iterator() is not guaranteed to traverse the elements of the PriorityQueue in any particular order. If you need ordered traversal, consider using Arrays.sort(pq.toArray()) .

Probablemente hay otros mecanismos equivalentes.

+6

Esta respuesta se beneficiaría de un ejemplo. 'Arrays.sort (pq.toArray())' no hace nada por lo que yo sepa. En primer lugar, debe crearse una matriz que contenga los elementos de 'PriorityQueue', luego se puede ordenar dicha matriz usando' Arrays.sort (theActualArray, pq.comparer()) '. – Madmenyo

0

El método peek() no elimina nada de la cola, pero debido a esto, continuamente obtendrá el valor superior hasta que esté vacío. Supongo que verificó si estaba vacío después de su ciclo while, lo que le daría esta conclusión.

La única forma de hacerlo es ordenarlo usted mismo. se puede obtener el comparador original para de esta manera:

Event[] events = Arrays.sort(pq.toArray(), pq.comparator()); 
for (Event e : events) { 
    // do stuff 
} 
+0

Esto es lo mismo que el ejemplo original de OP. –

+0

+1 para mostrar un ejemplo completo – Webnet

+0

Desde entonces, aprendí que este ejemplo no es la mejor ruta. Usando un 'comparador', uno no necesita convertir la cola a una matriz. 'for (Evento e: pq) {' debería hacer el trabajo. – Webnet

8

Una cola de prioridad basada en el montón solo garantiza que el primer elemento sea el más alto/más bajo. No hay forma barata (es decir, O (n)) de obtener los elementos en forma ordenada.

Si necesita hacer esto a menudo, considere usar una estructura que mantenga los elementos en forma ordenada. Por ejemplo, utilice java.util.TreeSet, y utilizar cualquiera pollFirst() o pollLast() en lugar de peek()/poll()

16

No se puede atravesar una cola de prioridad en ese orden, debido a la implementación subyacente (creo que es min en heap en Java). No es una matriz ordenada, por lo que puede pasar de un elemento a otro con menor prioridad. Leer a escondidas es un tiempo constante porque mira el elemento más pequeño. Para obtener el siguiente (en el tiempo O (log n)) debe dequeue el elemento más pequeño, así es como funciona. Dequeing no es solo una cuestión de sacar ese elemento, la estructura subyacente se reorganiza a sí misma para traer el elemento con la menor prioridad primero.

Además, para pasar por la cola de prioridad completa es una operación O (n log (n)). De modo que también puede tomar todos los elementos de la cola y ordenarlos (también O (n log (n))) y luego puede revisarlos como lo desee. La única desventaja es que tiene una copia extra de la cola.

Sin embargo, si necesita recorrer los datos de esta manera, una cola de prioridad puede no ser la estructura de datos correcta para sus necesidades.

+0

Entonces 'PriorityQueue' es bastante inútil, entonces? – Qix

+4

En absoluto, es increíblemente útil y está muy bien optimizado para lo que realmente debe hacer. Es más rápido de crear que una estructura de datos totalmente ordenada (lineal frente a O (n log n)), pero aún se puede encontrar el mínimo/máximo en tiempo constante y en cola/dequeue en log n. Simplemente no es la estructura de datos correcta si necesita iterar en orden ordenado sobre todos los elementos. –

+0

Justo, aunque llegaría a decir que tiene usos bastante limitados/específicos. – Qix

0

Recientemente, tuve el mismo problema. Quería usar algún objeto particular de la cola de prioridad y luego conservar los elementos restantes.

1) Creé una nuevaPriorityQueue. 2) Iterator usado para analizar cada elemento en oldQueue 3) método oldQueue.poll() utilizado para recuperar el elemento 4) inserte el elemento 3) en newPriorityQueue si no se utiliza.

Queue<String> newQueue = new PriorityQueue<String>(); 
    // Assuming that oldQueue have some data in it. 

    Iterator<String> itr = oldQueue.iterator(); 
    while(itr.hasNext()){ 
     String str = oldQueue.poll(); 
     // do some processing with str 
     if(strNotUsed){ 
      newQueue.offer(str); 
     } 
    } 

Al final, oldQueue estará vacio. @ Otros: - sugiera una forma mejor si puedo hacer lo mismo. No puedo usar el iterador ya que no devuelve elementos en el orden correcto.

0

Se puede hacer una copia de la cola y sondeo en un bucle, en este ejemplo pq es la cola de prioridad original:

PriorityQueue<Your_class> pqCopy = new PriorityQueue<Your_class>(pq); 
while(!pqCopy.isEmpty()){ 
    Your_Class obj = pqCopy.poll(); 
    // obj is the next ordered item in the queue 
    ..... 
} 
-1
for (Event event: pq.toArray(new Event[pq.size()])) { 
    event.toString(); 
} 
+0

Por favor, edite su respuesta para agregar alguna explicación. Las respuestas de solo código hacen muy poco para educar a los futuros lectores de SO. Su respuesta está en la cola de moderación por ser de baja calidad. – mickmackusa

+0

Su código no resuelve el problema. La matriz se debe ordenar antes de la iteración. – Nolequen

0

Así que teniendo la PriorityQueue en una lista y luego la clasificación es una buena opción como se menciona arriba. Aquí hay algunos detalles de por qué el iterador proporciona resultados inesperados:

El iterador no devuelve elementos en el orden correcto porque se imprime desde la estructura de datos subyacente (similar a ArrayList). ArrayList tiene datos almacenados en él de la misma manera que los datos se almacenan en una implementación Array de BinaryHeap. Por ejemplo:

PriorityQueue<Integer> pq = new PriorityQueue<>(); 
ArrayList<Integer> test = new ArrayList(Arrays.asList(6,12,7,9,2)); 
test.forEach(x -> pq.add(x)); 
System.out.println("Priority Queue:- "+pq); [2, 6, 7, 12, 9] 

donde childOf (i) es 2 * i + 1 y 2 * i + 2 y parentOf (i) es (i-1)/2