Stacks y Estructuras LIFO: Implementación y casos de uso

Con estos importantes métodos explicados, echemos un vistazo a la implementación final de nuestra clase Stack:

Los métodos push y pop aparecen exactamente como esperamos (líneas 13-32). Podemos usar nuestro método push para crear un inicializador personalizado con algunos valores variádicos (líneas 7-11). Además, podemos comprobar si hay una pila vacía comprobando si nuestro rootNode tiene un valor (líneas 34-36) y tiene un método de impresión básico que itera a través de nuestra lista, siempre y cuando sea capaz de acceder a los nodos a través de la siguiente propiedad (líneas 38-44).

Una prueba básica de la funcionalidad de nuestra pila se ve así:

Saber cómo implementar una pila es una cosa, pero aún más importante es reconocer situaciones para las que una pila es adecuada. En la siguiente sección veremos tres de estos casos.

Caso de uso 1: Orden inverso

Debido a que el orden de una pila es fijo, el orden inverso se puede lograr muy fácilmente haciendo estallar elementos de una pila e inmediatamente en otra. ¡Sin jugar con los índices de intercambio!

Caso de uso 2: Prueba de simetría

Otro buen caso de uso para pilas es probar simetría. En el siguiente ejemplo, estamos probando una cadena de soportes para asegurarnos de que cada soporte de cierre sea la contraparte correcta de un soporte de apertura anterior.

Comenzamos comprobando que el recuento de caracteres es divisible por dos, ya que un número impar de caracteres sería inmediatamente asimétrico (línea 6). A continuación, comprobamos que tenemos una entrada válida definiendo un conjunto de caracteres ilegales y luego comprobamos que nuestra cadena de entrada tiene un rango nulo de caracteres ilegales (líneas 7-8). Para comprobar que nuestros corchetes de cierre y apertura coinciden, los colocamos en un diccionario como pares clave-valor (línea 10). En otras situaciones, es posible que pueda calcular el valor inverso sin tener que almacenar pares en un diccionario. Luego tenemos nuestra pila (línea 11). El propósito de nuestra pila en este caso es almacenar los soportes de apertura. A medida que repasamos nuestra cadena, podemos comprobar si nuestro carácter es un corchete de apertura probando si es una clave en nuestro diccionario. Si lo es, lo empujamos a nuestra pila. Una vez que encontramos nuestro primer corchete cerrado, sabemos que estamos trabajando en la segunda mitad de nuestro patrón, por lo que establecemos nuestro primer medio booleano en falso (línea 12). Si encontramos más corchetes de apertura después de este punto, podemos comprobar el booleano e indicar una prueba fallida. Para cada soporte de cierre, sacamos el último soporte de apertura y comprobamos si son un par clave-valor correcto. Una vez más, solo necesitamos iterar a través de la cadena una vez, por lo que estamos obteniendo mucho valor de un algoritmo lineal.

Caso de uso 3: Deshacer comandos

Finalmente, usaremos una pila junto con el patrón de comandos para crear un historial de deshacer. Para empezar, echemos un vistazo a un objeto de cuenta bancaria simple. Tiene un saldo y un límite de sobregiro y algunos métodos simples para depositar y retirar fondos:

En lugar de llamar directamente a los métodos de depósito y retiro, podemos almacenar la información relevante en un comando. En el fragmento de código a continuación, especificamos qué tipo de acción queremos realizar con una propiedad de enumeración (depósito o retiro) y una cantidad . También almacenamos un booleano para indicar si el comando se pudo ejecutar (líneas 4-11). Tenga en cuenta que si la solicitud de retiro excede el límite de sobregiro, no le pasará nada a la cuenta bancaria y el booleano exitoso permanecerá falso, de lo contrario se volverá verdadero una vez que se complete el comando (líneas 18-26). Tenemos dos métodos para llamar o deshacer el comando, cada uno tomando una cuenta bancaria como argumento (líneas 18 & 28). Estos métodos toman la cuenta bancaria y llaman a sus métodos de instancia que vimos en el fragmento anterior.

Volviendo a la cuenta bancaria, ahora podemos introducir nuestra propiedad commandStack, que se ha inicializado con nuestro BankAccountType (línea 47). Marcamos nuestros métodos de depósito y retiro como fileprivate para que solo pueda acceder a ellos nuestro comando de cuentas bancarias (líneas 62 & 66). Ahora tenemos dos métodos expuestos: process (command:) y undoLastCommand (). El primero acepta un comando como entrada, lo ejecuta con la cuenta bancaria como entrada, y luego empuja el comando a la pila. Mientras tanto, el método undoLastCommand, saca el último comando de la pila y realiza un deshacer (líneas 51-60).

Este es un patrón muy simple, y uno que es muy poderoso. Las aplicaciones posibles son infinitas y ofrecen una experiencia de usuario satisfactoria.

Y ahora veamos el patrón en acción:

Wrap Up

En este artículo, exploramos el concepto de pila y el comportamiento LIFO. Implementamos nuestra propia pila utilizando una lista doblemente vinculada y demostramos cómo asigna y desasignauna memoria a medida que cambia el tamaño de la pila. También analizamos tres casos de uso comunes para pilas: invertir, probar simetría y deshacer. Cada una de estas tres situaciones surgen innumerables veces en proyectos del mundo real. Espero que piense en una pila como una estructura apropiada para manejar esas necesidades. Como siempre, gracias por leer!

Deja una respuesta

Tu dirección de correo electrónico no será publicada.

More: