2010-02-18 9 views
14

Necesito implementar una cola de prioridad donde la prioridad de un elemento en la cola puede cambiar y la cola se ajusta para que los elementos siempre se eliminen en el orden correcto. Tengo algunas ideas de cómo podría implementar esto, pero estoy seguro de que esta es una estructura de datos bastante común, así que espero poder usar una implementación de alguien más inteligente que yo como base.Cola de prioridad con prioridades de elementos dinámicos

¿Alguien me puede decir el nombre de este tipo de cola de prioridad así que sé qué buscar o, mejor aún, señalarme una implementación?

+0

Ver http://stackoverflow.com/questions/927631/is-there-a-heap-class-in-c-hat-supports-changing-the-priority-of-elements-othe y http: // stackoverflow.com/questions/450180/a-priority-queue-which-allows-efficient-priority-update –

Respuesta

2

Yo sugeriría tratando primero el acercamiento de frente en, para actualizar una prioridad:

  • eliminar el elemento de la cola
  • Reinsértela con la nueva prioridad

En C++, esto podría hacerse usando un std::multi_map, lo importante es que el objeto debe recordar dónde está almacenado en la estructura para poder eliminarse de manera eficiente. Para volver a insertarlo, es difícil ya que no puede presumir que sabe algo sobre las prioridades.

class Item; 

typedef std::multi_map<int, Item*> priority_queue; 

class Item 
{ 
public: 
    void add(priority_queue& queue); 
    void remove(); 

    int getPriority() const; 
    void setPriority(int priority); 

    std::string& accessData(); 
    const std::string& getData() const; 

private: 
    int mPriority; 
    std::string mData; 

    priority_queue* mQueue; 
    priority_queue::iterator mIterator; 
}; 

void Item::add(priority_queue& queue) 
{ 
    mQueue = &queue; 
    mIterator = queue.insert(std::make_pair(mPriority,this)); 
} 

void Item::remove() 
{ 
    mQueue.erase(mIterator); 
    mQueue = 0; 
    mIterator = priority_queue::iterator(); 
} 

void Item::setPriority(int priority) 
{ 
    mPriority = priority; 
    if (mQueue) 
    { 
    priority_queue& queue = *mQueue; 
    this->remove(); 
    this->add(queue); 
    } 
} 
+0

Gracias Matthieu, pensé en utilizando ese enfoque, pero debido a la frecuencia de la actualización no fue lo suficientemente eficiente para mis necesidades. Terminé usando una implementación que incluía elementos de mapeo del diccionario en sus índices en la cola, y luego tenía un método en la cola, UpdatePosition (Elemento del artículo), que buscaba el índice de artículos y luego lo convertía en su nueva posición. La cola tiene un evento que los elementos registran para que notifiquen a la cola cuando cambian sus prioridades. Eso parece funcionar bien. – sean

0

Google has a number of answers para usted, incluyendo una implementación de one in Java.

Sin embargo, esto suena como un problema de tarea, así que si es así, sugiero tratar primero de resolver las ideas tú mismo, y luego hacer referencia a la implementación de otra persona si te quedas atascado y necesitas un puntero en la dirección correcta. De esta forma, es menos probable que esté "predispuesto" hacia el método de codificación preciso utilizado por el otro programador y más probable que comprenda por qué se incluye cada fragmento de código y cómo funciona. A veces puede ser un poco tentador hacer el equivalente parafraseante de "copiar y pegar".

+1

Gracias Dav, pero esta es una cola de prioridad estándar. Si agrego un elemento a la cola y se cambia su prioridad (fuera de la cola), el orden de la cola puede ser incorrecto. En otras palabras, una cola de prioridad estándar solo ordena elementos cuando se agregan a la cola y no más tarde. Necesito implementar una cola que se actualice como la prioridad de sus actualizaciones de elementos. P.S. No es un problema de tarea, necesito implementar esto como parte de algún software de simulación. Tengo algunas ideas de cómo puedo implementarlo, pero quiero ver si hay una mejor manera de hacerlo. – sean

+0

Ah. Bueno. En ese caso, sugeriría buscar ejemplos de implementaciones del algoritmo de Dijkstra, que (si se implementa en su forma más eficiente) requiere una cola de prioridad reordenable, y por lo tanto, probablemente debería tener lo que está buscando. – Amber

5

Un montón binario estándar compatible con 5 operaciones (el ejemplo a continuación asumir un montón max):

* find-max: return the maximum node of the heap 
* delete-max: removing the root node of the heap 
* increase-key: updating a key within the heap 
* insert: adding a new key to the heap 
* merge: joining two heaps to form a valid new heap containing all the elements of both. 

Como se puede ver, en un montón max, puede aumentar una clave arbitraria. En un montón mínimo, puede disminuir una clave arbitraria. No se puede cambiar las llaves en ambos sentidos, lamentablemente, pero ¿lo hará? Si necesita cambiar las claves en ambos sentidos, entonces quizás quiera pensar en usar un min-max-heap.

+0

No veo cómo un montón binario podría admitir eficientemente la tecla aumentar si primero necesita buscar el elemento que desea aumentar. Como no hay orden en el montón, tomará tiempo lineal encontrar el elemento. – wcochran

+2

Debe tener una referencia al elemento para hacer que la tecla aumentar y disminuir la tecla sea eficiente. Esto se implementa con identificadores en la biblioteca Boost.Heap C++ http://www.boost.org/doc/libs/1_55_0/doc/html/heap/concepts.html#heap.concepts.mutability – lazd

0

¡Estoy buscando exactamente lo mismo!

Y aquí es un poco de mi idea:

  1. Dado que una prioridad de un elemento cambia constantemente, no tiene sentido para ordenar la cola antes de recuperar un elemento.
  2. Por lo tanto, debemos olvidarnos de utilizar una cola de prioridad. Y clasifique "parcialmente" el contenedor mientras recupera un artículo.

Y elija entre los siguientes algoritmos de ordenación STL: a. partición b. stable_partition c. nth_element d. partial_sort e. partial_sort_copy f. ordenar g.stable_sort

partition, stable_partition y nth_element son algoritmos de ordenamiento en tiempo lineal, que deberían ser nuestras primeras elecciones.

PERO, parece que no hay esos algoritmos en la biblioteca oficial de Java. Como resultado, le sugiero que use java.util.Collections.max/min para hacer lo que quiera.

7

Las colas de prioridad como esta se implementan típicamente utilizando una estructura de datos de montón binario como sugirió otra persona, que generalmente se representa utilizando una matriz pero también podría usar un árbol binario. En realidad, no es difícil aumentar o disminuir la prioridad de un elemento en el montón. Si sabe que está cambiando la prioridad de muchos elementos antes de que salga el siguiente elemento de la cola, puede desactivar temporalmente el reordenamiento dinámico, insertar todos los elementos al final del montón y luego reordenar todo el montón (a un costo de O (n)) justo antes de que el elemento deba saltar. Lo importante de montones es que solo cuesta O (n) colocar una matriz en orden de pila pero O (n log n) para ordenarla.

He utilizado este enfoque con éxito en un proyecto grande con prioridades dinámicas.

Aquí está mi implementación de un priority queue implementation in the Curl programming language parametrizado.

Cuestiones relacionadas