Топ (top)
↑
┌───┐
│ 5 │ ← добавляем/удаляем только отсюда
├───┤
│ 4 │
├───┤
│ 3 │
├───┤
│ 2 │
├───┤
│ 1 │
└───┘
Дно (bottom)
Операции:
push(6): [1, 2, 3, 4, 5, 6]
peek(): возвращает 6 (не удаляет)
pop(): удаляет 6, возвращает 6
isEmpty(): false История посещений (стек):
Шаг 1: google.com
Стек: [google.com]
Шаг 2: youtube.com
Стек: [google.com, youtube.com]
Шаг 3: leetcode.com
Стек: [google.com, youtube.com, leetcode.com]
↑
последний элемент (top)
Шаг 4: кнопка "Назад"
Удаляем leetcode.com, возвращаем youtube.com
Стек: [google.com, youtube.com]
Шаг 5: кнопка "Назад"
Удаляем youtube.com, возвращаем google.com
Стек: [google.com]
Шаг 6: кнопка "Вперёд"
Добавляем youtube.com (из отдельного стека "вперёд")
Стек: [google.com, youtube.com] Массив: [_, _, _, _, _]
0 1 2 3 4
↑
top = -1 (пустой)
push(1):
Массив: [1, _, _, _, _]
0 1 2 3 4
↑
top = 0
push(2):
Массив: [1, 2, _, _, _]
0 1 2 3 4
↑
top = 1
pop():
Возвращаем: 2
Массив: [1, 2, _, _, _] (значение 2 всё ещё там, но не учитывается)
0 1 2 3 4
↑
top = 0 # Python
# Создание стека
stack = []
# Добавление (push) — O(1)
stack.append(1)
stack.append(2)
stack.append(3)
# Просмотр вершины (peek) — O(1)
top = stack[-1] # 3
# Удаление (pop) — O(1)
top = stack.pop() # 3
# Проверка пустоты — O(1)
len(stack) == 0 // Java
import java.util.*;
// Создание стека
Stack<Integer> stack = new Stack<>();
// Добавление (push) — O(1)
stack.push(1);
stack.push(2);
stack.push(3);
// Просмотр вершины (peek) — O(1)
int top = stack.peek(); // 3
// Удаление (pop) — O(1)
top = stack.pop(); // 3
// Проверка пустоты — O(1)
boolean isEmpty = stack.isEmpty(); // Go
// Создание стека
stack := []int{}
// Добавление (push) — O(1)
stack = append(stack, 1)
stack = append(stack, 2)
stack = append(stack, 3)
// Просмотр вершины (peek) — O(1)
top := stack[len(stack)-1] // 3
// Удаление (pop) — O(1)
top = stack[len(stack)-1] // возвращаем последний
stack = stack[:len(stack)-1] // удаляем последний
// Проверка пустоты — O(1)
isEmpty := len(stack) == 0 Front (начало) Rear (конец)
↓ ↓
[ ] [ ] [ ] [ ] [ ]
↑
первый
Операции:
enqueue(1): enqueue(2): enqueue(3):
Queue: [1, 2, 3]
↑ ↑
front rear
dequeue():
Удаляет 1, возвращает 1
Queue: [2, 3]
↑ ↑
front rear
peek():
Возвращает 2 (не удаляет) Массив: [_, _, _, _, _]
0 1 2 3 4
↑
front = rear = 0 (пустой)
enqueue(1):
Массив: [1, _, _, _, _]
0 1 2 3 4
↑
front = rear = 1
enqueue(2):
Массив: [1, 2, _, _, _]
0 1 2 3 4
↑ ↑
front rear = 2
enqueue(3):
Массив: [1, 2, 3, _, _]
0 1 2 3 4
↑ ↑
front rear = 3
dequeue():
Возвращаем: 1
Массив: [2, 3, _, _]
0 1 2 3 4
↑ ↑
front rear Массив: [1, 2, 3, _, _]
0 1 2 3 4
↑ ↑
front rear Массив (размер 5): [1, 2, 3, 4, 5]
0 1 2 3 4
↑ ↑
front = 1 rear = 4
enqueue(6):
rear "заворачивается" в начало:
Массив: [6, 2, 3, 4, 5]
0 1 2 3 4
↑ ↑
rear = 0 front = 1
dequeue():
Удаляем 2, front двигается вперёд:
Массив: [6, 2, 3, 4, 5]
0 1 2 3 4
↑ ↑
rear = 0 front = 2
Условие переполнения:
Если rear + 1 == front → очередь полная
Условие пустоты:
Если front == rear → очередь пустая Операция | Стек (массив) | Стек (список) | Очередь (массив) | Очередь (список) |
push/enqueue | O(1)* | O(1) | O(1)* | O(1) |
pop/dequeue | O(1) | O(1) | O(1)** | O(1) |
peek/front | O(1) | O(1) | O(1) | O(1) |
isEmpty | O(1) | O(1) | O(1) | O(1) |
Свойство | Стек (LIFO) | Очередь (FIFO) |
Порядок доступа | Последний зашёл, первым вышел | Первый зашёл, первым вышел |
Куда добавляем | Вершина (top) | Конец (rear/back) |
Откуда удаляем | Вершина (top) | Начало (front/head) |
Использование | Undo/Redo, Call Stack | Print queue, BFS, События |
Метафора | Стопка тарелок | Очередь в магазине |
# Неправильно для очереди
queue = [1, 2, 3]
front = queue.pop(0) # O(n) - сдвиг всех элементов
# Правильно для очереди
from collections import deque
queue = deque([1, 2, 3])
front = queue.popleft() # O(1)
# Использование deque для стека
stack = deque()
stack.append(1) # O(1)
stack.pop() # O(1) // Стек (рекомендуется)
Deque<Integer> stack = new ArrayDeque<>();
stack.push(1);
stack.pop();
// Очередь (рекомендуется)
Queue<Integer> queue = new ArrayDeque<>();
queue.offer(1);
queue.poll(); // Очередь с ring buffer
import "container/ring"
// Создаём кольцевой буфер размером 5
rb := ring.New(5)
// Добавляем элементы
rb.Value = 1
rb = rb.Next()
rb.Value = 2
rb = rb.Next()
// Удаляем элементы
rb = rb.Prev()
value := rb.Value // 2
// Пример использования стека в Go
stack := []int{}
stack = append(stack, 1)
stack = append(stack, 2)
top := stack[len(stack)-1] // 2
stack = stack[:len(stack)-1] // удаляем последний Вход: "({[]})"
'(' → стек: ['(']
'{' → стек: ['(', '{']
'[' → стек: ['(', '{', '[']
']' → '[' соответствует ']' → стек: ['(', '{']
'}' → '{' соответствует '}' → стек: ['(']
')' → '(' соответствует ')' → стек: []
Выход: true (сбалансированы) Вход: "({[)}"
'(' → стек: ['(']
'{' → стек: ['(', '{']
'[' → стек: ['(', '{', '[']
')' → '[' НЕ соответствует ')' → false
Выход: false (несбалансированы) Текст: ""
action("add 'Hello'") → undo_stack: ["Hello"], redo_stack: []
Текст: "Hello"
action("add ' World'") → undo_stack: ["Hello", "Hello World"], redo_stack: []
Текст: "Hello World"
undo() → redo_stack: ["Hello World"], undo_stack: ["Hello"]
Текст: "Hello"
redo() → undo_stack: ["Hello", "Hello World"], redo_stack: []
Текст: "Hello World" Вход: ["2", "1", "+", "3", "*"]
"2" → стек: [2]
"1" → стек: [2, 1]
"+" → 2 + 1 = 3 → стек: [3]
"3" → стек: [3, 3]
"*" → 3 * 3 = 9 → стек: [9]
Выход: 9 Граф:
1
/ \
2 3
/ \ \
4 5 6
DFS от 1:
Шаг 1: стек = [1], посещённые = {1}
Шаг 2: стек = [2, 3], посещённые = {1, 2}
Шаг 3: стек = [4, 5, 3], посещённые = {1, 2, 4}
Шаг 4: 4 не имеет соседей, возвращаемся к 5
Шаг 5: стек = [5, 3], посещённые = {1, 2, 4, 5}
... и так далее Граф:
1
/ \
2 3
/ \ \
4 5 6
BFS от 1 до 6:
Шаг 1: очередь = [1]
Шаг 2: очередь = [2, 3] (соседи 1)
Шаг 3: очередь = [3, 4, 5] (соседи 2)
Шаг 4: очередь = [4, 5, 6] (соседи 3)
Шаг 5: нашли 6! Путь: 1 → 3 → 6 Время 0: поступает задача A
Время 1: поступает задача B
Время 2: поступает задача C
Время 3: работник свободен
Очередь: [A, B, C]
Шаг 1: работник берёт A → очередь: [B, C]
Шаг 2: работник завершает A, берёт B → очередь: [C]
Шаг 3: работник завершает B, берёт C → очередь: []