This commit is contained in:
krahets
2026-04-14 18:06:19 +08:00
parent 17b2a0b630
commit cf0747ba3e
131 changed files with 604 additions and 609 deletions
+3 -3
View File
@@ -4836,7 +4836,7 @@
<h3 id="1">1. &nbsp; Реализация на основе двусвязного списка<a class="headerlink" href="#1" title="Permanent link">&para;</a></h3>
<p>Вспомним предыдущий раздел: там мы использовали обычный односвязный список для реализации очереди, потому что он позволяет удобно удалять головной узел, что соответствует операции <code>dequeue</code> , и добавлять новый узел после хвостового узла, что соответствует операции <code>enqueue</code> .</p>
<p>Для двусторонней очереди и голова, и хвост допускают операции добавления и удаления элементов. Иначе говоря, двусторонняя очередь требует реализации еще одного симметричного направления операций. Поэтому в качестве базовой структуры данных двусторонней очереди удобно использовать двусвязный список.</p>
<p>Как показано на рисунках ниже, мы рассматриваем головной и хвостовой узлы двусвязного списка как голову и хвост двусторонней очереди и одновременно реализуем функции добавления и удаления узлов с обеих сторон.</p>
<p>Как показано на рисунке 5-8, мы рассматриваем головной и хвостовой узлы двусвязного списка как голову и хвост двусторонней очереди и одновременно реализуем функции добавления и удаления узлов с обеих сторон.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="2:5"><input checked="checked" id="__tabbed_2_1" name="__tabbed_2" type="radio" /><input id="__tabbed_2_2" name="__tabbed_2" type="radio" /><input id="__tabbed_2_3" name="__tabbed_2" type="radio" /><input id="__tabbed_2_4" name="__tabbed_2" type="radio" /><input id="__tabbed_2_5" name="__tabbed_2" type="radio" /><div class="tabbed-labels"><label for="__tabbed_2_1">&lt;1&gt;</label><label for="__tabbed_2_2">&lt;2&gt;</label><label for="__tabbed_2_3">&lt;3&gt;</label><label for="__tabbed_2_4">&lt;4&gt;</label><label for="__tabbed_2_5">&lt;5&gt;</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
@@ -6563,7 +6563,7 @@
</div>
</div>
<h3 id="2">2. &nbsp; Реализация на основе массива<a class="headerlink" href="#2" title="Permanent link">&para;</a></h3>
<p>Как показано на рисунках ниже, аналогично реализации обычной очереди на массиве мы также можем использовать кольцевой массив для реализации двусторонней очереди.</p>
<p>Как показано на рисунке 5-9, аналогично реализации обычной очереди на массиве мы также можем использовать кольцевой массив для реализации двусторонней очереди.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="4:5"><input checked="checked" id="__tabbed_4_1" name="__tabbed_4" type="radio" /><input id="__tabbed_4_2" name="__tabbed_4" type="radio" /><input id="__tabbed_4_3" name="__tabbed_4" type="radio" /><input id="__tabbed_4_4" name="__tabbed_4" type="radio" /><input id="__tabbed_4_5" name="__tabbed_4" type="radio" /><div class="tabbed-labels"><label for="__tabbed_4_1">&lt;1&gt;</label><label for="__tabbed_4_2">&lt;2&gt;</label><label for="__tabbed_4_3">&lt;3&gt;</label><label for="__tabbed_4_4">&lt;4&gt;</label><label for="__tabbed_4_5">&lt;5&gt;</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
@@ -7991,7 +7991,7 @@
</div>
<h2 id="533">5.3.3 &nbsp; Применение двусторонней очереди<a class="headerlink" href="#533" title="Permanent link">&para;</a></h2>
<p>Двусторонняя очередь сочетает в себе логику стека и очереди, <strong>поэтому она может покрыть все сценарии применения обеих структур и при этом предоставляет более высокую степень свободы</strong>.</p>
<p>Мы знаем, что функция "undo" в программном обеспечении обычно реализуется с помощью стека: система помещает каждое изменение в стек с помощью <code>push</code> , а затем использует <code>pop</code> для отмены. Однако, учитывая ограниченность системных ресурсов, программы обычно ограничивают число шагов отмены, например разрешают хранить только <span class="arithmatex">\(50\)</span> шагов. Когда длина стека превышает этот предел, программе нужно удалить элемент с дна стека, то есть с головы очереди. <strong>Но стек не может реализовать такую операцию, и в этом случае его приходится заменять двусторонней очередью</strong>. Обрати внимание: основная логика "undo" по-прежнему следует стековому правилу LIFO, просто двусторонняя очередь позволяет более гибко реализовать некоторые дополнительные механизмы.</p>
<p>Мы знаем, что функция «undo» в программном обеспечении обычно реализуется с помощью стека: система помещает каждое изменение в стек с помощью <code>push</code> , а затем использует <code>pop</code> для отмены. Однако, учитывая ограниченность системных ресурсов, программы обычно ограничивают число шагов отмены, например разрешают хранить только <span class="arithmatex">\(50\)</span> шагов. Когда длина стека превышает этот предел, программе нужно удалить элемент с дна стека, то есть с головы очереди. <strong>Но стек не может реализовать такую операцию, и в этом случае его приходится заменять двусторонней очередью</strong>. Обрати внимание: основная логика «undo» по-прежнему следует стековому правилу LIFO, просто двусторонняя очередь позволяет более гибко реализовать некоторые дополнительные механизмы.</p>
<!-- Source file information -->
+1 -1
View File
@@ -4280,7 +4280,7 @@
<div class="admonition abstract">
<p class="admonition-title">Abstract</p>
<p>Стек и очередь - две базовые линейные структуры данных.</p>
<p>Они соответственно воплощают принципы "последним пришел - первым вышел" и "первым пришел - первым вышел".</p>
<p>Они соответственно воплощают принципы «последним пришел - первым вышел» и «первым пришел - первым вышел».</p>
</div>
<h2 id="_1">Содержание главы<a class="headerlink" href="#_1" title="Permanent link">&para;</a></h2>
<ul>
+5 -5
View File
@@ -4435,8 +4435,8 @@
<!-- Page content -->
<h1 id="52">5.2 &nbsp; Очередь<a class="headerlink" href="#52" title="Permanent link">&para;</a></h1>
<p><u>Очередь (queue)</u> - это линейная структура данных, подчиняющаяся правилу "первым пришел - первым вышел". Как видно из названия, очередь моделирует обычную ситуацию ожидания: новые люди непрерывно присоединяются к хвосту очереди, а стоящие в начале по одному уходят.</p>
<p>Как показано на рисунке 5-4, начало очереди называется головой очереди, а конец - хвостом очереди; операцию добавления элемента в хвост называют <code>enqueue</code>, а операцию удаления элемента из головы - <code>dequeue</code>.</p>
<p><u>Очередь (queue)</u> - это линейная структура данных, подчиняющаяся правилу «первым пришел - первым вышел». Как видно из названия, очередь моделирует обычную ситуацию ожидания: новые люди непрерывно присоединяются к хвосту очереди, а стоящие в начале по одному уходят.</p>
<p>Как показано на рисунке 5-4, начало очереди называется головой очереди, а конец - хвостом очереди. Операцию добавления элемента в хвост называют <code>enqueue</code>, а операцию удаления элемента из головы - <code>dequeue</code>.</p>
<p><img alt="Правило FIFO для очереди" class="animation-figure" src="../queue.assets/queue_operations.png" /></p>
<p align="center"> Рисунок 5-4 &nbsp; Правило FIFO для очереди </p>
@@ -4792,7 +4792,7 @@
<p>https://pythontutor.com/render.html#code=from%20collections%20import%20deque%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%D0%98%D0%BD%D0%B8%D1%86%D0%B8%D0%B0%D0%BB%D0%B8%D0%B7%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D1%82%D1%8C%20%D0%BE%D1%87%D0%B5%D1%80%D0%B5%D0%B4%D1%8C%0A%20%20%20%20%23%20%D0%92%20Python%20%D0%B4%D0%B2%D1%83%D1%81%D1%82%D0%BE%D1%80%D0%BE%D0%BD%D0%BD%D1%8E%D1%8E%20%D0%BE%D1%87%D0%B5%D1%80%D0%B5%D0%B4%D1%8C%20deque%20%D0%BE%D0%B1%D1%8B%D1%87%D0%BD%D0%BE%20%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D1%83%D1%8E%D1%82%20%D0%BA%D0%B0%D0%BA%20%D0%BE%D1%87%D0%B5%D1%80%D0%B5%D0%B4%D1%8C%0A%20%20%20%20%23%20%D0%A5%D0%BE%D1%82%D1%8F%20queue.Queue%28%29%20%D1%8F%D0%B2%D0%BB%D1%8F%D0%B5%D1%82%D1%81%D1%8F%20%D0%BD%D0%B0%D1%81%D1%82%D0%BE%D1%8F%D1%89%D0%B8%D0%BC%20%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D0%BE%D0%BC%20%D0%BE%D1%87%D0%B5%D1%80%D0%B5%D0%B4%D0%B8%2C%20%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D1%8C%D1%81%D1%8F%20%D0%B8%D0%BC%20%D0%BD%D0%B5%20%D1%81%D0%BB%D0%B8%D1%88%D0%BA%D0%BE%D0%BC%20%D1%83%D0%B4%D0%BE%D0%B1%D0%BD%D0%BE%0A%20%20%20%20que%20%3D%20deque%28%29%0A%0A%20%20%20%20%23%20%D0%9F%D0%BE%D0%BC%D0%B5%D1%81%D1%82%D0%B8%D1%82%D1%8C%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%20%D0%B2%20%D0%BE%D1%87%D0%B5%D1%80%D0%B5%D0%B4%D1%8C%0A%20%20%20%20que.append%281%29%0A%20%20%20%20que.append%283%29%0A%20%20%20%20que.append%282%29%0A%20%20%20%20que.append%285%29%0A%20%20%20%20que.append%284%29%0A%20%20%20%20print%28%22%D0%BE%D1%87%D0%B5%D1%80%D0%B5%D0%B4%D1%8C%20que%20%3D%22%2C%20que%29%0A%0A%20%20%20%20%23%20%D0%9F%D0%BE%D0%BB%D1%83%D1%87%D0%B8%D1%82%D1%8C%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%20%D0%B2%20%D0%BD%D0%B0%D1%87%D0%B0%D0%BB%D0%B5%20%D0%BE%D1%87%D0%B5%D1%80%D0%B5%D0%B4%D0%B8%0A%20%20%20%20front%20%3D%20que%5B0%5D%0A%20%20%20%20print%28%22%D0%AD%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%20%D0%B2%20%D0%BD%D0%B0%D1%87%D0%B0%D0%BB%D0%B5%20%D0%BE%D1%87%D0%B5%D1%80%D0%B5%D0%B4%D0%B8%20front%20%3D%22%2C%20front%29%0A%0A%20%20%20%20%23%20%D0%98%D0%B7%D0%B2%D0%BB%D0%B5%D1%87%D1%8C%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%20%D0%B8%D0%B7%20%D0%BE%D1%87%D0%B5%D1%80%D0%B5%D0%B4%D0%B8%0A%20%20%20%20pop%20%3D%20que.popleft%28%29%0A%20%20%20%20print%28%22%D0%98%D0%B7%D0%B2%D0%BB%D0%B5%D1%87%D0%B5%D0%BD%D0%BD%D1%8B%D0%B9%20%D0%B8%D0%B7%20%D0%BE%D1%87%D0%B5%D1%80%D0%B5%D0%B4%D0%B8%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%20pop%20%3D%22%2C%20pop%29%0A%20%20%20%20print%28%22que%20%D0%BF%D0%BE%D1%81%D0%BB%D0%B5%20%D0%B8%D0%B7%D0%B2%D0%BB%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F%20%3D%22%2C%20que%29%0A%0A%20%20%20%20%23%20%D0%9F%D0%BE%D0%BB%D1%83%D1%87%D0%B8%D1%82%D1%8C%20%D0%B4%D0%BB%D0%B8%D0%BD%D1%83%20%D0%BE%D1%87%D0%B5%D1%80%D0%B5%D0%B4%D0%B8%0A%20%20%20%20size%20%3D%20len%28que%29%0A%20%20%20%20print%28%22%D0%94%D0%BB%D0%B8%D0%BD%D0%B0%20%D0%BE%D1%87%D0%B5%D1%80%D0%B5%D0%B4%D0%B8%20size%20%3D%22%2C%20size%29%0A%0A%20%20%20%20%23%20%D0%9F%D1%80%D0%BE%D0%B2%D0%B5%D1%80%D0%B8%D1%82%D1%8C%2C%20%D0%BF%D1%83%D1%81%D1%82%D0%B0%20%D0%BB%D0%B8%20%D0%BE%D1%87%D0%B5%D1%80%D0%B5%D0%B4%D1%8C%0A%20%20%20%20is_empty%20%3D%20len%28que%29%20%3D%3D%200%0A%20%20%20%20print%28%22%D0%9F%D1%83%D1%81%D1%82%D0%B0%20%D0%BB%D0%B8%20%D0%BE%D1%87%D0%B5%D1%80%D0%B5%D0%B4%D1%8C%20%3D%22%2C%20is_empty%29&amp;cumulative=false&amp;curInstr=3&amp;heapPrimitives=nevernest&amp;mode=display&amp;origin=opt-frontend.js&amp;py=311&amp;rawInputLstJSON=%5B%5D&amp;textReferences=false</p>
</details>
<h2 id="522">5.2.2 &nbsp; Реализация очереди<a class="headerlink" href="#522" title="Permanent link">&para;</a></h2>
<p>Чтобы реализовать очередь, нам нужна такая структура данных, которая позволяет добавлять элементы с одного конца и удалять их с другого; и связный список, и массив этим требованиям удовлетворяют.</p>
<p>Чтобы реализовать очередь, нам нужна такая структура данных, которая позволяет добавлять элементы с одного конца и удалять их с другого. И связный список, и массив этим требованиям удовлетворяют.</p>
<h3 id="1">1. &nbsp; Реализация на основе связного списка<a class="headerlink" href="#1" title="Permanent link">&para;</a></h3>
<p>Как показано на рисунке 5-5, мы можем рассматривать головной узел и хвостовой узел связного списка как голову очереди и хвост очереди соответственно, договорившись, что добавлять узлы можно только в хвост, а удалять - только из головы.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="2:3"><input checked="checked" id="__tabbed_2_1" name="__tabbed_2" type="radio" /><input id="__tabbed_2_2" name="__tabbed_2" type="radio" /><input id="__tabbed_2_3" name="__tabbed_2" type="radio" /><div class="tabbed-labels"><label for="__tabbed_2_1">&lt;1&gt;</label><label for="__tabbed_2_2">&lt;2&gt;</label><label for="__tabbed_2_3">&lt;3&gt;</label></div>
@@ -5715,7 +5715,7 @@
</details>
<h3 id="2">2. &nbsp; Реализация на основе массива<a class="headerlink" href="#2" title="Permanent link">&para;</a></h3>
<p>Удаление первого элемента из массива имеет временную сложность <span class="arithmatex">\(O(n)\)</span> , из-за чего операция <code>dequeue</code> оказывается неэффективной. Однако этого можно избежать с помощью следующего приема.</p>
<p>Мы можем использовать переменную <code>front</code> , указывающую на индекс элемента в голове очереди, и поддерживать переменную <code>size</code> , которая хранит длину очереди. Определим <code>rear = front + size</code> ; эта формула дает позицию <code>rear</code>, указывающую на ячейку сразу после хвоста очереди.</p>
<p>Мы можем использовать переменную <code>front</code> , указывающую на индекс элемента в голове очереди, и поддерживать переменную <code>size</code> , которая хранит длину очереди. Определим <code>rear = front + size</code>. Эта формула дает позицию <code>rear</code>, указывающую на ячейку сразу после хвоста очереди.</p>
<p>Исходя из этого, <strong>эффективный диапазон элементов массива равен <code>[front, rear - 1]</code></strong>, а различные операции реализуются, как показано на рисунке 5-6.</p>
<ul>
<li>Операция <code>enqueue</code>: записать входной элемент по индексу <code>rear</code> и увеличить <code>size</code> на 1.</li>
@@ -6669,7 +6669,7 @@
<h2 id="523">5.2.3 &nbsp; Типичные применения очереди<a class="headerlink" href="#523" title="Permanent link">&para;</a></h2>
<ul>
<li><strong>Очереди заказов</strong>. После оформления заказа покупателем заказ попадает в очередь, а затем система обрабатывает заказы по порядку. Во время крупных распродаж за короткое время возникает огромный поток заказов, и высокая конкурентная нагрузка становится ключевой инженерной проблемой.</li>
<li><strong>Различные отложенные задачи</strong>. Любой сценарий, где нужно реализовать принцип "кто раньше пришел, тот раньше обслуживается", например очередь заданий принтера или очередь блюд на кухне ресторана, хорошо моделируется очередью, которая эффективно поддерживает нужный порядок обработки.</li>
<li><strong>Различные отложенные задачи</strong>. Любой сценарий, где нужно реализовать принцип «кто раньше пришел, тот раньше обслуживается», например очередь заданий принтера или очередь блюд на кухне ресторана, хорошо моделируется очередью, которая эффективно поддерживает нужный порядок обработки.</li>
</ul>
<!-- Source file information -->
+4 -4
View File
@@ -4457,8 +4457,8 @@
<!-- Page content -->
<h1 id="51">5.1 &nbsp; Стек<a class="headerlink" href="#51" title="Permanent link">&para;</a></h1>
<p><u>Стек (stack)</u> - это линейная структура данных, подчиняющаяся логике "последним пришел - первым вышел".</p>
<p>Стек можно сравнить со стопкой тарелок на столе. Если разрешено перемещать только одну тарелку за раз, то, чтобы достать тарелку снизу, сначала придется по одной убрать все тарелки сверху. Если заменить тарелки различными элементами, например целыми числами, символами, объектами и т.д., получится структура данных "стек".</p>
<p><u>Стек (stack)</u> - это линейная структура данных, подчиняющаяся логике «последним пришел - первым вышел».</p>
<p>Стек можно сравнить со стопкой тарелок на столе. Если разрешено перемещать только одну тарелку за раз, то, чтобы достать тарелку снизу, сначала придется по одной убрать все тарелки сверху. Если заменить тарелки различными элементами, например целыми числами, символами, объектами и т.д., получится структура данных «стек».</p>
<p>Как показано на рисунке 5-1, верхнюю часть стопки элементов мы называем вершиной стека, а нижнюю - основанием стека. Операция добавления элемента на вершину называется <code>push</code>, а операция удаления верхнего элемента - <code>pop</code>.</p>
<p><img alt="Правило LIFO для стека" class="animation-figure" src="../stack.assets/stack_operations.png" /></p>
<p align="center"> Рисунок 5-1 &nbsp; Правило LIFO для стека </p>
@@ -6216,10 +6216,10 @@
<p><strong>Пространственная эффективность</strong></p>
<p>При инициализации массива система выделяет начальную емкость, которая может превышать реальную потребность. Кроме того, механизм расширения обычно увеличивает емкость по некоторому коэффициенту, например в 2 раза, и расширенная емкость тоже может оказаться больше фактически необходимой. Поэтому <strong>реализация стека на основе массива может приводить к некоторым потерям памяти</strong>.</p>
<p>Однако, поскольку узлы связного списка должны дополнительно хранить указатели, <strong>узлы списка сами по себе занимают больше пространства</strong>.</p>
<p>В итоге нельзя просто сказать, какая из реализаций более экономна по памяти; это нужно анализировать в контексте конкретной задачи.</p>
<p>В итоге нельзя просто сказать, какая из реализаций более экономна по памяти. Это нужно анализировать в контексте конкретной задачи.</p>
<h2 id="514">5.1.4 &nbsp; Типичные применения стека<a class="headerlink" href="#514" title="Permanent link">&para;</a></h2>
<ul>
<li><strong>Кнопки "назад" и "вперед" в браузере, undo и redo в программах</strong>. Каждый раз, когда мы открываем новую страницу, браузер помещает предыдущую страницу в стек, чтобы по операции "назад" можно было вернуться к ней. Операция "назад" по сути является <code>pop</code> . Если нужно одновременно поддерживать и "назад", и "вперед", то обычно используются два стека.</li>
<li><strong>Кнопки «назад» и «вперед» в браузере, undo и redo в программах</strong>. Каждый раз, когда мы открываем новую страницу, браузер помещает предыдущую страницу в стек, чтобы по операции «назад» можно было вернуться к ней. Операция «назад» по сути является <code>pop</code> . Если нужно одновременно поддерживать и «назад», и «вперед», то обычно используются два стека.</li>
<li><strong>Управление памятью программы</strong>. Каждый раз при вызове функции система помещает на вершину стека стековый кадр, в котором хранится контекст функции. В рекурсивной функции на этапе углубления рекурсии непрерывно выполняются операции <code>push</code> , а на этапе возврата - операции <code>pop</code> .</li>
</ul>
@@ -4359,25 +4359,25 @@
<h1 id="54">5.4 &nbsp; Резюме<a class="headerlink" href="#54" title="Permanent link">&para;</a></h1>
<h3 id="1">1. &nbsp; Основные выводы<a class="headerlink" href="#1" title="Permanent link">&para;</a></h3>
<ul>
<li>Стек - это структура данных, следующая правилу "последним пришел - первым вышел", и его можно реализовать с помощью массива или связного списка.</li>
<li>Стек - это структура данных, следующая правилу «последним пришел - первым вышел», и его можно реализовать с помощью массива или связного списка.</li>
<li>С точки зрения временной эффективности реализация стека на массиве обычно работает быстрее в среднем, но во время расширения емкости временная сложность отдельной операции <code>push</code> может ухудшаться до <span class="arithmatex">\(O(n)\)</span> . Напротив, реализация стека на связном списке дает более стабильные характеристики.</li>
<li>С точки зрения использования памяти реализация стека на массиве может приводить к некоторой потере пространства. Однако следует учитывать, что узлы связного списка занимают больше памяти, чем элементы массива.</li>
<li>Очередь - это структура данных, следующая правилу "первым пришел - первым вышел", и ее также можно реализовать с помощью массива или связного списка. Сравнение временной и пространственной эффективности для очереди в целом приводит к тем же выводам, что и для стека.</li>
<li>Очередь - это структура данных, следующая правилу «первым пришел - первым вышел», и ее также можно реализовать с помощью массива или связного списка. Сравнение временной и пространственной эффективности для очереди в целом приводит к тем же выводам, что и для стека.</li>
<li>Двусторонняя очередь - это очередь с более высокой степенью свободы, которая позволяет добавлять и удалять элементы с обоих концов.</li>
</ul>
<h3 id="2-q-a">2. &nbsp; Q &amp; A<a class="headerlink" href="#2-q-a" title="Permanent link">&para;</a></h3>
<p><strong>Q</strong>: Реализованы ли кнопки "вперед" и "назад" в браузере с помощью двусвязного списка?</p>
<p>По сути, функция переходов "вперед/назад" в браузере отражает логику стека. Когда пользователь открывает новую страницу, она помещается на вершину стека; когда пользователь нажимает кнопку "назад", эта страница снимается с вершины стека. Двусторонняя очередь позволяет удобно реализовать некоторые дополнительные операции, об этом уже упоминалось в разделе "Двусторонняя очередь".</p>
<p><strong>Q</strong>: Реализованы ли кнопки «вперед» и «назад» в браузере с помощью двусвязного списка?</p>
<p>По сути, функция переходов «вперед/назад» в браузере отражает логику стека. Когда пользователь открывает новую страницу, она помещается на вершину стека. Когда пользователь нажимает кнопку «назад», эта страница снимается с вершины стека. Двусторонняя очередь позволяет удобно реализовать некоторые дополнительные операции, об этом уже упоминалось в разделе «Двусторонняя очередь».</p>
<p><strong>Q</strong>: Нужно ли освобождать память узла после извлечения его из стека?</p>
<p>Если извлеченный узел еще понадобится, память освобождать не нужно. Если он больше не нужен, то в языках <code>Java</code> и <code>Python</code> есть автоматический сборщик мусора, поэтому ручное освобождение памяти не требуется; в <code>C</code> и <code>C++</code> память нужно освобождать вручную.</p>
<p>Если извлеченный узел еще понадобится, память освобождать не нужно. Если он больше не нужен, то в языках <code>Java</code> и <code>Python</code> есть автоматический сборщик мусора, поэтому ручное освобождение памяти не требуется. В <code>C</code> и <code>C++</code> память нужно освобождать вручную.</p>
<p><strong>Q</strong>: Двусторонняя очередь выглядит как два соединенных стека. Для чего она нужна?</p>
<p>Двусторонняя очередь похожа на комбинацию стека и очереди или на два соединенных стека. Она объединяет логику обеих структур, поэтому может покрыть все их применения и при этом остается более гибкой.</p>
<p><strong>Q</strong>: Как именно реализуются отмена (undo) и повтор (redo)?</p>
<p>Используются два стека: стек <code>A</code> для отмены и стек <code>B</code> для повтора.</p>
<ol>
<li>Каждый раз, когда пользователь выполняет действие, это действие помещается в стек <code>A</code> , а стек <code>B</code> очищается.</li>
<li>Когда пользователь выполняет "undo", последнее действие извлекается из стека <code>A</code> и помещается в стек <code>B</code> .</li>
<li>Когда пользователь выполняет "redo", последнее действие извлекается из стека <code>B</code> и помещается обратно в стек <code>A</code> .</li>
<li>Когда пользователь выполняет «undo», последнее действие извлекается из стека <code>A</code> и помещается в стек <code>B</code> .</li>
<li>Когда пользователь выполняет «redo», последнее действие извлекается из стека <code>B</code> и помещается обратно в стек <code>A</code> .</li>
</ol>
<!-- Source file information -->