Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Пособие часть1.doc
Скачиваний:
22
Добавлен:
01.03.2025
Размер:
6.94 Mб
Скачать

2.1.2. Функциональная спецификация очереди

Очередь (queue) - это другой специальный тип списка, где элементы вставляются в конец списка, называемый хвостом (tail), а удаляются из начала списка, называемого головой (head). Очереди также называют "списками типа FIFO" (аббревиатура FIFO расшифровывается как first-in-first-out: первым вошел — первым вышел). Операции, выполняемые с очередями, аналогичны операциям со стеками.

К сожалению, для обозначения операций нет стандартных устоявшихся названий. Воспользуемся обозначениями, которые предлагаются в книгах Ахо и Седжвика.

  1. Создание пустой очереди  — операция create

  2. Проверка очереди на наличие хотя бы одного элемента — предикат (логическая функция) isnull.

  3. Вставка значения p в конец (хвост) очереди — операция enqueue;

  4. Удаление элемента из начала (головы) непустой очереди с получением его значения — операция dequeue. Эту операцию можно рассматривать и как две различные операции: head — получение первого элемента из головы очереди и собственно dequeue — удаление элемента.

Формальная спецификация операций для очереди из элементов типа α Queue of α  Queue ( α ) ) [2] выполняется аналогично спецификации стека.

1. Create:  Null_queue ( α ) ;

2. IsNull: Queue ( α )  Boolean ;

3. EnQueue: Queue ( α )  α  Queue ( α );

4. GetHead: Non_null_queue ( α )  α;

5. DeQueue: Non_null_queue ( α )  Queue ( α ).

Приведем набор аксиом, справедливых для данных операций. Пусть p — значение типа α; q —queue ( α ):

A1. IsNull ( Create ) = true ;

A2. IsNull ( EnQueue ( q , p ) ) = false ;

A3. GetHead ( EnQueue ( q , p ) ) =

если IsNull ( q ) то p иначе Head ( q );

A4. DeQueue ( EnQueue ( q , p ) ) = 

если IsNull(q) то Create иначе EnQueue(DeQueue(q),p).

2.1.3. Деки

Иногда используют списки, в которых вставка и удаление элементов выполняются с обоих концов. Такой список называется деком. (сокращение от английского double ended queue-очередь с двумя концами).

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

Формальную спецификацию дека можно выполнить аналогично стеку или очереди.

2.1.4. Общие замечания по реализации атд

Прежде чем перейти к реализации конкретных АТД, сделаем несколько общих замечаний.

Реализация АТД, в отличие от его формальной спецификации, существенно зависит от выбранного языка программирования и подхода к реализации. Язык С++ предоставляет программисту различные механизмы реализации АТД:

  • отдельно определить стуктуру данных и базовые функции — структурный подход;

  • определить АТД в виде структуры (struct) или класса (class), при этом базовые функции включить в состав данной структуры или класса как методы — объектно-ориентированный подход.

Объектно-ориентированный подход является более предпочтительным. В данной главе будем использовать структуры (struct), включающие операции (базовые функции) как методы. При таком подходе операция создания пустого стека, очереди или дека (в спецификации Create) обычно реализуется как конструктор — специальный метод, который автоматически выполняется при создании переменной и имеет имя, совпадающее с именем структуры.

Примечаение

Заметим, что при реализации линейных структур на основе массивов память под массив можно захватить динамически в конструкторе, при этом появится возможность управлять максимальными размерами (в языке С++ разрешены конструкторы с параметрами). Оставим это для самостоятельной реализации.

В формальной спецификации АТД предполагается, что его элементы могут иметь любой тип (но обязательно один и тот же). В языке С++ имеется два способа сделать описание структуры независимым от типа элементов— оператор typedef и шаблоны (template).

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

С этой точки зрения оператор typedef представляет компромиссный вариант, поскольку он все-таки предполагает присутствие конкретного типа элементов, но только в самом операторе typedef. Для изменения типа достаточно поменять только этот оператор typedef (можно вообще поместить этот оператор в отдельный файл, который подключать с помощью директивы #include).

В примерах будут продемонстрированы оба подхода, но для лучшей читаемости кода в основном будет использоваться оператор typedef. Заметим, что в С++ имеется специальная библиотека STL (Standart Template Library), содержащая шаблонные классы для наиболее востребованных структур данных, поэтому большинство примеров реализации АТД, приведенных далее, следует рассматривать всего лишь как демонстрацию рассматриваемых подходов и алгоритмов.

При реализации АТД важную проблему представляет обработка аварийных ситуаций, которая может выполняться по-разному. В примерах реализован самый простой способ — сообщение об ошибке посылается в стандартный выходной поток cerr и выполнение программы прекращается. Можно предложить и другие варианты, например, использование исключительных ситуаций (в С++ конструкция try … catch), самое главное — не допустить неправильной работы функций в подобных крайних случаях.