¿Se pueden implementar tres pilas en una matriz, con O (1) tiempo push / pop?

9

Se pueden implementar de manera eficiente dos pilas usando una matriz de tamaño fijo: la pila # 1 comienza desde el extremo izquierdo y crece hacia la derecha, y la pila # 2 comienza desde el extremo derecho y crece hacia la izquierda. ¿Es lo mismo posible para tres pilas?

Más específicamente, es posible implementar tres pilas dadas las siguientes condiciones:

  1. Tiene una matriz de tamaño fijo que puede contener N objetos.
  2. Mientras la suma de los tres tamaños de pila sea <N, push () no debería fallar.
  3. Ambas operaciones push () y pop () deberían tomar tiempo O (1).
  4. Además de la matriz, puede usar solo O (1) espacio adicional.

Aquí hay ejemplos de soluciones que no satisfacen estos requisitos:

  • Dividir la matriz en 3 partes fijas y usar cada parte para una pila (viola 2).
  • Similar a lo anterior pero con límites móviles entre las pilas (viola 3).
  • Implementaciones simples basadas en listas vinculadas (viola 4).

Aceptaré algoritmos no triviales o pruebas de imposibilidad incluso si no cumplen con todas las condiciones (1) - (4) exactamente, por ejemplo, un algoritmo donde push / pop toma O (1) tiempo amortizado, o donde el la memoria adicional es menor que O (N), por ejemplo, O (log N). O una prueba de imposibilidad que muestra que, por ejemplo, es imposible acceder a menos de 5 elementos de la matriz por push / pop.

usuario1020406
fuente
1
No sé si considera esto como una violación del requisito 4, pero si cada "objeto" en su matriz de N objetos puede incluir un campo adicional como un índice entero, puede implementar las "listas vinculadas" dentro de su matriz . Puede mantener el índice de la parte superior de cada una de las 3 pilas usando 3 variables externas, y cada "objeto" puede apuntar al elemento anterior en su pila.
Avi Tal
Por "objetos" me refería a cosas que push () acepta y pop () devuelve. Desde el punto de vista de la implementación de la pila, son solo bloques de datos opacos (por ejemplo, un objeto podría ser un entero de 32 bits). La implementación de la pila no debe modificar estos objetos de ninguna manera.
user1020406
1
Considere que primero realiza una secuencia de operaciones de inserción y luego solo realiza operaciones pop. ¿Se sabe algo sobre esta versión del problema? norte
Dmitri Urbanowicz
¿ de espacio adicional te satisface? O(norte)
Dmitri Urbanowicz
Re: Versión "N empuja y luego N estalla": No lo sé, pero incluso identificar esto como un subproblema interesante es útil porque incluso allí no está claro si una solución O (1) es posible. Vea la respuesta de @ Alexei y su hilo de comentarios para el límite superior. En cuanto a un solución, sí, lo aceptaré. Soy nuevo en la publicación de preguntas sobre stackexchange, por lo que no estoy seguro de cómo manejar los casos en los que se pueden proporcionar mejores y mejores soluciones con el tiempo. Un enfoque que he visto es esperar un día más o menos antes de aceptar una respuesta en caso de que se publique algo mejor, así que lo haré. O(norte)
user1020406

Respuestas:

6

Θ(norteε)Θ(norte) nortenorte

jbapple
fuente
0

Deje que N sea la longitud de la matriz subyacente. Puedo imaginar pilas como listas enlazadas de fragmentos grandes, de modo que el número total de fragmentos no sea más que O (log2 (N)). Coloque la tercera pila entre las dos primeras, en el índice de N / 2. Entonces tenemos 3 áreas ocupadas y 2 libres. Cuando una pila no puede aceptar el siguiente elemento, esto significa que un área libre está agotada. Si el otro también está agotado, entonces toda la memoria está agotada. De lo contrario, hay otra área libre con un tamaño no mayor a N / 2. Continúa la pila desbordada en esa área libre. para que toda la configuración se parezca al diseño inicial de las pilas. Como la memoria libre ahora no es más que la mitad de la inicial, no habrá más que log2 (N) de tales operaciones de enlace. Cada operación de enlace requiere una cantidad fija de memoria para guardar el estado anterior de la pila. Entonces,

Alexei Kaigorodov
fuente
1
¿Cómo recicla la memoria obtenida haciendo estallar cosas de uno de los trozos grandes?
Emil Jeřábek
Buena pregunta. La respuesta rápida es que el fragmento que se vuelve libre devuelve su memoria al área libre de donde fue tomado previamente. Pero, ¿qué pasa si el área libre se redujo desde el momento de la memoria de asignación para ese fragmento, y el fragmento ahora no es adyacente? Esto conduce a la fragmentación de la memoria libre, puede haber más de 2 áreas libres, lo que arruina toda mi construcción.
Alexei Kaigorodov
De hecho, el problema es el estallido, pero la construcción de Alexei proporciona un buen límite superior para la versión del problema que Dmitri preguntó en los comentarios: ¿qué pasa si necesitamos que todos los empujes sucedan antes de que aparezcan? Me pregunto si es posible algo mejor que O (log N) en este caso.
user1020406