БлогNot. Шаблон для класса очереди фиксированного размера

Шаблон для класса очереди фиксированного размера

Далее показан несложный шаблон класса-очереди ограниченной ёмкости (не более size элементов, 1≤size≤SIZE).

В очереди сохраняется не более size последних помещённых туда элементов, самые старые удаляются.

Наверное, самое простое решение, чтобы сделать шаблон для любых скалярных типов - предусмотреть дополнительный аргумент конструктора (назовём его NaN), принимающий значение, которым будут помечаться пустые элементы. Ведь просто (T)0 не обязано везде работать, а typeid(T).name() тоже не обязано возвращать одно и то же в разных средах.

Также мне было нужно, чтобы очередь потенциально не переполнялась по достижении счётчиками значения INT_MAX, поэтому "сквозной нумерации" элементов в коде нет.

Существенно и то, что методы set и get ничего не знают о порядке своего вызова, можно попытаться получить элемент до добавления, добавлять элементы бесконечно и т.п.

Лучший контроль за значением переменной i, которой мы разрешаем меняться в пределах от 0 до size-1 включительно, выглядит как i++; i %= size;

Ниже приводится исходник, проверенный в Dev C++ 4.9.X, Visual Studio 2015 и QT 5.10.X

#include <iostream>
#include <string>
using namespace std;

template <class T> class queue {
 static const int SIZE = 100; //Максимальная размерность
 T q[SIZE]; //Данные
 T NaN; //Признак пустой очереди
 int from, to, size; //Начало, конец, реальная размерность
 int cnt; //Добавлено за последний цикл добавления
public:
 queue (int,T); //Конструктор
 void put (T); //Положить элемент
 T get (); //Забрать элемент
 void show (string); //Вывести с заголовком
};

template <class T> queue<T>::queue (int size, T NaN) {
 from = to = cnt = 0;
 if (size < 1) size = 1;
 if (size > SIZE) size = SIZE;
 this->size = size;
 for (int i=0; i<size; i++) q[i] = NaN;
 this->NaN = NaN;
}

template <class T> void queue<T>::put (T item) {
 if (!cnt) from = to = 0;
 q[to++] = item;
 to %= size;
 cnt++;
 if (cnt > size) {
  cnt = size;
  from++;
  from %= size;
 }
}

template <class T> T queue<T>::get () {
 if (!cnt) return NaN;
 T item = q[from];
 q[from++] = NaN;
 from %= size;
 cnt--;
 return item;
}

template <class T> void queue<T>::show (string msg) {
 cout << endl << msg << ": ";
 for (int i=0; i < size; i++) cout << q[i] << " ";
 cout << endl;
}

int main() {
 queue <int> q (2, 0);
 const int size = 3;
 for (int i=1; i <= size; i++) q.put (i);
 for (int i=1; i <= size; i++) {
  int n = q.get();
  cout << n << " ";
  //не выводить несколько выражений q.get() в одном операторе,
  //будет неверно определена точка следования!
 }
 cout << endl; //2 3 0
 q.put (4);
 cout << q.get() << endl; //4
 cout << q.get() << endl; //0

 const int size2 = 3;
 queue <string> s(size2,"(null)");
 cout << s.get() << endl; //(null)
 s.put("Lilu");
 s.put("Afty");
 for (int i=0; i<size2; i++) {
  string str = s.get();
  cout << str << " "; //Lilu Afty (null)
 }

 cin.get(); return 0;
}

теги: c++ алгоритм

03.09.2019, 16:08; рейтинг: 43