Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование очередей кольцевой обработки д...docx
Скачиваний:
6
Добавлен:
10.09.2019
Размер:
80.94 Кб
Скачать

Алгоритм кругового обслуживания

Очередь с круговым буфером является удобной и естественной абстрактной структурой данных для моделирования обхода элементов по кругу в условиях задачи Иосифа по алгоритму, который можно условно назвать алгоритмом кругового обслуживания. Алгоритм кругового обслуживания составляет следующая последовательность шагов:

1. Заготовить пустую очередь с размером кольцевого буфера на 1 больше, чем число обслуживаемых элементов.  2. Применяя примитив ENQUEUE соответствующее число раз, разместить номера всех обслуживаемых элементов в кольцевом буфере очереди, что эквивалентно расположению элементов по кругу.  3. Чередуя вызовы примитивов DEQUEUE и ENQUEUE необходимое число раз, добиться, чтобы в голове очереди оказался элемент с желаемым номером.  4. Инициализировать счетчик шагов по кругу значением 1.  5. Чередовать вызовы примитивов DEQUEUE и ENQUEUE при увеличении значения счетчика шагов, пока оно не достигнет заданного порогового значения. Эти действия эквивалентны обходу круга, чтобы достигнуть элемент, который нужно удалить из очереди. Исключаемый элемент будет находиться в голове очереди.  6. Используя процедуру DEQUEUE удалить элемент из головы очереди и распечатать его номер.  7. Проверить выполнение условия пустой очереди (tail=head). Если в очереди еще остались элементы, перейти на шаг 4 для продолжения анализа очередности удаления элементов. Иначе, если очередь пуста, завершить выполнение алгоритма.

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

#define SIZE 100 // Максимальная длина очереди

int QUEUE[SIZE]; // Массив элементов очереди

int head; // Указатели на первый элемент очереди

int tail; // Указатель на следующий свободный за последним

void Clear() { head = tail = 0;} // Очистить очередь

int Enq(int val) // Поставить в конец очереди

{

int next;

if ((next = (tail+1) % SIZE) == head)

return(0); // Переполнение очереди

QUEUE[tail] = val;

head = next;

return(1);

}

int Deq() // Взять из начала очереди

{

int val;

if (head == tail) return(0); // Очередь пуста

val = QUEUE[head++]; //

head %= SIZE; // По достижении fst==SIZE

return(val); // сбрасывается в 0

}

Программирование очереди с кольцевым буфером.

Для программирования целесообразно применить принцип инкапсуляции объектно-ориентированного программирования, сосредоточив описание структуры очереди и примитивов ее обработки в отдельном классе RingQueue. Организация класса RingQueue должна быть ориентирована на применение его в качестве базового класса для построения производных классов, обладающих спецификой обработки кольцевой очереди в различных приложениях.  Класс RingQueue должен содержать защищенные (protected) компоненты-данные и общедоступные (public) компонентные методы их обработки. Это обеспечит доступ к данным класса только собственными компонентными методами или компонентными методами производного класса, но исключит возможность непосредственного несанкционированного обращения к ним из любых внешних функций программы.  Чтобы исключить зависимость компонентов класса RingQueue от типа элементов очереди, при его проектировании удобно воспользоваться средствами параметризации классов и функций, поддержка которых обеспечена в любых версиях системы программирования С++, начиная с USL 3.0. Параметризация класса осуществляется с помощью шаблона (template), который декларирует абстрактные типы данных как параметры класса.  Шаблон помогает компилятору сгенерировать определение конкретного класса по образу и подобию заданной схемы. Параметры класса использованы для абстрактной типизации компонент-данных или кодов возврата и аргументов компонентных методов класса.

Шаблоны функций. Часто встречаются функции, реализующие одни и те же действия для аргументов различных типов. Например, сортировка массива по возрастанию его элементов может выполняться одним и тем же методом и для данных типа int и для данных типа double. Различие состоит только в типах параметров и некоторых внутренних переменных. Подставим вместо конкретного типа данных некоторый абстрактный тип, который, в зависимости от ситуации, будет заменен на реальный тип данных - и, таким образом, мы сможем сгенерировать тот же самый код для какого угодно типа данных. В С++ включено специальное средство, позволяющее параметризовать определение функции, чтобы компилятор мог построить конкретную реализацию функции для указанного типа параметров функции. Параметризованное определение функции строится по схеме:

template < class имя_класса >           Заголовок функции       { /* Тело функции */ }

Имя класса является параметром и задается идентификатором, локализованным в пределах определения функции. Хотя бы один из параметров функции должен иметь тип, соответствующий этому идентификатору.  Вызов функции queue ( aint, 10 ) обеспечит вызов queue для упорядочения массива целых, а вызов функции queue ( adbl , 20 ) обеспечит вызов queue для упорядочения массива с элементами типа double. http://pgworld.narod.ru/doc/inprborcpp/objborcpp/5.htm

В данном случае в шаблоне класса RingQueue может быть объявлен абстрактный тип <class QType>, обозначающий тип элементов очереди. Учитывая синтаксические особенности шаблонов классов в системе программирования С++, декларация логической структуры класса RingQueue может иметь следующий формат:

  template <class QType> class RingQueue    {    protected:  //спецификация компонент-данных 

QType* qbuf:  /*абстрактный тип QType является параметром из шаблона класса, размером qbuf. Конкретизация типа параметризованных компонент шаблонного класса должна быть выполнена либо в производном нешаблонном классе или при определении объекта класса*/  int qsize;    //размер очереди   int head;     //указатель головы очереди  int tail;     //указатель на хвост очереди   public:  /*спецификация прототипов компонентных методов*/