Comprender la implementación de la pila en Python

Las estructuras de datos juegan un papel clave en el mundo de la programación. Nos ayudan a organizar nuestros datos de una manera que se puede utilizar de manera eficiente. La pila es una de las estructuras de datos más simples.

Aprendamos sobre la pila y su implementación en Python.

¿Qué es una pila?

Una pila es similar a la pila de libros, sillas, etc., en la vida real. Y sigue el principio Last-in/First-out (LIFO). Es la estructura de datos más simple. Veamos el escenario con un ejemplo del mundo real.

Digamos que tenemos una pila de libros de la siguiente manera.

Cuando queremos el tercer libro desde arriba, tenemos que quitar los dos primeros libros desde arriba para sacar el tercer libro. Aquí, el libro de arriba va último en la pila y es el primero de la pila. La pila de estructura de datos sigue el mismo principio Last-in/First-out (LIFO) en la programación.

Operaciones en la pila

Hay principalmente dos operaciones en una pila.

1. empujar (datos)

Agrega o inserta los datos en la pila.

2. estallar()

Elimina o extrae el elemento superior de la pila.

Consulte las siguientes ilustraciones de las operaciones de empujar y abrir.

Escribiremos algunas funciones auxiliares que nos ayuden a obtener más información sobre la pila.

Veámoslos.

ojeada()

Devuelve el elemento superior de la pila.

esta vacio()

Devuelve si la pila está vacía o no.

Suficientes aspectos conceptuales de la estructura de datos de la pila. Pasemos a la implementación sin más preámbulos.

Supongo que tiene Python instalado en su PC, si no, también puede probar el compilador en línea.

Implementación de pila

La implementación de la pila es la más fácil en comparación con otras implementaciones de estructuras de datos. Podemos implementar una pila de varias formas en Python.

Vamos a verlos todos uno por uno.

#1. Lista

Vamos a implementar la pila usando la lista en una clase. Veamos la implementación paso a paso de la pila.

Paso 1: escribe una clase llamada Stack.

class Stack:
	pass

Paso 2: Tenemos que mantener los datos en una lista. Agreguemos una lista vacía en la clase Stack con elementos de nombre.

class Stack:
	def __init__(self):
		self.elements = []

Paso 3: Para empujar los elementos a la pila, necesitamos un método. Escribamos un método push que tome datos como argumento y los agreguemos a la lista de elementos.

class Stack:
	def __init__(self):
		self.elements = []

	def push(self, data):
		self.elements.append(data)
		return data

Paso 4: Del mismo modo, escribamos el método pop que extrae el elemento superior de la pila. Podemos usar el método pop del tipo de datos de lista.

class Stack:
	## ...
	def pop(self):
		return self.elements.pop()

Hemos completado la implementación de la pila con las operaciones requeridas. Ahora, agreguemos las funciones auxiliares para obtener más información sobre la pila.

Paso 5: podemos obtener el elemento superior de la pila usando el índice negativo. El código elemento[-1] devuelve el último de la lista. Es el elemento superior de la pila en nuestro caso.

class Stack:
	## ...

	def peek(self):
		return self.elements[-1]

Paso 6: si la longitud de la lista de elementos es 0, entonces la pila está vacía. Escribamos un método que devuelva si el elemento está vacío o no.

class Stack:
	## ...
	def is_empty(self):
		return len(self.elements) == 0

Hemos completado la implementación de la pila utilizando el tipo de datos de lista.

¡Vaya! espera, acabamos de implementarlo. Pero, no vi cómo usarlo. ¿Cómo usarlo entonces?

Ven vamos a ver cómo implementarlo. Tenemos que crear un objeto para que la clase Stack lo use. No es gran cosa. Hagámoslo primero.

class Stack: 
    ## ...

if __name__ == '__main__':
    stack = Stack()

Hemos creado el objeto de pila y estamos listos para usarlo. Sigamos los pasos a continuación para probar las operaciones de la pila.

  • Compruebe si la pila está vacía o no utilizando el método is_empty. Debería devolver True.
  • Empuje los números 1, 2, 3, 4, 5 en la pila utilizando el método de inserción.
  • El método is_empty debería devolver False. Revisalo.
  • Imprime el elemento superior usando el método de vista.
  • Saca el elemento de la pila usando el método pop.
  • Compruebe el elemento de vista. Debería devolver el elemento 4.
  • Ahora, saque todos los elementos de la pila.
  • El método is_empty debería devolver True. Revisalo.

Nuestra implementación de pila se completa si pasa todos los pasos anteriores. Intente escribir el código para los pasos anteriores.

¿Escribiste el código? No, no te preocupes, revisa el código a continuación.

class Stack: 
    def __init__(self): 
        self.elements = [] 
    
    def push(self, data): 
        self.elements.append(data) 
        return data 
    
    def pop(self): 
        return self.elements.pop() 
        
    def peek(self): 
        return self.elements[-1] 
        
    def is_empty(self): 
        return len(self.elements) == 0

if __name__ == '__main__':
    stack = Stack()
    
    ## checking is_empty method -> true
    print(stack.is_empty())

    ## pushing the elements
    stack.push(1)
    stack.push(2)
    stack.push(3)
    stack.push(4)
    stack.push(5)

    ## again checking is_empty method -> false
    print(stack.is_empty())

    ## printing the topmost element of the stack -> 5
    print(stack.peek())

    ## popping the topmost element -> 5
    stack.pop()

    ## checking the topmost element using peek method -> 4
    print(stack.peek())

    ## popping all the elements
    stack.pop()
    stack.pop() 
    stack.pop() 
    stack.pop() 

    ## checking the is_empty method for the last time -> true
    print(stack.is_empty())

¡Viva! Hemos completado la implementación de la pila desde cero utilizando el tipo de datos de lista. Verá el resultado como se menciona a continuación si ejecuta el código anterior.

True
False
5
4
True

Podemos usar directamente el tipo de datos de lista como una pila. La implementación anterior de la pila también lo ayuda a comprender la implementación de la pila en otros lenguajes de programación.

También puede consultar esta lista de artículos relacionados.

Veamos el deque integrado del módulo integrado de colecciones que puede actuar como una pila.

#2. deque de colecciones

Se implementa como una cola de dos extremos. Ya que admite la adición y eliminación de elementos de ambos extremos. Por lo tanto, podemos usarlo como una pila. Podemos hacer que siga el principio LIFO de la pila.

Se implementa utilizando otras estructuras de datos denominadas listas doblemente enlazadas. Entonces, el rendimiento de la inserción y eliminación de elementos es consistente. Acceder a los elementos de la lista enlazada del medio tomó O(n) tiempo. Podemos usarlo como una pila, ya que no es necesario acceder a los elementos intermedios de la pila.

Antes de implementar la pila, veamos los métodos que se usan para implementar la pila usando la cola.

  • agregar (datos): se usa para enviar los datos a la pila
  • pop(): se usa para eliminar el elemento superior de la pila

No hay métodos alternativos para peek e is_empty. Podemos imprimir toda la pila en lugar del método de vistazo. A continuación, podemos usar el método len para verificar si la pila está vacía o no.

Implementemos la pila usando deque del módulo de colecciones.

from collections import deque

## creating deque object
stack = deque()

## checking whether stack is empty or not -> true
print(len(stack) == 0)

## pushing the elements
stack.append(1)
stack.append(2)
stack.append(3)
stack.append(4)
stack.append(5)

## again checking whether stack is empty or not -> false
print(len(stack) == 0)

## printing the stack
print(stack)

## popping the topmost element -> 5
stack.pop()

## printing the stack
print(stack)

## popping all the elements
stack.pop()
stack.pop() 
stack.pop() 
stack.pop() 

## checking the whether stack is empty or not for the last time -> true
print(len(stack) == 0)

Eso es todo. Hemos aprendido cómo implementar la pila usando el deque del módulo integrado de colecciones. Obtendrá el resultado como se menciona a continuación si ejecuta el programa anterior.

True
False
deque([1, 2, 3, 4, 5])
deque([1, 2, 3, 4])
True

Hasta ahora, hemos visto dos formas de implementar la pila. ¿Hay otras formas de implementar una pila? ¡Sí! Veamos la forma final de implementar una pila en este tutorial.

#3. LifoQueue

El propio nombre LifoQueue dice que sigue el principio LIFO. Por lo tanto, podemos usarlo como una pila sin ninguna duda. Es de la cola del módulo incorporado. LifoQueue proporciona algunos métodos prácticos que son útiles en la implementación de la pila. vamos a verlos

  • put (datos): agrega o empuja los datos a la cola
  • get (): elimina o saca el elemento superior de la cola
  • vacío () – devuelve si la pila está vacía o no
  • qsize() – devuelve la longitud de la cola

Implementemos la pila usando LifoQueue desde el módulo de cola.

from queue import LifoQueue

## creating LifoQueue object
stack = LifoQueue()

## checking whether stack is empty or not -> true
print(stack.empty())

## pushing the elements
stack.put(1)
stack.put(2)
stack.put(3)
stack.put(4)
stack.put(5)

## again checking whether stack is empty or not -> false
print(stack.empty())

## popping all the elements
print(stack.get())
print(stack.get())
print(stack.get())

## checking the stack size
print("Size", stack.qsize())

print(stack.get())
print(stack.get())

## checking the whether stack is empty or not for the last time -> true
print(stack.empty())

Obtendrá el resultado mencionado a continuación si ejecuta el programa anterior sin cambiarlo.

True
False
5
4
3
Size 2
2
1
True

Aplicación de pila

Ahora, tiene suficiente conocimiento sobre pilas para aplicarlo en problemas de programación. Veamos un problema y resolvámoslo usando una pila.

Dada una expresión, escriba un programa para verificar si los paréntesis, las llaves, las llaves están balanceadas correctamente o no.

Veamos algunos ejemplos.

Aporte: «[{}]([])”

Salida: Equilibrada

Aporte: «{[}]([])”

Salida: no balanceada

Podemos usar la pila para resolver el problema anterior. Veamos los pasos para solucionar el problema.

  • Crea una pila para almacenar los caracteres.
  • Si la longitud de la expresión es impar, entonces la expresión no está balanceada
  • Iterar a través de la expresión dada.
    • Si el carácter actual es el corchete de apertura de ( o { o [, then push it to stack.
    • Else if the current character is a closing bracket ) or } or ]luego pop de la pila.
    • Si el carácter reventado coincide con el paréntesis inicial, continúe; de ​​lo contrario, los paréntesis no están equilibrados.
  • Después de la iteración, si la pila está vacía, la ecuación está balanceada; de lo contrario, la ecuación no está balanceada.

Podemos hacer uso del tipo de datos establecido para la verificación de coincidencia de paréntesis.

## stack
class Stack: 
    def __init__(self): 
        self.elements = [] 
    
    def push(self, data): 
        self.elements.append(data) 
        return data 
        
    def pop(self): 
        return self.elements.pop() 
    
    def peek(self): 
        return self.elements[-1] 
        
    def is_empty(self): 
        return len(self.elements) == 0

def balance_check(expression):
    ## checking the length of the expression
    if len(expression) % 2 != 0:
        ## not balanced if the length is odd
        return False
    
    ## for checking
    opening_brackets = set('([{') 
    pairs = set([ ('(',')'), ('[',']'), ('{','}') ]) 
    
    ## stack initialization
    stack = Stack()
    
    ## iterating through the given expression
    for bracket in expression:

        ## checking whether the current bracket is opened or not        
        if bracket in opening_brackets:
            ## adding to the stack 
            stack.push(bracket)
        else:
            ## popping out the last bracket from the stack
            popped_bracket = stack.pop()
        
            ## checking whether popped and current bracket pair
            if (popped_bracket, bracket) not in pairs:
                return False
    
    return stack.is_empty()

if __name__ == '__main__':
    if balance_check('[{}]([])'):
        print("Balanced")
    else:
        print("Not Balanced")
    
    if balance_check('{[}]([])'):
        print("Balanced")
    else:
        print("Not Balanced")

Podemos usar la pila para resolver muchos más problemas. El problema anterior es uno de ellos. Intenta aplicar el concepto de pila donde creas que te conviene más.

Conclusión

¡Sí! Has completado el tutorial. Espero que hayas disfrutado el tutorial tanto como yo mientras lo hago. Eso es todo por el tutorial.

Codificación feliz 🙂 👨‍💻