Главная страница

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


Скачать 173.4 Kb.
НазваниеСтек (stack) это последовательность однотипных элементов, характерная тем, что элементы добавляются и удаляются только с одного
Дата12.03.2023
Размер173.4 Kb.
Формат файлаpdf
Имя файла1 Структуры данных и способы их реализации.pdf
ТипДокументы
#983231

1. Структуры данных и способы их реализации
Стек (stack) – это последовательность однотипных элементов, характерная тем, что элементы добавляются и удаляются только с одного
конца, называемого вершиной стека. Стек работает по принципу «Элемент, помещенный в стек последним, извлечен будет первым». Иногда этот принцип обозначается сокращением LIFO (от английского «Last In – First
Out», т.е. «последним зашел – первым вышел»). Естественно, можно перевернуть этот принцип и сформулировать его так: «Элемент, помещенный в стек первым, извлечен будет последним». Иногда такой элемент называют
дном стека.
Бытовой пример стека – стопка тяжелых предметов (например – бетонные плиты). Примеры использования стека в программировании:
 вложенные вызовы подпрограмм, в частности – рекурсивные: вызовы подпрограмм идут в одном порядке, а возвраты из них – в обратном
 стек операндов при разборе арифметических выражений со вложенными скобками
Важность стека для вычислительной техники в целом подтверждается тем, что все современные типы процессоров реализуют стековые операции на уровне базовых команд.
Стеки могут хранить любые однотипные данные, как простейшие (целые числа или отдельные символы), так и структурированные (строки, записи).
Очередь (Queue) – это последовательность однотипных элементов, характерная тем, что новые элементы в нее добавляются с одного конца, а
удаляются с другого.
Очередь работает по принципу “Элемент, помещенный в очередь
первым, извлечен будет тоже первым”. Иногда этот принцип обозначается сокращением FIFO (от английского «First In – First Out», т.е. «Первым зашел
– первым вышел»). Для очереди определяется ее начало (первый элемент в очереди) и конец (последний элемент).

Очереди особенно часто используются в системных программах, прежде всего в многозадачных операционных системах (очередь потоков на выполнение, очередь событий, очередь заданий на печать и т.д.). Кроме того, существует множество прикладных задач, связанных с обслуживанием клиентов или заявок, где без подобной структуры не обойтись.
Линейный список (List) – это набор связанных однотипных элементов, в котором каждый элемент каким-то образом определяет следующий за ним элемент. В отличие от стека и очереди, добавление нового элемента возможно в любом месте списка, также можно удалить любой элемент списка. Ясно, что списковые структуры являются более гибкими, но и немного более
сложными в реализации. Фактически, стеки и очереди можно считать
частными случаями списков, в которых добавление и удаление элементов может выполняться только на концах. Списковые структуры находят широкое применение и в системных, и в прикладных задачах. Важной разновидностью списков являются упорядоченные списки, в которых элементы выстроены по порядку в соответствии с некоторым правилом.
Все три перечисленные структуры данных можно реализовать одним из
двух способов:
 на основе массива (статическая или непрерывная реализация)
 на основе использования специальных адресных переменных и механизма динамического распределения памяти (динамическая,
адресная или связная реализация)
Ни один из этих способов не является идеальным, каждый имеет свои достоинства и недостатки и отсюда – свою область применения. Не вдаваясь пока в тонкости реализации этих способов, дадим следующее их сравнение
(отметив, где это имеет смысл, плюсы и минусы).
Реализация на основе массива:
 может использоваться, когда число элементов в структуре известно хотя
бы приблизительно и мало изменяется в процессе эксплуатации, иначе могут возникать существенные потери памяти за счет большого числа не используемых элементов массива
 имеет очень простую программную реализацию, сводящуюся к стандартным операциям с массивов ( + )
 обеспечивает очень высокую скорость выполнения таких операций как
доступ к элементам по их индексам, поиск при использовании упорядоченных массивов, добавление и удаление для стеков и очередей
( + )
 при реализации списков может приводить к замедлению таких операций как добавление и удаление элементов ( - )
 требует выделения непрерывной области памяти, что не всегда возможно
( - )
Реализация на основе адресных связей:
 подходит для ситуации, когда число элементов может изменяться в
очень широких пределах
не требует выделения единой непрерывной области памяти и приводит к более экономному расходованию оперативной памяти ( + )
 обеспечивает быстрое выполнение операций добавления и удаления элементов, особенно для стеков и очередей ( + )
 имеет более сложную программную реализацию, основанную на использовании переменных адресного типа и увеличивающую вероятность появления ошибок при выполнении программы ( - )

многократное повторение операций динамического выделения и освобождения памяти может приводить к некоторому замедлению работы программы ( - )
Первый способ реализации структур использует классическое понятие массива, что объясняет происхождение термина “непрерывная” реализация: элементы структуры занимают последовательные ячейки массива, т. е.
располагаются в памяти строго друг за другом. Второй термин (статическая реализация) связан с особенностями выделения памяти для элементов массива: это происходит при обработке текста программы транслятором, т. е. на этапе создания исполняемого кода.
Каждой объявленной в программе переменной транслятор выделяет
необходимую по размеру область памяти и связывает адрес этой области с именем переменной. Например, пусть объявлены следующие три переменные:
var x, y : real;
MyArr : array [ 1 .. 100 ] of integer;
float x, y;
int MyArr[100] ;
Тогда компилятор при обработке этих объявлений распределит память
примерно следующим образом (с учетом возможных различий в представлении базовых типов на разных платформах): число x
(6/4 байт) число y
(6/4 байт)
Элементы массива
( 100*4 = 400 байт)
Особенность статического распределения памяти – жесткая фиксация выделенных областей, невозможность изменения этого распределения при
выполнении программы. Этим и объясняются как положительные, так и отрицательные стороны использования классических массивов.
В тех задачах, где подобная жесткость является слишком неудобной, можно использовать другой способ распределения памяти – динамический.
Он позволяет выделять память под значения переменных непосредственно в процессе выполнения программы в ответ на вызов специальных стандартных
функций. Когда необходимость в использовании этих значений исчезает, соответствующие области памяти можно освободить для других целей.
Это позволяет весьма экономно расходовать такой важнейший ресурс как имя x имя y имя MyArr
оперативная память, хотя и приводит к небольшому замедлению выполнения программы в случае многократного выделения памяти за счет необходимости взаимодействия с операционной системой. Это является еще одним проявлением классического противоречия между скоростью работы программы и требуемыми объемами памяти.
Особенности динамической реализации будут рассмотрены немного позже, а несколько следующих тем будут посвящены рассмотрению первого способа реализации структур на основе обычных массивов.


написать администратору сайта