Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Информатика и ВТ Брукшир.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
5.07 Mб
Скачать

7.4.2Реализация стека

Для реализации стека в компьютерной памяти обычно резервируют блок смежных ячеек памяти достаточного размера, чтобы вместить стек с учетом его увеличения или уменьшения. (Решение о размере этого блока зачастую является критическим. Если зарезервировано слишком мало места, в конечном итоге размер стека превысит размер выделенного пространства; если зарезервировано слишком много места, оно не будет полностью использовано.) Один из концов блока обозначен как основание стека. Здесь хранится первая протолкнутая в стек запись, а все остальные помещаются за ней, и стек растет по направлению к другому концу зарезервированного блока.

Таким образом, по мере проталкивания и выталкивания записей вершина стека перемещается вперед и назад в пределах зарезервированного блока ячеек памяти. Для того чтобы отслеживать положение вершины, ее адрес хранится в дополнительной ячейке памяти, называемой указателем стека (stack pointer). To есть указатель стека — это указатель на вершину стека.

Система стека работает следующим образом (рис. 7.10): для того чтобы протолкнуть в стек новую запись, значение указателя стека переопределяется — теперь он указывает на свободное место за вершиной стека. Затем на это место записывается новый элемент. Чтобы вытолкнуть элемент из стека, мы считываем данные, на которые указывает указатель стека, а затем переопределяем этот указатель, чтобы он указывал на предыдущую запись в стеке.

Как и для списков, программисту, очевидно, будет удобнее написать процедуры для выполнения операций проталкивания и выталкивания и использовать стек как абстрактный инструмент. Обратите внимание, что эти процедуры должны обрабатывать такие случаи, как попытки выталкивания записей из пустого стека и проталкивания элементов в полный стек. Таким образом, полная система стека предполагает наличие процедур для проталкивания и выталкивания записей, а также для проверки, пуст ли стек и есть ли в нем свободные места.

Между абстрактной структурой и фактической организацией в памяти стека, реализованного в виде блока смежных ячеек памяти, практически нет различий. Но допустим, что предсказать максимальный размер стека и зарезервировать точно подходящий по размеру фиксированный блок памяти невозможно. Решить эту проблему можно, реализовав стек в виде связной структуры, похожей на ту, которую мы рассматривали в разделе 7.2. Таким образом, можно обойти ограничения, налагаемые фиксированным размером блока памяти, так как записи стека будут размещены в различных, даже в самых маленьких свободных областях памяти. Но в этом случае абстрактная структура стека будет отличаться от фактической организации его в памяти.

7.5 Очереди

В противоположность стеку, где вставка и удаление производятся на одном и том же конце, очередь (queue) — это список, в который записи добавляются с одной стороны, а удаляются с другой. Мы уже встречались с этой структурой, обсуждая очереди в главе 3, где определили их как системы хранения типа FIFO (first-in, first-out, первым прибыл — первым обслужен). В действительности концепция очередей обязательно присутствует в любой системе, где объекты обслуживаются в порядке поступления. Концы очереди получили свои названия по аналогии с очередью ожидания. Тот конец, откуда записи удаляются, называется головой (head) (или началом) очереди, так же как в кафе мы можем сказать, что следующим будет обслужен человек, стоящий в начале очереди. Аналогично, конец, куда добавляются записи, называется хвостом очереди (tail).

Можно реализовать очередь в памяти компьютера в блоке смежных ячеек, схожим со стеком образом. Так как нам необходимо производить операции на обоих концах структуры, то, в отличие от стека, где требуется одна дополнительная ячейка, здесь мы отдельно заводим еще две ячейки памяти для использования в качестве указателей. Один из них, называемый указателем головы, предназначен для отслеживания головы очереди; другой, указатель хвоста, предназначен для хвоста очереди. Если очередь пуста, оба указателя указывают на одно и то же место в памяти (рис. 7.11). Новая запись помещается по адресу, содержащемуся в указателе хвоста, а затем значение этого указателя изменяется на адрес следующего свободного места в памяти. Таким образом, указатель хвоста всегда указывает на первое свободное место в очереди. Для удаления записи из очереди необходимо считать значение, на которое указывает указатель головы, а затем изменить его значение, чтобы он указывал на запись, следующую за удаленной.

С этой системой хранения связана другая проблема. Если не управлять очередью, она постепенно будет перемещаться по памяти, как ледник, разрушая остальные данные на своем пути (рис. 7.12). Это движение является результатом «эгоцентричного» правила добавления новых элементов путем размещения их рядом с предыдущим и соответствующего переопределения указателя хвоста. Если добавить достаточно записей, хвост очереди, в конце концов, доберется до конца машинной памяти.

Причиной такого расходования памяти является не размер очереди, а недостаток ее реализации. (Для небольшой, но часто изменяющейся очереди может потребоваться больше машинной памяти, чем для большой, но практически неподвижной.) Можно решить эту проблему, перемещая элементы очереди вперед при каждом удалении записей из ее начала, так же как в очереди к театральной кассе люди делают шаг вперед, как только первый человек приобретает свои билеты. Но этот подход не эффективен в компьютерной технологии, так как требует массовых перемещений данных.

Наиболее распространенный способ управления очередью в памяти компьютера состоит в выделении блока памяти, с одного края которого очередь начинается и перемещается к концу блока. Затем, когда хвост очереди достигает конца блока, мы просто начинаем добавлять записи в начало этого блока, где к этому времени освобождается место. Когда последняя запись в блоке станет головой очереди и будет удалена, головной указатель переместится обратно к началу блока, куда были добавлены новые записи, ожидающие обработки. Таким образом, очередь как бы ходит по кругу внутри одного блока, а не перемещается по всей памяти компьютера.

Этот способ реализации называется циклической очередью (circular queue), так как образуется цикл из ячеек памяти, выделенных для очереди (рис. 7.13). С точки зрения этой очереди последняя ячейка в блоке соседствует с первой.

Необходимо еще раз обратить внимание на разницу между абстрактной структурой, как ее представляет пользователь, и фактической циклической структурой, реализованной в памяти машины. Как и в случае с предыдущими структурами, программное обеспечение скрывает эти различия. То есть помимо набора ячеек памяти, в которых хранятся данные, реализация очереди должна включать в себя несколько процедур для добавления и удаления записей из очереди и определения, пуста очередь или заполнена. Тогда программист, работающий с другим программным модулем, сможет производить вставку и удаление записей при помощи этих процедур, не думая о деталях организации очереди в памяти.