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

Очередь функционирует по принципу FIFO – first-in-first-out: «первым вошел – первым вышел».

В повседневной жизни очереди встречаются часто. Например, очередь к кассе в магазине.

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

Существует несколько способов реализации очереди:

    с помощью одномерного массива; с помощью связанного списка; с помощью класса объектно-ориентированного программирования.

Основные операции с очередью:

НЕ нашли? Не то? Что вы ищете?
    запись элемента в очередь (если это возможно, т. е. нет переполнения массива). чтение элемента из очереди (если очередь не пуста).

В очереди, в силу ее определения, доступны две позиции:

    ее начало (head «голова») , откуда извлекаются (обслуживаются) элементы; ее конец (tail «хвост») , куда заносятся новые элементы (ставятся в очередь на обслуживание).

Рассмотрим очередь, реализованную на одномерном массиве.

const size=8;

var a:array[0..size]of integer;

  i, x,n, top:integer;

Начальное состояние: head = 0;

  tail = 0;

Запись элемента: a[tail]:= x;

  tail:= (tail+1) mod n;

Чтение элемента: x:=a[head];

  head:= (head+1) mod n;



0

13

0

1

5

  head 

2

8

3

9

4

14

5

5

6

tail

7


  Рис. 1. Пример очереди

На рис.1 приведено состояние очереди в определенный момент времени (n = 8). Элементы записывались в очередь так: 13, 5, 8, 9, 14, начиная с нулевого элемента массива a. Чтения не было. Доступный для извлечения  (обслуживания) элемент очереди – 13, он определяетсязначением указателя head. Место для записи (постановки в очередь) определяется указателем tile.

Если бы начало очереди всегда совпадало с первым элементом массива (индекс 0), то при удалении элемента из очереди потребовалось бы сдвигать все оставшиеся элементы к началу массива. Это приводило бы к неэффективности программы. Существует другой способ, при котором элементы очереди не сдвигаются – это использование «циклического массива» или «кольца». Суть этого способа заключается в том, что вычисление  head и tail при чтении и записи элементов осуществляется по модулю числа  n. Например, после записи в ячейку с номером 7 осуществляется запись в ячейку с индексом 0, если она, конечно свободна. Аналогично и при чтении элементов.

Замечание. Именно кольцевая очередь используется на практике, в том числе в качестве буферной памяти клавиатуры. Часто при зацикливании программ в операционных системах MS-DOS или Windows вводимые с клавиатуры и поступающие в её буфер данные не считываются из этого буфера – очередь переполняется. Индикацией этого события является звуковой сигнал.

Рассмотрим два примера:

    На рис.2а изображено состояние очереди после чтения элементов 13, 5, 8, 9, 14. Оба указателя показывают на одну и ту же ячейку (номер 5), т. е. head = tail. Это признак того, что очередь пустая. На рис.2б изображено состояние очереди, когда сначала было выполнено чтение элементов 13 и 5, а затем записаны элементы 25, 6, 9, 10, 45. Оба указателя показывают на одну и ту же ячейку (номер 2), т. е. head = tail. Это признак того, что очередь заполнена.

0

5

0

10

2

1

head

1

45

head

2

2

8

3

3

9

4

4

14

5

5

5

25

2

6

tail

6

6

tile

7

7

9



  а)  б)

  Рис. 2. Очередь: a)пуста - head = tail, б)заполнена - head = tail

Имеем два неразличимых на уровне значения переменных head и tail состояния очереди. Как определить, очередь пуста (Empty) или заполнена  (Full)? Для разрешения этой ситуации нужно ввести логическую переменную, например, p для фиксации факта «кто кого догнал». В первом случае, когда очередь пуста  - head догнал tail ( Рис. 2а), а во втором случае, когда очередь полна – tail догнал head  (Рис. 2б). Начальное значение переменной p = true, а при переходе как того, так и другого указателей (head и tail) через значение n она изменяет свое значение на противоположное. Для рассматриваемых примеров, в первом случае (Рис.2а) – p = true, а во втором (рис.2б) – p = false, так как мы уже один раз перешли через значение n (указатель tail).

Основные процедуры и функции для работы с очередью


Определение заполнена очередь или нет.

Function Queue_Full(head, tail:integer; p:boolean):boolean;

Begin if (head = tail) and not p then Queue_Full:= true

  else Queue_Full:= false;

end;

  2. Определение пустая очередь или нет.

Function Queue_Empty(head, tail:integer; p:boolean):boolean;

Begin if (head = tail) and p then Queue_ Empty:= true

  else Queue_ Empty:= false;

end;

Запись элемента в очередь.

Procedure Queue_Write( var tail:integer; var p:boolean;x:integer);

Begin a[tail]:= x;

  tail:= (tail+1) mod n;

  if tail = 0 then p:=not p;

end;


Чтение элемента из очереди.

Procedure Queue_Read( var head:integer; var p:boolean; var x:integer);

Begin x:=a[head];

  head:= (head+1) mod n

  if head = 0 then p:=not p;

end;

Существует еще одна линейная динамическая структура данных, которая называется  дек.

Дек – это линейный список, в котором можно добавлять и удалять элементы как с одного, так и с другого конца.

Из определения следует, что дек может работать и как стек и как очередь.

Ссылки и материалы:

1. http://prog-cpp. ru/data-queue/

2. http://www. tdoc. ru/c/programming/pascal/turbopascal-encyclopaedia-page21.html

3. http://kvodo. ru/queue. html

4. https://www. intuit. ru/studies/courses/2193/67/lecture/1980?page=3

5. Абстрактные типы данных, БИНОМ 2009г.

6. , Информатика. Углубленный уровень. Учебник для 11 класса. Часть 2.