← Назад к вопросам

Какую структуру данных будешь использовать для хранения стека на Python?

1.3 Junior🔥 101 комментариев
#Python Core#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Структуры данных для реализации стека в Python

Для хранения стека в Python рекомендуется использовать список (list) благодаря его эффективности и встроенным методам. Альтернативно можно использовать collections.deque, которая оптимизирована для операций с концами. Кастомная реализация на основе связного списка используется в образовательных целях.

1. Список (list) — самый простой вариант

Питон-список идеально подходит для стека благодаря:

  • O(1) операциям push (append) и pop
  • Встроенным методам
  • Простоте использования
class Stack:
    def __init__(self):
        self.items = []  # Список как основание стека
    
    def push(self, item):
        """Добавить элемент в стек"""
        self.items.append(item)  # O(1) амортизированное
    
    def pop(self):
        """Удалить и вернуть верхний элемент"""
        if self.is_empty():
            raise IndexError("pop из пустого стека")
        return self.items.pop()  # O(1)
    
    def peek(self):
        """Посмотреть верхний элемент без удаления"""
        if self.is_empty():
            raise IndexError("стек пуст")
        return self.items[-1]  # O(1)
    
    def is_empty(self):
        """Проверить, пуст ли стек"""
        return len(self.items) == 0  # O(1)
    
    def size(self):
        """Получить размер стека"""
        return len(self.items)  # O(1)

# Использование
stack = Stack()
stack.push(10)
stack.push(20)
stack.push(30)

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

2. collections.deque — оптимизированный вариант

Deque (Double-Ended Queue) специально оптимизирована для операций с концами:

from collections import deque

class StackDeque:
    def __init__(self):
        self.items = deque()
    
    def push(self, item):
        """Добавить элемент"""
        self.items.append(item)  # O(1)
    
    def pop(self):
        """Удалить и вернуть верхний элемент"""
        if self.is_empty():
            raise IndexError("pop из пустого стека")
        return self.items.pop()  # O(1)
    
    def peek(self):
        """Посмотреть верхний элемент"""
        if self.is_empty():
            raise IndexError("стек пуст")
        return self.items[-1]  # O(1)
    
    def is_empty(self):
        return len(self.items) == 0
    
    def size(self):
        return len(self.items)

# Использование
stack = StackDeque()
for i in range(1000000):
    stack.push(i)

while not stack.is_empty():
    stack.pop()

Сравнение: list vs deque

import timeit
from collections import deque

# Тест push/pop производительности
def test_list():
    s = []
    for i in range(10000):
        s.append(i)
    for _ in range(10000):
        s.pop()

def test_deque():
    s = deque()
    for i in range(10000):
        s.append(i)
    for _ in range(10000):
        s.pop()

print("list:", timeit.timeit(test_list, number=100))
print("deque:", timeit.timeit(test_deque, number=100))
# deque часто быстрее при больших объёмах

3. Кастомная реализация на основе связного списка

Для образовательных целей или специальных случаев:

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

class LinkedListStack:
    def __init__(self):
        self.head = None  # Указатель на верх стека
        self._size = 0
    
    def push(self, item):
        """Добавить элемент в начало списка"""
        new_node = Node(item)
        new_node.next = self.head
        self.head = new_node
        self._size += 1
    
    def pop(self):
        """Удалить и вернуть верхний элемент"""
        if self.is_empty():
            raise IndexError("pop из пустого стека")
        
        data = self.head.data
        self.head = self.head.next
        self._size -= 1
        return data
    
    def peek(self):
        """Посмотреть верхний элемент"""
        if self.is_empty():
            raise IndexError("стек пуст")
        return self.head.data
    
    def is_empty(self):
        return self.head is None
    
    def size(self):
        return self._size

# Использование
stack = LinkedListStack()
stack.push(100)
stack.push(200)
stack.push(300)

while not stack.is_empty():
    print(stack.pop())

4. Практические примеры использования стека

Проверка сбалансированных скобок

def is_balanced(expr):
    """Проверить, сбалансированы ли скобки"""
    stack = []
    pairs = {'(': ')', '[': ']', '{': '}'}
    
    for char in expr:
        if char in pairs:
            stack.append(char)  # push
        elif char in pairs.values():
            if not stack or pairs[stack.pop()] != char:
                return False
    
    return len(stack) == 0

print(is_balanced("(()[{}])"))    # True
print(is_balanced("([{]})"))       # True
print(is_balanced("([)])"))        # False

Обратная польская нотация (RPN)

def evaluate_rpn(tokens):
    """Вычислить выражение в обратной польской нотации"""
    stack = []
    operators = {'+', '-', '*', '/'}
    
    for token in tokens:
        if token in operators:
            b = stack.pop()
            a = stack.pop()
            
            if token == '+':
                stack.append(a + b)
            elif token == '-':
                stack.append(a - b)
            elif token == '*':
                stack.append(a * b)
            elif token == '/':
                stack.append(int(a / b))
        else:
            stack.append(int(token))
    
    return stack[0]

print(evaluate_rpn(["2", "1", "+", "3", "*"]))  # (2+1)*3 = 9
print(evaluate_rpn(["15", "7", "1", "1", "-", "/", "*", "2", "-", "1", "+"]))  # 5

Обход дерева в глубину (DFS)

class TreeNode:
    def __init__(self, val):
        self.val = val
        self.left = None
        self.right = None

def dfs_iterative(root):
    """Обход дерева итеративно с использованием стека"""
    if not root:
        return []
    
    result = []
    stack = [root]
    
    while stack:
        node = stack.pop()
        result.append(node.val)
        
        # Добавляем в обратном порядке (right, left)
        if node.right:
            stack.append(node.right)
        if node.left:
            stack.append(node.left)
    
    return result

Рекомендация

Используй list в 95% случаев:

  • Просто и понятно
  • Встроенные методы (append, pop)
  • Достаточно быстро для большинства задач
# Минимальная реализация
stack = []
stack.append(item)     # push
item = stack.pop()     # pop
top = stack[-1]        # peek
is_empty = len(stack) == 0

Используй deque, если:

  • Нужна максимальная производительность
  • Работаешь с очень большими стеками
  • Нужны операции с обоих концов

Используй связный список, если:

  • Изучаешь структуры данных
  • Нужна гибкость в управлении памятью
  • Не критична производительность
Какую структуру данных будешь использовать для хранения стека на Python? | PrepBro