Stos w Pythonie

Stos to popularna struktura danych oparta na zasadzie LIFO (Last In, First Out), co oznacza, że element dodany jako ostatni jest usuwany jako pierwszy.

Podstawowe operacje na stosie

Python nie ma wbudowanej klasy Stack, ale stos można łatwo zaimplementować za pomocą listy lub modułu collections.deque.

Implementacja za pomocą listy

stack = []

# Operacja push - dodawanie elementów
stack.append(10)
stack.append(20)
stack.append(30)

print(stack)  # Wynik: [10, 20, 30]

# Operacja pop - usuwanie ostatniego elementu
last_element = stack.pop()
print(last_element)  # Wynik: 30
print(stack)         # Wynik: [10, 20]

# Operacja peek - podglądanie ostatniego elementu (bez usuwania)
if stack:  # Sprawdzenie, czy stos nie jest pusty
    top_element = stack[-1]
    print(top_element)  # Wynik: 20

Zastosowania stosu

Odwracanie ciągów znaków

Stos pozwala łatwo odwrócić ciąg znaków, ponieważ najpierw dodajemy (push) znaki na stos, a potem usuwamy je w odwrotnej kolejności (pop).

def reverse_string(s):
    stack = []
    # Dodajemy znaki na stos
    for char in s:
        stack.append(char)
    # Zdejmujemy znaki ze stosu w odwrotnej kolejności
    reversed_s = ''.join(stack.pop() for _ in range(len(stack)))
    return reversed_s

print(reverse_string("Python"))  # Wynik: nohtyP

Nawigacja wstecz/przód (np. w przeglądarce internetowej)

Można użyć dwóch stosów: jeden do historii wstecznej, drugi do przyszłej.

class BrowserNavigation:
    def __init__(self):
        self.back_stack = []
        self.forward_stack = []

    def visit(self, url):
        if self.back_stack:
            self.forward_stack.clear()  # Po nowej wizycie czyścimy stos do przodu
        self.back_stack.append(url)
        print(f"Odwiedzono: {url}")

    def back(self):
        if self.back_stack:
            self.forward_stack.append(self.back_stack.pop())
            return self.back_stack[-1] if self.back_stack else "Brak poprzedniej strony"
        return "Nie można cofnąć"

    def forward(self):
        if self.forward_stack:
            url = self.forward_stack.pop()
            self.back_stack.append(url)
            return url
        return "Nie można przejść do przodu"

# Przykład użycia
browser = BrowserNavigation()
browser.visit("example.com")
browser.visit("google.com")
browser.visit("openai.com")
print(browser.back())  # Wynik: google.com
print(browser.back())  # Wynik: example.com
print(browser.forward())  # Wynik: google.com

Analiza nawiasów w wyrażeniach

Stos może służyć do sprawdzania poprawności nawiasów w wyrażeniu matematycznym czy kodzie.

def is_valid_expression(expression):
    stack = []
    matching_brackets = {')': '(', '}': '{', ']': '['}

    for char in expression:
        if char in matching_brackets.values():  # Otwierające nawiasy
            stack.append(char)
        elif char in matching_brackets.keys():  # Zamykające nawiasy
            if not stack or stack.pop() != matching_brackets[char]:
                return False  # Błąd: brak dopasowania
    return not stack  # Prawidłowe, jeśli stos jest pusty

# Przykład użycia
print(is_valid_expression("{[()]}"))  # Wynik: True
print(is_valid_expression("{[(])}"))  # Wynik: False

Zewnętrzne biblioteki

queue.LifoQueue

Choć nie jest zewnętrzną biblioteką, warto wspomnieć, że wbudowany moduł queue zawiera klasę LifoQueue, która działa jako stos i dodaje wsparcie dla operacji wielowątkowych.

from queue import LifoQueue

stack = LifoQueue()
stack.put(10)  # push
stack.put(20)
stack.put(30)

print(stack.get())  # pop (Wynik: 30)
print(stack.get())  # pop (Wynik: 20)

blist

blist to biblioteka, która oferuje zoptymalizowane struktury danych, w tym listy i deki, które mogą być używane jako stosy. Działa szybciej i zużywa mniej pamięci w porównaniu do wbudowanych list przy dużej liczbie elementów.

from blist import blist

stack = blist()
stack.append(10)  # push
stack.append(20)
stack.append(30)

print(stack.pop())  # Wynik: 30

stack 

Prosta biblioteka przeznaczona wyłącznie do obsługi stosów. Obsługuje operacje takie jak pushpoppeek, a także pozwala na sprawdzanie rozmiaru i pustego stosu.

from stack import Stack

stack = Stack()
stack.push(10)
stack.push(20)
stack.push(30)

print(stack.pop())   # Wynik: 30
print(stack.peek())  # Wynik: 20
print(stack.size())  # Wynik: 2

pycollections

Biblioteka pycollections dostarcza różnych struktur danych, w tym stosów, kolejek, czy zestawów, z bardziej rozbudowaną funkcjonalnością.

from pycollections import Stack

stack = Stack()
stack.push(10)
stack.push(20)
stack.push(30)

print(stack.pop())   # Wynik: 30
print(stack.peek())  # Wynik: 20
print(stack.is_empty())  # Wynik: False

pystack

pystack to dedykowana biblioteka do implementacji stosów z dodatkowymi funkcjami, takimi jak operacje na pełnym stosie, wgląd w całą zawartość czy debugowanie.

from pystack import Stack

stack = Stack()
stack.push(10)
stack.push(20)
stack.push(30)

print(stack.peek())  # Wynik: 30
print(stack.pop())   # Wynik: 30
print(stack.to_list())  # Wynik: [10, 20]

datastructures

Biblioteka dostarczająca różne struktury danych, w tym stosy, z możliwością konfiguracji (np. ograniczenie rozmiaru stosu).

from datastructures.stack import Stack

stack = Stack()
stack.push(10)
stack.push(20)
stack.push(30)

print(stack.pop())  # Wynik: 30
print(stack.is_empty())  # Wynik: False

more-itertools

Biblioteka oferująca narzędzia do pracy z iterowalnymi strukturami, w tym stosami, umożliwiając bardziej zaawansowaną manipulację danych.

from more_itertools import always_reversible

stack = always_reversible([10, 20, 30])
print(next(stack))  # Wynik: 30 (działa jako stos)

Porównanie bibliotek pod względem wydajności

Biblioteka / ImplementacjaOperacje push i pop (złożoność czasowa)Uwagi
list (wbudowana)O(1)Szybkie, ale może mieć dodatkowy koszt związany z realokacją pamięci.
collections.dequeO(1)Bardzo szybka i wydajna dla stosów. Brak obsługi zaawansowanych funkcji jak peek.
queue.LifoQueueO(1)Bezpieczne dla wielowątkowości, ale wolniejsze przez blokady (locks).
blistO(log N)Wolniejsze dla pojedynczych operacji, ale optymalniejsze dla dużych struktur.
stack (zewnętrzna)O(1)Dedykowana, minimalistyczna implementacja, wydajna jak lista.
pycollections.StackO(1)Porównywalna do stack, ale z dodatkowymi funkcjami jak is_empty.
pystackO(1)Nieco wolniejsza przez dodatkowe funkcje debugowania.
datastructures.StackO(1)Porównywalna do stack, prostsza, brak blokad wielowątkowych.