Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Комплект Информатика / Курс лекций.doc
Скачиваний:
128
Добавлен:
22.05.2015
Размер:
4.8 Mб
Скачать

Контрольные вопросы

1. Что такое массив в концептуальном и физическом представлении?

2. Как осуществляется доступ к элементам массива?

3. Какая опасность подстерегает программиста при работе с массивами в языке программирования Си++?

4. Что такое список в концептуальном и физическом представлении?

5. Какие виды списков бывают. Покажите на примере их целесообразность применения.

Лекция № 24 Стеки

Цель лекции

Изучить способы организации и хранения данных с помощью стеков.

План лекции

1. Структура и функции стека.

2. Реализация стека.

1 Структура и функции стека

Одним из свойств списка, делающих связную структуру более привлекательной по сравнению с непрерывной, является простота добавления и удаления записей внутри списка. Вспомните, что в случае непрерывного списка для выполнения этой операции могло понадобиться смещение всего массива имен для заполнения или создания свободного места. Если же разрешить добавление и удаление только в начале и конце структуры, то использовать смежную структуру становится удобнее. Примером такой структуры является стек (stack), то есть список, в котором элементы добавляются и удаляются только на одном конце. Следствием такого ограничения является то, что последний добавленный элемент всегда будет удален первым — из-за этого стеки называют структурами LIFO (last - in, first - out, последним прибыл — первым убыл).

Тот конец стека, где добавляются и удаляются элементы, называется вершиной стека (top). Другой конец часто называют основанием стека (stack's base). Чтобы отразить тот факт, что доступ к стеку ограничен верхней записью, мы используем для обозначения операций добавления и удаления специальные термины. Процесс добавления объекта в стек называется проталкиванием (push), а процесс удаления — выталкиванием (pop). To есть запись проталкивается в стек или выталкивается из него.

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

Ситуация усложняется тем, что сама процедура может запросить выполнение другой процедуры, которая, в свою очередь, вызовет еще одну и т. д. (рис. 1). Следовательно, накапливаются местоположения, которые необходимо запомнить, чтобы вернуть туда управление. После того как выполнены все процедуры, управление должно быть возвращено к должному месту программного модуля, который вызвал первую процедуру. Таким образом, точки возврата должны сохраняться в системе и затем восстанавливаться в правильном порядке.

Рисунок 1 – Вложенные процедуры, выполнение которых завершается в порядке, обратном запросам

Стек — это идеальная структура для такой системы. При вызове каждой процедуры указатель на соответствующую точку возврата проталкивается в стек. Затем, по завершении очередной процедуры, выталкивается верхняя запись стека, причем гарантируется возврат к правильному месту в программе.

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

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

Листинг 1. Процедура печати связного списка в обратном порядке с использованием вспомогательного стека

procedure ReversePrint (List)

CurrentPointer <- указатель головы списка List

while (CurrentPointer не NIL) do

(push (проталкивание) имени из элемента, на который указывает CurrentPointer. в стек:

Считывание указателя из элемента списка List, на который указывает CurrentPointer,

и присваивание этого значения CurrentPointer.)

while (стек не пустой) do

(pop (выталкивание) имени из стека и печать.)

Рисунок 2 – Печать связного списка в обратном порядке при помощи стека