Структуры данных: стеки и очереди
Записи и оператор with
Записи используются для создания своих типов данных
{ Обьявление записи - тип "Точка" } type TPoint = Record x,y : double; end; { Функция, вычисляющая расстояние между точками } function dist( A,B : TPoint ):double; begin dist := sqrt( (A.x - B.x)*(A.x - B.x) + (A.y - B.y)*(A.y - B.y) ); end; { Использование записей } var A,B : TPoint; begin { Инициализируем координаты точек } A.x := 1; A.y := 2; B.x := 10; B.y := 11; writeln( dist(A,B) ); end.
Использование with:
{ Обьявление записи - тип "Персонаж в игре" } type TUnit = Record x,y : integer; { Координаты клетки где стоит персонаж } name : string; { Имя персонажа } end; var Unit1 : TUnit; { Инициализация без with } Unit1.x := 2; Unit1.y := 3; Unit1.name := 'SUPER-HERO'; { Инициализация с with } with Unit1 do begin x := 2; y := 3; name := 'SUPER-HERO'; end;
Реализация Стека и Очереди на базе массива
Стек (англ. stack — стопка) — структура данных с методом доступа к элементам LIFO (англ. Last In — First Out, «последним пришёл — первым вышел»). Чаще всего принцип работы стека сравнивают со стопкой тарелок: чтобы взять вторую сверху, нужно снять верхнюю.
const StackSize = 10000; { Размер стека (сколько в него можно положить элементов) } { === Хранение стека === } var Stack : array [1..StackSize] of Integer; { Массив для хранения стека } StackTop : Integer = 0; { Вершина стека - индекс в массиве Stack } { === Операции со стеком === } { Стек пуст? } function isEmpty : Boolean; begin isEmpty := StackTop = 0; end; { Положить значение на вершину стека } procedure Push( Value : Integer ); begin assert( StackTop < StackSize, 'Стек полон! Больше положить в него нельзя!'); Inc(StackTop); Stack[StackTop] := Value; end; { Забрать значение с вершины стека } function Pop : Integer; begin assert( not isEmpty, 'Нельзя извлечь элемент, потому что стек пуст!'); Pop := Stack[StackTop]; Dec( StackTop ); end; { === Тестирование работы стека === } begin Writeln(isEmpty); { Выводит "TRUE" - стек пуст } Push(2); { В стеке: 2 } Writeln(isEmpty); { Выводит "FALSE" - стек не пуст } Push(5); { В стеке: 2, 5 } Writeln(Pop); { Выводит "5", в стеке: 2 } Writeln(Pop); { Выводит "2", в стеке пусто } end.
Очередь — структура данных с дисциплиной доступа к элементам «первый пришёл — первый вышел» (FIFO, First In — First Out). Добавление элемента (принято обозначать словом enqueue — поставить в очередь) возможно лишь в конец очереди, выборка — только из начала очереди (что принято называть словом dequeue — убрать из очереди), при этом выбранный элемент из очереди удаляется.
const QSize = 10000; { Размер очереди (сколько в неё можно положить элементов) } var Q : array [1..QSize] of Integer; { Массив для хранения очереди } Q_Start : Integer = 1; { Указывает на голову очереди } Q_End : Integer = 1; { Указывает на элемент, который заполнится, когда в очередь войдёт новый элемент } { = Операции с очередью = } { Очередь пуста? } function isEmpty : Boolean; begin isEmpty := Q_Start = Q_End; end; { Положить значение в конец очереди } procedure Put( Value : Integer ); begin Q[Q_End] := Value; Dec(Q_End); { Поддержка закольцованности очереди } if Q_End < 1 then Q_End := QSize; end; { Забрать значение с начала очереди } function Get : Integer; begin assert( not isEmpty, 'В очереди ничего нет!'); Get := Q[Q_Start]; Dec(Q_Start); { Поддержка закольцованности очереди } if Q_Start < 1 then Q_Start := QSize; end; begin Writeln(isEmpty); { Выводит "TRUE" - очередь пуста } Put(2); { В очереди: 2 } Writeln(isEmpty); { Выводит "FALSE" - очередь не пуста } Put(5); { В очереди: 5, 2 } Writeln(Get); { Выводит "2", в очереди: 5 } Writeln(Get); { Выводит "5", в очереди пусто } end.
Реализация на C/C++
Реализация Стека
#include <iostream> #include <assert.h> using namespace std; // Определение класса Стек // Шаблон с двумя параметрами: // T - тип элемента (например: int, char, char*) // size - размер стека (целое число) template <typename T,int size> class Stack{ T data[size]; // Данные стека int count; // Количество элементов в стеке // count указывает на ячейку после последнего элемента в стеке // Например, если count = 1, то последний элемент это data[0] public: // Конструктор Stack(){ count = 0; }; // Стек пуст? bool isEmpty(){ return count <= 0; }; // Стек полон? bool isFull(){ return count >= size; }; // Добавить на вершину стека void push(T value){ assert(!isFull()); // Можно добавить только если стек ещё не полон data[count++] = value; // Записываем значение в массив и сдвигаем счётчик вправо } // Снять с вершины стека T pop(){ assert(!isEmpty()); // Можно снять только если стек не пуст return data[--count]; // Уменьшаем счётчик (сдвигаем влево) и возвращаем значение } }; // Основная программа - тестирование стека int main() { Stack<int,5> s; // Создаём пример стека assert(s.isEmpty()); // Сейчас стек должен быть пустым s.push(5); // Добавляем один элемент assert(!s.isEmpty()); assert(s.pop() == 5); assert(s.isEmpty()); assert(!s.isFull()); s.push(1); s.push(2); s.push(3); s.push(4); assert(!s.isFull()); // Стек ещё не полон после добавления четвёртого элемента s.push(5); assert(s.isFull()); Stack<char,2> cs; // Заводим другой пример стека - с символами в качестве элементов cs.push('a'); return 0; }
Реализация очереди (циклической очереди)
#include <iostream> #include <assert.h> using namespace std; // Определение класса Очередь // Шаблон с двумя параметрами: // T - тип элемента (например: int, char, char*) // size - размер очереди (целое число) template <typename T,int size> class Queue{ T data[size]; // Данные очереди int head; // Голова очереди (первый элемент) int tail; // Хвост очереди (последний элемент) public: // Конструктор Queue(){ head = -1; tail = 0; }; // Очередь пуста? bool isEmpty(){ return head < tail; }; // Очередь полна? bool isFull(){ return len() >= size; }; // Текущая длина очереди int len(){ return head-tail+1; }; // Добавить в начало очереди void put(T value){ assert(!isFull()); // Можно добавить только если очередь не полна ++head; // Сдвигаем голову вправо data[head % size] = value; // Записываем в ячейку с номером по модулю // ----------------------------------------- // | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | // ----------------------------------------- // Количество ячеек - 10, максимальный размер очереди - 10 // Куда должен пойти 10-ый элемент? На 0-ую позицию // Куда должен пойти 20-ый элемент? Тоже на 0-ую позицию // Цикличность очереди обепечивается тем, что мы индекс элемента всегда берём по модулю максимального размера очереди } // Взять из конца очереди T get(){ assert(!isEmpty()); // Можно снять только если очередь не полна return data[tail++ % size]; // Забираем значение из хвоста и двигаем хвост вправо } }; // Основная программа - тестирование стека int main() { Queue<int,5> s; // Создаём пример стека assert(s.isEmpty()); // Сейчас очередь должна быть пуста s.put(5); // Добавляем один элемент assert(!s.isEmpty()); assert(s.get() == 5); assert(s.isEmpty()); assert(!s.isFull()); s.put(1); s.put(2); s.put(3); s.put(4); assert(!s.isFull()); s.put(5); assert(s.isFull()); return 0; }