Respuesta corta: no puedes.
Respuesta un poco más larga:
Necesitará espacio adicional para almacenar la "edad" de su entrada que le permitirá discriminar entre prioridades idénticas. Y necesitará espacio para información que permita inserciones y recuperaciones rápidas. Además de su carga útil (valor y prioridad).Ω ( n )Ω ( n )Ω ( n )
Y, por cada carga útil que almacene, podrá "ocultar" cierta información en la dirección (por ejemplo, significa que Y es anterior a X). Pero en esa información "oculta", ocultará la "edad", O la información de "recuperación rápida". No ambos.a drer ( X) < a drer ( Y)
Respuesta muy larga con pseudo-matemáticas inexactas:
Nota: el final de la segunda parte es incompleto, como se mencionó. Si algún matemático pudiera proporcionar una versión mejor, estaría agradecido.
Pensemos en la cantidad de datos involucrados en una máquina de X bits (digamos 32 o 64 bits), con registros (valor y prioridad) de palabras de máquina ancho.PAGS
Tiene un conjunto de registros potenciales que está parcialmente ordenado: y pero no puede comparar y .( a , 1 ) = ( a , 1 ) ( a , 1 )( a , 1 ) < ( a , 2 )( a , 1 ) = ( a , 1 )( a , 1 )(b,1)
Sin embargo, desea poder comparar dos valores no comparables de su conjunto de registros, en función de cuándo se insertaron. Por lo que tiene aquí otro conjunto de valores: los que se han insertado, y quiere mejorarla con un orden parcial: si y sólo si se insertan antes de .X<YYXY
En el peor de los casos, su memoria se llenará con registros del formulario (con Diferente para cada uno), por lo que tendrá que confiar completamente en el tiempo de inserción para decidir cuál va fuera primero.?(?,1)?
- El tiempo de inserción (en relación con otros registros aún en la estructura) requiere bits de información (con carga útil de byte P y bytes de memoria accesibles).X−log2(P)2X
- La carga útil (el valor y la prioridad de su registro) requiere palabras de información de la máquinaP
Eso significa que de alguna manera debe almacenar bits adicionales de información para cada registro que almacene. Y eso es para registros.O ( n )X−log2(P)O(n)n
Ahora, ¿cuántos bits de información nos proporciona cada "célula" de memoria?
- W bits de datos ( es el ancho de palabra de la máquina).W
- X bits de dirección.
Ahora, supongamos (la carga útil tiene al menos una palabra de máquina de ancho (generalmente un octeto)). Esto significa que , por lo que podemos ajustar la información del orden de inserción en la dirección de la celda. Eso es lo que sucede en una pila: las celdas con la dirección más baja ingresaron primero a la pila (y saldrán al final).X - l o g 2 ( P ) < XP≥1X−log2(P)<X
Entonces, para almacenar toda nuestra información, tenemos dos posibilidades:
- Almacene el orden de inserción en la dirección y la carga útil en la memoria.
- Almacene ambos en la memoria y deje la dirección libre para algún otro uso.
Obviamente, para evitar el desperdicio, usaremos la primera solución.
Ahora para las operaciones. Supongo que deseas tener:
- Insert(task,priority) con complejidad de tiempo.O(logn)
- StableExtractMin() con complejidad de tiempo.O(logn)
Veamos :StableExtractMin()
El algoritmo realmente muy general es así:
- Encuentre el registro con prioridad mínima y "tiempo de inserción" mínimo en .O(logn)
- Eliminarlo de la estructura en .O(logn)
- Devolverlo.
Por ejemplo, en el caso de un montón, se organizará de forma ligeramente diferente, pero el trabajo es el mismo: 1. Busque el registro mínimo en
2. Elimínelo de la estructura en
3. Arregle todo para que la próxima vez # 1 y # 2 sigan siendo es decir, "repare el montón". Esto debe hacerse en "O (log n)" 4. Devuelva el elemento.0(1)O(1)O(1)
Volviendo al algoritmo general, vemos que para encontrar el registro en el tiempo , necesitamos una forma rápida de elegir el correcto entre candidatos (en el peor de los casos, la memoria es lleno).O(logn)2(X−log2(P))
Esto significa que necesitamos almacenar bits de información para recuperar ese elemento (cada bit divide el espacio candidato, por lo que tenemos bisecciones , lo que significa complejidad de tiempo).X−log2(P)O(logn)O(logn)
Estos bits de información pueden almacenarse como la dirección del elemento (en el montón, el mínimo está en una dirección fija) o, por ejemplo, con punteros (en un árbol de búsqueda binario (con punteros), debe seguir en promedio para llegar al mínimo).O(logn)
Ahora, al eliminar ese elemento, necesitaremos aumentar el siguiente registro mínimo para que tenga la cantidad correcta de información para permitir la recuperación de próxima vez, es decir, que tenga bits de información que lo discrimina de los otros candidatos.O(logn)X−log2(P)
Es decir, si no tiene suficiente información, deberá agregar algo. En un árbol de búsqueda binario (no equilibrado), la información ya está allí: tendrá que colocar un puntero NULO en algún lugar para eliminar el elemento, y sin ninguna otra operación, se puede buscar el BST en tiempo en promedio.O(logn)
Después de este punto, es un poco incompleto, no estoy seguro de cómo formular eso. Pero tengo la fuerte sensación de que cada uno de los elementos restantes en su conjunto necesitará tener bits de información que ayudarán a encontrar el próximo minuto y aumentarlo con suficiente información para que pueda encontrarse en hora la próxima vez.O ( l o g n )X−log2(P)O(logn)
El algoritmo de inserción generalmente solo necesita actualizar parte de esta información, no creo que cueste más (en cuanto a memoria) hacer que funcione rápidamente.
Ahora, eso significa que necesitaremos almacenar más bits de información para cada elemento. Entonces, para cada elemento, tenemos:X−log2(P)
- El tiempo de inserción, bits.X−log2(P)
- Las palabras de la máquina carga útil .P
- La información de "búsqueda rápida", bits.X−log2(P)
Como ya usamos el contenido de la memoria para almacenar la carga útil y la dirección para almacenar el tiempo de inserción, no nos queda espacio para almacenar la información de "búsqueda rápida". Así que tendremos que asignar algo de espacio extra para cada elemento, y así "desperdiciar" espacio extra.Ω(n)