Опубликован: 08.04.2009 | Уровень: для всех | Доступ: платный
Лекция 6:

Типы данных

< Лекция 5 || Лекция 6: 123456 || Лекция 7 >

6.2. Очереди

Значениями типа "очередь элементов типа T ", как и для стеков, являются последовательности значений типа T. Разница состоит в том, что берутся элементы не с конца, а с начала (а добавляются по-прежнему в конец).

Операции с очередями:

  • Сделать_пустой ( var x: очередь элементов типа T );
  • Добавить ( t:T, var x: очередь элементов типа T );
  • Взять ( var t:T, var x: очередь элементов типа T );
  • Пуста ( x: очередь элементов типа T ): boolean ;
  • Очередной ( x: очередь элементов типа T ): T.

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

Английские названия стеков - Last In First Out (последним вошел - первым вышел), а очередей - First In First Out (первым вошел - первым вышел). Сокращения: LIFO, FIFO.

Реализация очередей в массиве

6.2.1. Реализовать операции с очередью ограниченной длины так, чтобы количество действий для каждой операции было ограничено константой, не зависящей от длины очереди.

Решение. Будем хранить элементы очереди в соседних элементах массива. Тогда очередь будет прирастать справа и убывать слева. Поскольку при этом она может дойти до края, свернем массив в окружность.

Введем массив

Содержание: array [0..n-1] of T

и переменные

Первый: 0..n-1,
Длина : 0..n.

При этом элементами очереди будут

\begin{multiline*}
{Содержание [Первый]}, {Содержание [Первый+1]}, \ldots,\\
%
      {Содержание [Первый+Длина-1]},
\end{multiline*}
где сложение выполняется по модулю n. (Предупреждение. Если вместо этого ввести переменные Первый и Последний, значения которых - вычеты по модулю n, то пустая очередь может быть спутана с очередью из n элементов.)

Операции выполняются так.

Сделать пустой:

Длина := 0;
Первый := 0;

Добавить элемент:

{Длина < n}
Содержание [(Первый + Длина) mod n] := элемент;
Длина := Длина + 1;

Взять элемент:

{Длина > 0}
элемент := Содержание [Первый];
Первый := (Первый + 1) mod n;
Длина := Длина - 1;

Пуста:

Длина = 0

Очередной:

Содержание [Первый]

6.2.2. (Сообщил А.Г. Кушниренко) Придумать способ моделирования очереди с помощью двух стеков (и фиксированного числа переменных типа T ). При этом отработка n операций с очередью (начатых, когда очередь была пуста) должна требовать порядка n действий.

Решение. Инвариант: \textsl{стеки, составленные концами,
образуют очередь}. (Перечисляя элементы одного стека вглубь и затем элементы второго наружу, мы перечисляем все элементы очереди от первого до последнего.) Ясно, что добавление сводится к добавлению к одному из стеков, а проверка пустоты - к проверке пустоты обоих стеков. Если мы хотим взять элемент, есть два случая. Если стек, где находится начало очереди, не пуст, то берем из него элемент. Если он пуст, то предварительно переписываем в него все элементы второго стека, меняя порядок (это происходит само собой при перекладывании из стека в стек) и сводим дело к первому случаю. Хотя число действий на этом шаге и не ограничено константой, но требование задачи выполнено, так как каждый элемент очереди может участвовать в этом процессе не более одного раза.

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

6.2.4. (Сообщил А.Г. Кушниренко.) Имеется дек элементов типа T и конечное число переменных типа T и целого типа. В начальном состоянии в деке некоторое число элементов. Составить программу, после исполнения которой в деке остались бы те же самые элементы, а их число было бы в одной из целых переменных.

Указание. (1) Элементы дека можно циклически переставлять, забирая с одного конца и помещая в другой. После этого, сделав столько же шагов в обратном направлении, можно вернуть все на место. (2) Как понять, прошли мы полный круг или не прошли? Если бы какой-то элемент заведомо отсутствовал в деке, то можно было бы его подсунуть и ждать вторичного появления. Но таких элементов нет. Вместо этого можно для данного n выполнить циклический сдвиг на n дважды, подсунув разные элементы, и посмотреть, появятся ли разные элементы через n шагов.

< Лекция 5 || Лекция 6: 123456 || Лекция 7 >
Татьяна Новикова
Татьяна Новикова
Россия, Пошатово
Artem Bardakov
Artem Bardakov
Россия