edubun
Русский

Стеки

Чтобы проверить, что скобки в {[()()]} правильно образуют пары, нужен один стек и 8 добавлений и извлечений, по одному на каждую скобку.

Последним пришёл, первым ушёл

Представь стопку тарелок. Чистую тарелку кладёшь наверх, а когда нужна тарелка, берёшь сверху. Тарелка, положенная последней, уходит первой. Стек является структурой данных ровно с этим правилом, оно называется «последним пришёл, первым ушёл» (LIFO). У него две главные операции: push кладёт значение наверх, а pop снимает верхнее значение и возвращает его. Многие стеки предлагают и peek, которая смотрит на верх, ничего не снимая.

В конспектах MIT 6.006 стек является частным случаем интерфейса последовательности: insert last(x) и delete last(). Это уже подсказывает, как его построить. Положи значения в динамический массив и считай конец массива верхом. В прошлом уроке конец был дешёвой стороной, поэтому push и pop стоят по 1 шагу (амортизированно, из-за редких копирований). Размер стека ничего не меняет. Снять значение со стека из 3 значений или из 3 миллионов значит сделать один и тот же шаг.

const stack = [];
stack.push(4);
stack.push(8);
stack.push(5);
console.log(stack.pop());           // 5, добавлено последним
console.log(stack[stack.length - 1]); // peek: 8
console.log(stack.length);          // 2
Загрузка

Перетащи, чтобы повернуть. Колёсико или щипок для масштаба.

Стек в виде стопки. Push и Pop работают только с верхом. Выбери строку со скобками и нажми «Проверить скобки», чтобы посмотреть, как стек решает, сбалансирована ли она.

Проверка скобок

Классическое применение стека: проверка, сбалансированы ли скобки, это делает каждый редактор кода и компилятор. Читай текст слева направо. Каждая открывающая скобка, (, [ или {, кладётся в стек. Каждая закрывающая скобка должна совпадать с открывающей на верху стека: если совпадает, сними эту открывающую; если стек пуст или наверху скобка другого вида, строка не сбалансирована. В конце стек должен быть пуст, иначе какая-то открывающая скобка так и не закрылась.

Попробуй строки в лаборатории. {[()()]} требует 4 добавления и 4 извлечения, 8 шагов, и заканчивается пустым стеком. ([)] ломается на третьем символе: ) приходит, когда наверху [. (() дочитывается до конца, и одна ( остаётся лишней. Почему для этой работы подходит стек? Скобки вкладываются друг в друга, и последняя открытая должна закрыться первой. Это и есть «последним пришёл, первым ушёл».

Где ещё встречаются стеки

  • Стек вызовов. Когда функция a вызывает b, а b вызывает c, компьютер кладёт запись для каждого вызова. Когда c возвращает результат, её запись снимается, и b продолжает с того места, где остановилась. Бесконечная рекурсия переполняет этот стек, отсюда ошибка «переполнение стека» (stack overflow).
  • Отмена. Редактор кладёт в стек каждое изменение. Отмена снимает последнее изменение и откатывает его.
  • Кнопка «Назад». Браузер кладёт в стек каждую страницу, с которой ты уходишь; «Назад» снимает последнюю.
  • Поиск в глубину. В курсе об алгоритмах стек помогал зайти в лабиринте как можно глубже, прежде чем возвращаться.
КонтекстСтек как идею вычислений обычно возводят к Фридриху Л. Бауэру и Клаусу Замельзону из Мюнхена. Работая над переводом арифметических формул, они хранили отложенные операции в хранилище, где последний положенный элемент берётся первым, и назвали его Keller, по-немецки «подвал». Заявку на патент на этот метод они подали в 1957 г.; в США его выдали в 1962 г. Примерно тогда же обработка списков у Аллена Ньюэлла, Клиффа Шоу и Герберта Саймона в корпорации RAND тоже опиралась на стеки, потому что их программы были полны рекурсии.
  1. В каком порядке стек возвращает значения?
    • Первым пришёл, первым ушёл
    • Последним пришёл, первым ушёл
    • Сначала наименьшее
    • В случайном порядке
  2. Стек пуст. Push 4, push 8, push 5, pop, push 2. Что наверху?
    • 4
    • 8
    • 5
    • 2
  3. Сколько значений в стеке после этих операций?
  4. Push A, затем B, затем C, затем pop, пока стек не опустеет. Расставь снятые значения по порядку.
  5. Сколько всего добавлений и извлечений нужно, чтобы проверить {[()()]} способом со скобками?
  6. Если проверять ([)] слева, где проверка ломается?
    • На первой (
    • На [
    • На )
    • На последней ]
  7. Что не так с (() ?
    • Закрывающая скобка приходит при пустом стеке
    • В конце в стеке остаётся одна (
    • Не хватает квадратных скобок
    • Всё в порядке; строка сбалансирована
  8. Сколько шагов занимает pop из стека (хранящегося в динамическом массиве), в котором 1000 значений?
  9. Функция main вызывает draw, а draw вызывает line. Чья запись лежит на верху стека вызовов, пока выполняется line?
    • main
    • draw
    • line
    • ничья
  10. В каком году Бауэр и Замельзон подали заявку на патент на метод стека?
    • 1946
    • 1957
    • 1962
    • 1972
Главное
  • Стек работает по правилу «последним пришёл, первым ушёл»: push кладёт наверх, pop снимает сверху.
  • Если стек построен на конце динамического массива, push и pop стоят по 1 шагу.
  • Проверка скобок кладёт открывающие в стек и снимает по одной на каждой закрывающей; {[()()]} требует 8 шагов.
  • Стек вызовов, отмена и кнопка «Назад» являются стеками.
Источники курса (11)
  • MIT OpenCourseWare 6.006 Introduction to Algorithms, Spring 2020 (Demaine, Ku, Solomon)
  • lecture notes 2 Data Structures (interface vs data structure, Sequence and Set interfaces, stack = insert_last/delete_last, queue = insert_last/delete_first, array, linked list, dynamic array, amortized Θ(1) append)
  • 4 Hashing (chaining, pigeonhole collisions, chain length n/m)
  • 6 Binary Trees Part 1 (height, traversal order, O(h) operations) and 7 Binary Trees Part 2: AVL (Adelson-Velsky and Landis, 1962) at ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/pages/lecture-notes
  • MDN Web Docs, Array.prototype.shift (shifts all values left by 1)
  • Array.prototype.unshift, Map (insertion order, Map vs Object, spec requires sublinear average access) and Set (developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects)
  • ECMAScript 2025 Language Specification (tc39.es/ecma262)
  • 24.1 Map Objects and 24.2 Set Objects ("must be implemented using either hash tables or other mechanisms that, on average, provide access times that are sublinear on the number of elements")
  • Array.prototype.shift steps (Repeat, while k < len: move element k to k - 1)
  • D. E. Knuth, The Art of Computer Programming vol. 3 (2nd ed. 1998) section 6.4 History (H. P. Luhn, IBM internal memorandum January 1953, hashing with chaining; digit pairs added mod 10, 31415926 -> 4548) via gwern.net copy, and IEEE Spectrum, "Hans Peter Luhn and the Birth of the Hashing Algorithm" (2018)
  • "A brief history of the stack", SIGCIS (sigcis.org/files/A brief history.pdf: Bauer and Samelson applied for the patent in 1957, US 3,047,228 granted July 31, 1962; IPL list processing by Newell, Simon and Shaw at RAND 1956) and Wikipedia, Information Processing Language (Newell, Shaw, Simon, RAND and Carnegie Institute of Technology, about 1956).

Проверено: 2026-10-18