3.2. Параметризованные очереди и стеки

Очередь представляет собой линейный список, доступ к элементам которого осуществляется по принципу FIFO («первым вошел – первым вышел»).

Рассмотрим две функции обслуживания очереди: qstore() и qretrieve(). Функция qstore() помещает элемент в конец очереди, а функция qretrieve() извлекает из очереди первый элемент и возвращает его значение.

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

// очередь элементов типа Qtype

#include <conio.h>       //библиотека консольного ввода-вывода

#include <iostream.h>    //библиотека потокового ввода-вывода

#include <stdlib.h>            //стандартная библиотека

template <class Qtype> class queue

{

Qtype *q;         // массив элементов очереди

int sloc, rloc;   // последний записанный элемент

                   // и последний прочитанный

int length;       // размер очереди

public:

queue(int size);  // конструктор

~queue() { delete [] q;} //деструктор

void qstore(Qtype i); //запись в конец очереди

Qtype qretrieve(); // получение первого элемента очереди

};

// конструктор

template <class Qtype>

queue <Qtype>:: queue(int size)

{

size++; // размер на 1 больше

q = new Qtype[size]; //выделим память

if(!q) //если не удалось выделить память

{

       cout << "nнет памяти для очереди"; exit(1);

}

length = size;   //длина очереди   

sloc = rloc = 0; // начало и конец очереди

}

// запись в очередь

template <class Qtype>

void queue <Qtype>:: qstore(Qtype i)

{

if(sloc+1 == length) //если нельзя сместить указатель на конец

{

       cout << "Очередь переполненаn";

       return;

}

sloc++; //смещаем указатель

q[sloc] = i; //записываем элемент

}

// чтение и удаление из очереди

template <class Qtype>

Qtype queue <Qtype> :: qretrieve()

{

if(rloc == sloc) //если указатель на конец равен указателю на начало

{

       cout << "nОчередь пуста ";

       return 0;

}

rloc++; return q[rloc];

}

// пример использования очереди

main()

{

clrscr();               //очистка экрана

queue <int> a(10), b(10); //две очереди с целыми числами

queue <double> c(10);   //одна очередь с числами с плавающей точкой

  a.qstore(100);

a.qstore(200);

b.qstore(300);

b.qstore(400);

cout<<"Первый элемент очереди а "<<a.qretrieve()<<" n";//выведет 100

cout<<"Второй элемент очереди а "<<a.qretrieve()<<" "; // выведет 200

cout << a.qretrieve() << " n"; // "очередь пуста"

c.qstore(-1);

c.qstore(-2);

cout<<"Первый элемент очереди с "<<c.qretrieve()<<" "; //выведет -1

return 0;

}

Результат работы программы

Первый элемент очереди а 100

Второй элемент очереди а 200

Очередь пуста 0

Первый элемент очереди с –1

В данном примере после записи и чтения десяти элементов очереди индекс sloc будет указывать на конец массива, в результате чего дальнейшее использование очереди станет невозможным. Чтобы исправить этот недостаток, индекс последнего записанного элемента при достижении конца массива устанавливается на начало. При такой реализации программы в очередь можно будет поместить любое количество элементов, при условии, что элементы не только помещаются в очередь, но и извлекаются из нее. Такая реализация очереди называется циклической очередью, поскольку она использует массив, в котором хранятся элементы очереди, как циклический список.

Приведём текст программы, имеющей те же самые результаты, что и в предыдущем примере, но использующей в своей работе циклическую очередь.

// очередь элементов типа Qtype

#include <conio.h>       //библиотека консольного ввода-вывода

#include <iostream.h>    //библиотека потокового ввода-вывода

#include <stdlib.h>            //стандартная библиотека

template <class Qtype> class queue

{

Qtype *q;         // массив элементов очереди

int sloc, rloc;   // последний записанный элемент

                   // и последний прочитанный

int length;       // размер очереди

public:

queue(int size);  // конструктор

~queue() { delete [] q;} //деструктор

void qstore(Qtype i); //запись в конец очереди

Qtype qretrieve(); // получение первого элемента очереди

};

// конструктор

template <class Qtype>

queue <Qtype>:: queue(int size)

{

size++; // размер на 1 больше

q = new Qtype[size]; //выделим память

if(!q) //если не удалось выделить память

{

       cout << "nнет памяти для очереди"; exit(1);

}

length = size;   //длина очереди   

sloc = rloc = 0; // начало и конец очереди

}

// запись в очередь

template <class Qtype>

void queue <Qtype>::qstore(Qtype i) // добавление

{

if((sloc+1 == rloc) || (sloc+1 == length) && !rloc)

{

       cout << "nОчередь переполнена"; return;

}

q[sloc] = i; sloc++;

if(sloc == length) sloc = 0;         // циклический список

}

// чтение и удаление из очереди

template <class Qtype>

Qtype queue <Qtype>:: qretrieve()

{

if(rloc == length) rloc = 0;

if(rloc == sloc)

{

       cout << "nОчередь пуста"; return 0;

}

rloc++;

return q[rloc-1];

}

// пример использования очереди

main()

{

clrscr();               //очистка экрана

queue <int> a(10), b(10); //две очереди с целыми числами

queue <double> c(10);   //одна очередь с числами с плавающей точкой

a.qstore(100);

a.qstore(200);

b.qstore(300);

b.qstore(400);

cout<<"Первый элемент очереди а "<<a.qretrieve()<<" n";//выведет 100

cout<<"Второй элемент очереди а "<<a.qretrieve()<<" "; // выведет 200

cout << a.qretrieve() << " n"; // "очередь пуста"

c.qstore(-1);

c.qstore(-2);

cout<<"Первый элемент очереди с "<<c.qretrieve()<<" "; //выведет -1

return 0;

}

Результат работы программы

Первый элемент очереди а 100

Второй элемент очереди а 200

Очередь пуста 0

Первый элемент очереди с –1

Стек представляет собой линейный список, доступ к элементам которого осуществляется по принципу LIFOпоследним вошел – первым вышел»).        

Две основные операции традиционно называются pop() (извлечение) и push() (добавление).        

Приведенная ниже программа реализует параметризованный класс стека.

//программа, использующая стек       

#include <conio.h>       //библиотека консольного ввода-вывода

#include <iostream.h>   //библиотека потокового ввода-вывода

#include <stdlib.h>     //стандартная библиотека

template <class Stype>

class stack              //класс стека

{

Stype *s;               // массив, содержащий элементы стека

int tos;                // число записанных элементов

int length;             // размер стека

public:

stack(int size);        // конструктор

~stack() {delete [] s;} // освобождение памяти

void push(Stype i);     // запись элемента в стек

Stype pop();            // извлечение элемента из стека

};

// конструктор

template <class Stype>

stack <Stype>:: stack(int size)

{

s = new Stype[size];    // захват памяти

if(!s)                  // если s=0

{

       cout << "nНет памяти для стека";

       exit(1);

}

length = size; tos = 0; // вершина стека

}

// запись объекта в стек

template <class Stype>

void stack <Stype>:: push(Stype i)

{

if(tos == length)       //если длина стека — максимум

{

       cout << "nСтек переполнен";

       return;

}

s[tos++] = i;            //сохраняем элемент в стеке

}

// чтение и удаление объекта из стека

template <class Stype>

Stype stack <Stype>:: pop()

{

if(tos == 0)

{

cout << "nСтек пуст"; return 0;

}

return s[—tos];         //получение элемента из стека

}

// примеры использования стека

main()

{

stack <int>        a(10); // стек целых чисел

stack <double> b(10);     // стек чисел с плавающей точкой

clrscr();                 // очистка экрана

a.push(10);               // запись в стек a

b.push(-1);               // запись в стек b

a.push(20);               // запись в стек a

cout <<"Последний элемент стека а "<< a.pop()<<"n";// вывод числа 20

cout <<"Последний элемент стека b "<< b.pop();      // вывод числа -1

return 0;

}

Результат работы программы

Последний элемент стека а 20

Последний элемент стека b -1