Collections — различия между версиями

Материал из Вики ИТ мехмата ЮФУ
Перейти к: навигация, поиск
м (Правки 87.117.8.39 (обсуждение) откачены к версии Juliet)
Строка 1: Строка 1:
 
[[Категория:Коды]]
 
[[Категория:Коды]]
 
__TOC__
 
__TOC__
== Collections ==
+
== Nodes (вспомогательный модуль) ==
 
<source lang="Delphi">
 
<source lang="Delphi">
 
/// Модуль содержит шаблоны классов
 
/// Модуль содержит шаблоны классов
///  Stack стек
+
///  SingleNode узла с одним полем связи
///  Queue очередь
+
///  DoubleNode узла с двумя полями связи
///  DynArray — динамический массив
+
unit Nodes;
///  SimpleSet — простое множество на основе динамического массива
 
///  AssocArray — простой ассоциативный массив на основе динамического массива пар
 
///  LinkedList — двусвязный список
 
unit Collections;
 
  
//------------------------------------------------------------------------------
 
// Модуль упрощенных классов коллекций для обучения
 
// Версия 1.0
 
// Copyright (c) 2009 Белякова Ю., Михалкович С.С., Саатчи А.
 
//------------------------------------------------------------------------------
 
 
 
interface
 
interface
+
 
// -------------------------------- SingleNode ---------------------------------
 
 
type
 
type
 +
 +
//-------------------------------------------SINGLE_NODE-------------------------------------------
 
   /// Узел с одним полем связи
 
   /// Узел с одним полем связи
   SingleNode<T> = class
+
   SingleNode<DataType> = class
  private
+
     /// Значение узла
     /// Значение, содержащееся в узле
+
     data: DataType;
     fData: T;
 
 
     /// Ссылка на следующий элемент
 
     /// Ссылка на следующий элемент
     fNext: SingleNode<T>;
+
     next: SingleNode<DataType>;
  public
+
   
 
     /// <summary>
 
     /// <summary>
     /// Создает узел с одним полем связи
+
     /// Конструктор
 
     /// </summary>
 
     /// </summary>
     /// <param name="pData">Значение в узле</param>
+
     /// <param name="pData">Значение узла</param>
 
     /// <param name="pNext">Ссылка на следующий элемент</param>
 
     /// <param name="pNext">Ссылка на следующий элемент</param>
     constructor Create(data: T; next: SingleNode<T>);
+
     constructor Create(pData: DataType; pNext: SingleNode<DataType>);
    begin
+
  end;
      fData := data;
+
 
      fNext := next;
+
// -------------------------------------------DOUBLE_NODE------------------------------------------ 
    end;
+
  /// Узел с двумя полями связи
     /// Значение, содержащееся в узле
+
  DoubleNode<DataType> = class
     property Data: T read fData write fData;
+
     /// Значение узла
 +
     data: DataType;
 
     /// Ссылка на следующий элемент
 
     /// Ссылка на следующий элемент
     property Next: SingleNode<T> read fNext write fNext;
+
     next: DoubleNode<DataType>;
   end;  
+
    /// Ссылка на предыдущий элемент
 +
    prev: DoubleNode<DataType>;
 +
   
 +
    /// <summary>
 +
    /// Конструктор
 +
    /// </summary>
 +
    /// <param name="pData">Значение узла</param>
 +
    /// <param name="pNext">Ссылка на следующий элемент</param>
 +
    /// <param name="pPrev">Ссылка на предыдущий элемент</param>
 +
    constructor Create(pData: DataType; pPrev, pNext: DoubleNode<DataType>);
 +
  end;
 +
 
 +
implementation
 +
 
 +
//-------------------------------------------SINGLE_NODE-------------------------------------------
 +
{Конструктор
 +
    pData — значение узла
 +
    pNext — cсылка на следующий элемент}
 +
constructor SingleNode<DataType>.Create(pData: DataType; pNext: SingleNode<DataType>);
 +
begin
 +
  data := pData;
 +
  next := pNext;
 +
end;
 +
 
 +
// -------------------------------------------DOUBLE_NODE------------------------------------------ 
 +
{Конструктор
 +
    pData — значение узла
 +
    pNext — cсылка на следующий элемент
 +
    pPrev — ссылка на предыдущий элемент}
 +
constructor DoubleNode<DataType>.Create(pData: DataType; pPrev, pNext: DoubleNode<DataType>);
 +
begin
 +
  data := pData;
 +
  next := pNext;
 +
   prev := pPrev;
 +
end;
 +
 
 +
end.
 +
</source>
 +
 
 +
== Collections ==
 +
<source lang="Delphi">
 +
/// Модуль содержит шаблоны классов
 +
///  Stack — стек
 +
///  Queue — очередь
 +
///  DynArray — динамический массив с автоконтролем памяти
 +
///  SimpleSet — простое множество (с минимальным набором операций)
 +
///  AssocArray — ассоциативный массив
 +
///  LinkedListNode — узел с двумя полями связи
 +
///  LinkedList — двусвязный линейный список
 +
unit Collections;
 
   
 
   
// ----------------------------------- Stack -----------------------------------
+
interface
 +
 +
uses Nodes;  // для использования типа SingleNode<DataType> —
 +
              // узла с одним полем связи
 +
 +
 +
// ============================================= Stack ============================================
 
type
 
type
   /// Шаблон класса Stack
+
   /// Шаблон класса Stack [Стек]
   Stack<T> = class
+
   Stack<DataType> = class
 
   private  
 
   private  
 +
    // ----------------------------------- Поля ----------------------------------
 
     /// Вершина стека
 
     /// Вершина стека
     fTop: SingleNode<T> := nil;  
+
     fTop: SingleNode<DataType> := nil;  
 +
 
   public  
 
   public  
 +
    // ---------------------------- Стандартные методы ---------------------------
 
     /// Создает пустой стек
 
     /// Создает пустой стек
 
     constructor Create;
 
     constructor Create;
 +
 
     /// <summary>
 
     /// <summary>
 
     /// Кладет элемент x на вершину стека
 
     /// Кладет элемент x на вершину стека
 
     /// </summary>
 
     /// </summary>
 
     /// <param name="x">Новый элемент</param>
 
     /// <param name="x">Новый элемент</param>
     procedure Push(x: T);
+
     procedure Push(x: DataType);
 
     /// Возвращает значение элемента на вершине, снимая его со стека
 
     /// Возвращает значение элемента на вершине, снимая его со стека
     function Pop: T;  
+
     function Pop: DataType;
 
     /// Возвращает значение элемента на вершине стека, не снимая его
 
     /// Возвращает значение элемента на вершине стека, не снимая его
     function Top: T;
+
     function Top: DataType;
 +
 
     /// Возвращает истину, если стек пуст
 
     /// Возвращает истину, если стек пуст
 
     function IsEmpty: boolean;  
 
     function IsEmpty: boolean;  
     /// Преобразует содержимое стека в строку
+
   
    function ToString: string; override;
+
     // ---------------------------------- Вывод ----------------------------------
 
     /// Выводит содержимое стека на консоль
 
     /// Выводит содержимое стека на консоль
    procedure Print;
+
     procedure Println();
    /// Выводит содержимое стека на консоль с переходом на новую строку
 
     procedure Println;
 
 
   end;
 
   end;
 
   
 
   
// ----------------------------------- Queue -----------------------------------
+
 +
// ============================================= Queue ============================================
 
type   
 
type   
   /// Шаблон класса Queue
+
   /// Шаблон класса Queue [Очередь]
   Queue<T> = class
+
   Queue<DataType> = class
 
   private
 
   private
 +
    // ----------------------------------- Поля ----------------------------------
 
     /// Голова очереди
 
     /// Голова очереди
     fHead: SingleNode<T>;
+
     head: SingleNode<DataType>;
 
     /// Хвост очереди
 
     /// Хвост очереди
     fTail: SingleNode<T>;
+
     tail: SingleNode<DataType>;
 +
 
   public
 
   public
 +
    // ---------------------------- Стандартные методы ---------------------------
 
     /// Создает пустую очередь
 
     /// Создает пустую очередь
 
     constructor Create;
 
     constructor Create;
 +
 
     /// <summary>
 
     /// <summary>
 
     /// Добавляет элемент x в хвост очереди
 
     /// Добавляет элемент x в хвост очереди
 
     /// </summary>
 
     /// </summary>
 
     /// <param name="x">Добавляемый элемент</param>
 
     /// <param name="x">Добавляемый элемент</param>
     procedure Enqueue(x: T);
+
     procedure Enqueue(x: DataType);
 
     /// Возвращает значение элемента в голове, удаляя его из очереди
 
     /// Возвращает значение элемента в голове, удаляя его из очереди
     function Dequeue: T;
+
     function Dequeue: DataType;
 
     /// Возвращает значение элемента в голове очереди, не удаляя его
 
     /// Возвращает значение элемента в голове очереди, не удаляя его
     function First: T;
+
     function Top: DataType;
 +
 
     /// Возвращает истину, если очередь пуста
 
     /// Возвращает истину, если очередь пуста
 
     function IsEmpty: boolean;
 
     function IsEmpty: boolean;
     /// Преобразует содержимое очереди в строку
+
    function ToString: string; override;
+
     // ---------------------------------- Вывод ----------------------------------
 
     /// Выводит содержимое очереди на консоль
 
     /// Выводит содержимое очереди на консоль
    procedure Print;
+
     procedure Println();
    /// Выводит содержимое очереди на консоль с переходом на новую строку
 
     procedure Println;
 
 
   end;
 
   end;
 
   
 
   
// --------------------------------- DynArray ----------------------------------
+
 +
// =========================================== DynArray ==========================================
 
const
 
const
 
   /// Минимальная емкость, устанавливаемая при создании массива
 
   /// Минимальная емкость, устанавливаемая при создании массива
Строка 114: Строка 168:
 
   
 
   
 
type
 
type
   /// Шаблон класса DynArray (Динамический массив с автоконтролем памяти)
+
   /// Шаблон класса DynArray [Динамический массив с автоконтролем памяти]
   DynArray<T> = class
+
   DynArray<DataType> = class
 
   private
 
   private
 +
    // ----------------------------------- Поля ----------------------------------
 
     /// Встроенный динамический массив, содержащий данные
 
     /// Встроенный динамический массив, содержащий данные
     fData: array of T;
+
     data: array of DataType;
 
     /// Размер массива
 
     /// Размер массива
     fSize: integer;
+
     size: integer;
 
     /// Емкость массива
 
     /// Емкость массива
     fCap: integer;
+
     cap: integer;
     /// Устанавливает элемент с индексом index равным x
+
   
     procedure SetElem(index: integer; x: T);
+
    // ----------------------------- Сеттеры/Геттеры -----------------------------
     /// Возвращает элемент массива с индексом index
+
     /// Устанавливает элемент с индексом ind равным x
     function GetElem(index: integer): T;
+
     procedure SetElem(ind: integer; x: DataType);
 +
     /// Возвращает элемент массива с индексом ind
 +
     function GetElem(ind: integer): DataType;
 +
 
   public
 
   public
     /// Создает пустой массив
+
     // ---------------------------- Стандартные методы ---------------------------
    constructor Create;
+
     /// Создает массив размера pSize
     /// Создает массив размера size
+
     constructor Create(pSize: integer := 0);
     constructor Create(size: integer);
+
 
     /// <summary>
 
     /// <summary>
     /// Выделяет новую память. Емкость увеличивается до NewSize.
+
     /// Выделяет новую память. Емкость увеличивается до newCap.
 
     /// (Если newCap меньше текущей емкости, ничего не происходит)  
 
     /// (Если newCap меньше текущей емкости, ничего не происходит)  
 
     /// </summary>
 
     /// </summary>
Строка 143: Строка 201:
 
     /// <param name="newSize">Новый размер массива</param>
 
     /// <param name="newSize">Новый размер массива</param>
 
     procedure Resize(newSize: integer);
 
     procedure Resize(newSize: integer);
 +
 
     /// <summary>
 
     /// <summary>
 
     /// Добавляет элемент x в конец массива  
 
     /// Добавляет элемент x в конец массива  
 
     /// </summary>
 
     /// </summary>
 
     /// <param name="x">Добавляемый элемент</param>
 
     /// <param name="x">Добавляемый элемент</param>
     procedure Add(x: T);
+
     procedure Add(x: DataType);
 
     /// <summary>
 
     /// <summary>
     /// Вставляет элемент x в указанную позицию pos
+
     /// Вставляет элемент x в позицию pos
 
     /// </summary>
 
     /// </summary>
 
     /// <param name="pos">Позиция, в которую вставляется элемент</param>
 
     /// <param name="pos">Позиция, в которую вставляется элемент</param>
 
     /// <param name="x">Вставляемый элемент</param>
 
     /// <param name="x">Вставляемый элемент</param>
     procedure Insert(pos: integer; x: T);
+
     procedure Insert(pos: integer; x: DataType);
 
     /// <summary>
 
     /// <summary>
     /// Удаляет элемент массива из указанной позиции pos
+
     /// Удаляет элемент массива из позиции pos
 
     /// </summary>
 
     /// </summary>
 
     /// <param name="pos">Позиция, из которой удаляется элемент</param>
 
     /// <param name="pos">Позиция, из которой удаляется элемент</param>
 
     procedure Remove(pos: integer);
 
     procedure Remove(pos: integer);
 +
 
     /// <summary>
 
     /// <summary>
 
     /// Возвращает индекс первого элемента массива равного x
 
     /// Возвращает индекс первого элемента массива равного x
Строка 164: Строка 224:
 
     /// </summary>
 
     /// </summary>
 
     /// <param name="x">Искомый элемент</param>
 
     /// <param name="x">Искомый элемент</param>
     function Find(x: T): integer;
+
     function Find(x: DataType): integer;
 +
   
 +
    // --------------------------------- Свойства --------------------------------
 
     /// Количество элементов (размер) массива
 
     /// Количество элементов (размер) массива
     property Count: integer read fSize write Resize;
+
     property Count: integer read size write Resize;
     /// Емкость массива  
+
     /// Емкость массива (отведенная память)
     property Capacity: integer read fCap write Reserve;
+
     property Capacity: integer read cap write Reserve;
 +
 
     /// Позволяет обращаться к элементам массива по индексу  
 
     /// Позволяет обращаться к элементам массива по индексу  
     property Elem[index: integer]: T read GetElem write SetElem; default;
+
    /// (например, apples[5])
     /// Преобразует содержимое массива в строку
+
     property Elem[index: integer]: DataType read GetElem write SetElem; default;
    function ToString: string; override;
+
 +
     // ---------------------------------- Вывод ----------------------------------
 
     /// Выводит содержимое массива на консоль
 
     /// Выводит содержимое массива на консоль
     procedure Print;
+
     procedure Println();
     /// Выводит содержимое массива на консоль с переходом на новую строку
+
     /// Выводит содержимое массива на консоль в обратном порядке
     procedure Println;
+
     procedure PrintlnReverse();
 
   end;
 
   end;
 
   
 
   
// -------------------------------- SimpleSet ----------------------------------
+
 +
// =========================================== SimpleSet =========================================
 
type  
 
type  
   /// Шаблон класса SimpleSet (Простое множество на основе динамического массива)
+
   /// Шаблон класса SimpleSet [Простое множество]
   SimpleSet<T> = class  
+
   SimpleSet<DataType> = class  
 
   private
 
   private
 +
    // ----------------------------------- Поля ----------------------------------
 
     /// Элементы множества
 
     /// Элементы множества
     fData: DynArray<T>;
+
     data := new DynArray<DataType>;
 +
 
   public
 
   public
     /// Создает множество
+
     // ---------------------------- Стандартные методы ---------------------------
    constructor Create;
 
 
     /// <summary>
 
     /// <summary>
 
     /// Добавляет элемент x во множество, если его там еще нет
 
     /// Добавляет элемент x во множество, если его там еще нет
 
     /// </summary>
 
     /// </summary>
 
     /// <param name="x">Добавляемый элемент</param>     
 
     /// <param name="x">Добавляемый элемент</param>     
     procedure Add(x: T);
+
     procedure Add(x: DataType);
 
     /// <summary>
 
     /// <summary>
 
     /// Удаляет элемент x из множества, если он там есть
 
     /// Удаляет элемент x из множества, если он там есть
 
     /// </summary>
 
     /// </summary>
 
     /// <param name="x">Удаляемый элемент</param>
 
     /// <param name="x">Удаляемый элемент</param>
     procedure Remove(x: T);
+
     procedure Remove(x: DataType);
 +
 
     /// <summary>
 
     /// <summary>
 
     /// Возвращает истину, если множество содержит элемент x
 
     /// Возвращает истину, если множество содержит элемент x
 
     /// </summary>
 
     /// </summary>
 
     /// <param name="x">Искомый элемент</param>           
 
     /// <param name="x">Искомый элемент</param>           
     function Contains(x: T): boolean;   
+
     function Contains(x: DataType): boolean;   
    /// Преобразует содержимое массива в строку
+
    function ToString: string; override;
+
     // ---------------------------------- Вывод ----------------------------------
     /// Выводит содержимое массива на консоль
+
     ///Выводит содержимое множества на консоль
    procedure Print;
+
     procedure Println();
     /// Выводит содержимое множества на консоль с переходом на новую строку
 
     procedure Println;
 
 
end;
 
end;
 +
 
   
 
   
// -------------------------------- AssocArray ---------------------------------
+
// =========================================== AssocArray ========================================
 
type
 
type
   /// Шаблон класса AssocArray  
+
   /// Шаблон класса AssocArray [Ассоциативный массив]
 
   AssocArray<KeyType, ValueType> = class
 
   AssocArray<KeyType, ValueType> = class
 
   private
 
   private
 +
    // ----------------------------------- Поля ----------------------------------
 
     /// Ключи
 
     /// Ключи
     fKeys: DynArray<KeyType>;
+
     keys: DynArray<KeyType> := new DynArray<KeyType>;
 
     /// Значения, соответствующие ключам
 
     /// Значения, соответствующие ключам
     fValues: DynArray<ValueType>;
+
     values: DynArray<ValueType> := new DynArray<ValueType>;
 
+
   
 +
    // ----------------------------- Сеттеры/Геттеры -----------------------------
 
     /// Устанавливает значение элемента с ключом key равным value
 
     /// Устанавливает значение элемента с ключом key равным value
 
     procedure SetElem(key: KeyType; value: ValueType);
 
     procedure SetElem(key: KeyType; value: ValueType);
 
     /// Возвращает значение элемента с ключом key
 
     /// Возвращает значение элемента с ключом key
 
     function GetElem(key: KeyType): ValueType;
 
     function GetElem(key: KeyType): ValueType;
 +
 
   public
 
   public
     /// Создает ассоциативный массив
+
     // --------------------------------- Свойства --------------------------------
    constructor Create;
 
 
     /// Позволяет обращаться к элементам массива по ключу
 
     /// Позволяет обращаться к элементам массива по ключу
 +
    /// (Например, zoo['крокодил'])
 
     property Elem[key: KeyType]: ValueType read GetElem write SetElem; default;
 
     property Elem[key: KeyType]: ValueType read GetElem write SetElem; default;
     /// Преобразует содержимое ассоциативного массива в строку
+
      
    function ToString: string; override;
+
     // ---------------------------------- Вывод ----------------------------------
     /// Выводит содержимое ассоциативного массива на консоль
+
     ///Выводит содержимое ассоциативного массива на консоль
    procedure Print;
+
     procedure Println();
     /// Выводит содержимое ассоциативного массива на консоль с переходом на новую строку
 
     procedure Println;
 
 
   end;
 
   end;
+
 
// ----------------------------- LinkedListNode --------------------------------
+
 
 +
// ========================================= LinkedListNode =======================================
 
type
 
type
 
   /// Узел с двумя полями связи
 
   /// Узел с двумя полями связи
   LinkedListNode<T> = class
+
   LinkedListNode<DataType> = class
 
   private
 
   private
     /// Значение, содержащееся в узле
+
    // ----------------------------------- Поля ----------------------------------
     fData: T;
+
     /// Значение узла
 +
     fData: DataType;
 
     /// Ссылка на предыдущий элемент
 
     /// Ссылка на предыдущий элемент
     fPrev: LinkedListNode<T>;
+
     fPrev: LinkedListNode<DataType>;
 
     /// Ссылка на следующий элемент
 
     /// Ссылка на следующий элемент
     fNext: LinkedListNode<T>;
+
     fNext: LinkedListNode<DataType>;
 +
   
 
   public
 
   public
 +
    // --------------------------------- Свойства --------------------------------
 +
    /// Значение узла
 +
    property Value: DataType read fData write fData;
 +
    /// Ссылка на предыдущий элемент — только на чтение
 +
    property Prev: LinkedListNode<DataType> read fPrev;
 +
    /// Ссылка на следующий элемент — только на чтение
 +
    property Next: LinkedListNode<DataType> read fNext;
 +
   
 +
    // ---------------------------- Стандартные методы ---------------------------
 
     /// <summary>
 
     /// <summary>
 
     /// Создает новый узел
 
     /// Создает новый узел
 
     /// </summary>
 
     /// </summary>
     /// <param name="T">Значение узла</param>
+
     /// <param name="DataType">Значение узла</param>
 
     /// <param name="Prev">Ссылка на предыдущий элемент</param>
 
     /// <param name="Prev">Ссылка на предыдущий элемент</param>
 
     /// <param name="Next">Ссылка на следующий элемент</param>
 
     /// <param name="Next">Ссылка на следующий элемент</param>
     constructor Create(data: T; prev, next: LinkedListNode<T>);
+
     constructor Create(Data: DataType; Prev, Next: LinkedListNode<DataType>);
    begin
 
      fData := data;
 
      fNext := next;
 
      fPrev := prev;
 
    end;
 
    /// Значение, содержащееся в узле
 
    property Value: T read fData write fData;
 
    /// Ссылка на предыдущий элемент — только на чтение
 
    property Prev: LinkedListNode<T> read fPrev;
 
    /// Ссылка на следующий элемент — только на чтение
 
    property Next: LinkedListNode<T> read fNext;
 
 
   end;
 
   end;
 
    
 
    
 
    
 
    
// -------------------------------- LinkedList ---------------------------------
+
// =========================================== LinkedList =========================================
 
type
 
type
 
   /// Двусвязный линейный список
 
   /// Двусвязный линейный список
   LinkedList<T> = class
+
   LinkedList<DataType> = class
 
   private
 
   private
 +
    // ----------------------------------- Поля ----------------------------------
 
     /// Первый элемент (голова)
 
     /// Первый элемент (голова)
     fFirst: LinkedListNode<T>;
+
     fFirst: LinkedListNode<DataType> := nil;
 
     /// Последний элемент (хвост)
 
     /// Последний элемент (хвост)
     fLast: LinkedListNode<T>;
+
     fLast: LinkedListNode<DataType> := nil;
 +
   
 
   public
 
   public
     /// Создает пустой список
+
     // --------------------------------- Свойства --------------------------------
    constructor Create;
 
 
     /// Первый элемент (голова) — только на чтение
 
     /// Первый элемент (голова) — только на чтение
     property First: LinkedListNode<T> read fFirst;
+
     property First: LinkedListNode<DataType> read fFirst;
 
     /// Последний элемент (хвост) — только на чтение
 
     /// Последний элемент (хвост) — только на чтение
     property Last: LinkedListNode<T> read fLast;
+
     property Last: LinkedListNode<DataType> read fLast;
 +
   
 +
    // ---------------------------- Стандартные методы ---------------------------
 
     /// <summary>
 
     /// <summary>
 
     /// Добавляет элемент x в начало списка
 
     /// Добавляет элемент x в начало списка
 
     /// </summary>
 
     /// </summary>
 
     /// <param name="x">Добавляемый элемент</param>
 
     /// <param name="x">Добавляемый элемент</param>
     procedure AddFirst(x: T);
+
     procedure AddFirst(x: DataType);
 
     /// <summary>
 
     /// <summary>
 
     /// Добавляет элемент x в конец списка
 
     /// Добавляет элемент x в конец списка
 
     /// </summary>
 
     /// </summary>
 
     /// <param name="x">Добавляемый элемент</param>
 
     /// <param name="x">Добавляемый элемент</param>
     procedure AddLast(x: T);
+
     procedure AddLast(x: DataType);
 +
   
 
     /// Удаляет первый элемент списка
 
     /// Удаляет первый элемент списка
 
     procedure RemoveFirst();
 
     procedure RemoveFirst();
 
     /// Удаляет последний элемент списка
 
     /// Удаляет последний элемент списка
 
     procedure RemoveLast();
 
     procedure RemoveLast();
 +
   
 
     /// <summary>
 
     /// <summary>
 
     /// Добавляет элемент x перед node
 
     /// Добавляет элемент x перед node
Строка 307: Строка 380:
 
     /// <param name="node">Ссылка на элемент, перед которым нужно добавить новый</param>
 
     /// <param name="node">Ссылка на элемент, перед которым нужно добавить новый</param>
 
     /// <param name="x">Добавляемый элемент</param>
 
     /// <param name="x">Добавляемый элемент</param>
     procedure AddBefore(node: LinkedListNode<T>; x: T);  
+
     procedure AddBefore(node: LinkedListNode<DataType>; x: DataType);  
 
     /// <summary>
 
     /// <summary>
 
     /// Добавляет элемент x после node
 
     /// Добавляет элемент x после node
Строка 313: Строка 386:
 
     /// <param name="node">Ссылка на элемент, после которого нужно добавить новый</param>
 
     /// <param name="node">Ссылка на элемент, после которого нужно добавить новый</param>
 
     /// <param name="x">Добавляемый элемент</param>
 
     /// <param name="x">Добавляемый элемент</param>
     procedure AddAfter(node: LinkedListNode<T>; x: T);
+
     procedure AddAfter(node: LinkedListNode<DataType>; x: DataType);
 +
   
 
     /// <summary>
 
     /// <summary>
 
     /// Удаляет элемент node
 
     /// Удаляет элемент node
 
     /// </summary>
 
     /// </summary>
 
     /// <param name="node">Ссылка на элемент, который нужно удалить</param>
 
     /// <param name="node">Ссылка на элемент, который нужно удалить</param>
     procedure Remove(node: LinkedListNode<T>);
+
     procedure Remove(node: LinkedListNode<DataType>);
     /// Преобразует содержимое списка в строку
+
   
    function ToString: string; override;
+
     // ---------------------------------- Вывод ----------------------------------
 
     /// Выводит содержимое списка на консоль
 
     /// Выводит содержимое списка на консоль
     procedure Print;
+
     procedure Println();
     /// Выводит содержимое списка на консоль с переходом на новую строку
+
     /// Выводит содержимое списка на консоль в обратном порядке
     procedure Println;
+
     procedure ReversePrintln();
 
   end;
 
   end;
 
   
 
   
//==============================================================================
+
 
implementation
 
implementation
 
   
 
   
//Сообщения исключений
+
const PopNilStackExceptionMessage = 'Попытка снятия элемента с пустого стека';
+
// ============================================= Stack ============================================
TopNilStackExceptionMessage = 'Попытка получения элемента с пустого стека';
+
       
+
// ---------------------------- Стандартные методы ---------------------------
DequeueNilQueueExceptionMessage = 'Попытка удаления элемента из пустой очереди';
+
{Создает пустой стек}
FirstNilQueueExceptionMessage = 'Попытка получения элемента из пустой очереди';
+
constructor Stack<DataType>.Create;
       
 
NegativeArraySizeExceptionMessage = 'Попытка присвоить размеру массива отрицательное значение ';
 
      InsOutOfArrayBoundExceptionMessage ='Попытка вставки за границей массива в позицию ';
 
      RemOutOfArrayBoundExceptionMessage ='Попытка удаления за границей массива из позиции ';
 
      SetElemOutOfBoundExceptionMessage = 'Попытка присвоить значение элементу за границей массива с индексом ';
 
      GetElemOutOfBoundExceptionMessage = 'Попытка получить значение элемента за границей массива с индексом ';
 
     
 
RemoveFromNilListExceptionMessage = 'Попытка удаления из пустого списка';
 
AddNilNodeExceptionMessage = 'Параметр node является нулевой ссылкой';
 
RemoveNilNodeExceptionMessage = 'Параметр node является нулевой ссылкой';
 
 
// ----------------------------------- Stack -----------------------------------
 
constructor Stack<T>.Create;
 
 
begin
 
begin
 
   fTop := nil;
 
   fTop := nil;
 
end;
 
end;
 
   
 
   
procedure Stack<T>.Push(x: T);
+
{Кладет элемент x на вершину стека}
 +
procedure Stack<DataType>.Push(x: DataType);
 
begin
 
begin
   fTop := new SingleNode<T>(x, fTop);
+
   fTop := new SingleNode<DataType>(x, fTop);
 
end;
 
end;
 
   
 
   
function Stack<T>.Pop: T;
+
{Возвращает значение элемента на вершине, снимая его со стека}
 +
function Stack<DataType>.Pop: DataType;
 
begin
 
begin
 
   if IsEmpty then  
 
   if IsEmpty then  
     raise new Exception(PopNilStackExceptionMessage);
+
     raise new Exception('Попытка снятия элемента с пустого стека!');
 
   
 
   
   Result := fTop.data;
+
   result := fTop.data;
   fTop := fTop.next;  // элемент удаляется из вершины стека (т.е. вершиной становится следующий элемент)
+
   fTop := fTop.next;  // элемент снимается с вершины стека
 +
                      // (т.е. вершиной становится следующий элемент)
 
end;
 
end;
 
   
 
   
function Stack<T>.Top: T;
+
{Возвращает значение элемента на вершине стека, не снимая его}
 +
function Stack<DataType>.Top: DataType;
 
begin
 
begin
 
   if IsEmpty then  
 
   if IsEmpty then  
     raise new Exception(TopNilStackExceptionMessage);
+
     raise new Exception('Попытка получения элемента с пустого стека!');
 
   
 
   
   Result := fTop.data;
+
   result := fTop.data;
 
end;
 
end;
 
+
function Stack<T>.IsEmpty: boolean;
+
{Возвращает истину, если стек пуст}
 +
function Stack<DataType>.IsEmpty: boolean;
 
begin
 
begin
   Result := (fTop = nil);
+
   result := (fTop = nil);
 
end;
 
end;
 
   
 
   
function Stack<T>.ToString: string;
+
// ---------------------------------- Вывод ----------------------------------
 +
{Выводит содержимое стека на консоль}
 +
procedure Stack<DataType>.Println();
 
begin
 
begin
   Result := '';
+
   if not IsEmpty then
  var curElem := fTop;
 
  while curElem <> nil do
 
 
   begin
 
   begin
     Result += curElem.data.ToString + ' ';
+
     var curElem := fTop;
    curElem := curElem.next;
+
 +
    while curElem <> nil do
 +
    begin
 +
      write(curElem.data, ' ');
 +
      curElem := curElem.next;
 +
    end;
 
   end;
 
   end;
 +
  writeln();
 
end;
 
end;
 
   
 
   
procedure Stack<T>.Print;
 
begin
 
  write(ToString);
 
end;
 
 
   
 
   
procedure Stack<T>.Println;
+
// ============================================= Queue ============================================
begin
 
  writeln(ToString);
 
end;
 
 
   
 
   
// ----------------------------------- Queue -----------------------------------
+
// ---------------------------- Стандартные методы ---------------------------
constructor Queue<T>.Create;
+
{Создает пустую очередь}
 +
constructor Queue<DataType>.Create;
 
begin
 
begin
   fHead := nil;
+
   head := nil;
   fTail := nil;
+
   tail := nil;
 
end;
 
end;
 
   
 
   
procedure Queue<T>.Enqueue(x: T);
+
{Добавляет элемент x в хвост очереди}
 +
procedure Queue<DataType>.Enqueue(x: DataType);
 
begin
 
begin
 
   if IsEmpty then
 
   if IsEmpty then
 
   begin
 
   begin
     fHead := new SingleNode<T>(x, nil);
+
     head := new SingleNode<DataType>(x, nil);
     fTail := fHead;
+
     tail := head;
 
   end
 
   end
 
   else
 
   else
 
   begin
 
   begin
     fTail.next := new SingleNode<T>(x, nil);
+
     tail.next := new SingleNode<DataType>(x, nil);
     fTail := fTail.next;  // элемент удаляется из хвоста очереди (т.е. хвостом становится следующий элемент)
+
     tail := tail.next;  // элемент удаляется из хвоста очереди
 +
                        // (т.е. хвостом становится следующий элемент)
 
   end;
 
   end;
 
end;
 
end;
 
   
 
   
function Queue<T>.Dequeue: T;
+
{Возвращает значение элемента в голове, удаляя его из очереди}
 +
function Queue<DataType>.Dequeue: DataType;
 
begin
 
begin
 
   if IsEmpty then  
 
   if IsEmpty then  
     raise new Exception(DequeueNilQueueExceptionMessage);
+
     raise new Exception('Попытка удаления элемента из пустой очереди!');
 
   
 
   
   Result := fHead.data;
+
   result := head.data;
   fHead := fHead.next;  // элемент удаляется из головы очереди (т.е. головой становится следующий элемент)
+
   head := head.next;  // элемент удаляется из головы очереди
   if fHead = nil then
+
                      // (т.е. головой становится следующий элемент)
     fTail := nil;
+
   if head = nil then
 +
     tail := nil;
 
end;
 
end;
 
   
 
   
function Queue<T>.First: T;
+
{Возвращает значение элемента в голове очереди, не удаляя его}
 +
function Queue<DataType>.Top: DataType;
 
begin
 
begin
 
   if IsEmpty then  
 
   if IsEmpty then  
     raise new Exception(FirstNilQueueExceptionMessage);
+
     raise new Exception('Попытка получения элемента из пустой очереди!');
   
+
   Result := fHead.data;
+
   result := head.data;
 
end;
 
end;
 
   
 
   
function Queue<T>.IsEmpty: boolean;
+
{Возвращает истину, если очередь пуста}
 +
function Queue<DataType>.IsEmpty: boolean;
 
begin
 
begin
   Result := (fHead = nil);
+
   result := (head = nil);
   if Result then
+
   if result then
     Assert(fTail = nil);
+
     Assert(tail = nil);
 
end;
 
end;
 
   
 
   
function Queue<T>.ToString: string;
+
// ---------------------------------- Вывод ----------------------------------
 +
{Выводит содержимое очереди на консоль}
 +
procedure Queue<DataType>.Println();
 
begin
 
begin
   Result := '';
+
   if not IsEmpty then
  var curElem := fHead;
 
  while curElem <> fTail do
 
 
   begin
 
   begin
     Result += curElem.data.ToString + ' ';
+
     var curElem := head;
    curElem := curElem.next;
+
 +
    while curElem <> nil do
 +
    begin
 +
      write(curElem.data, ' ');
 +
      curElem := curElem.next;
 +
    end;
 
   end;
 
   end;
   Result += curElem.data.ToString;
+
   writeln();
 
end;
 
end;
 +
 +
 +
// =========================================== DynArray ==========================================
  
procedure Queue<T>.Print;
+
// ----------------------------- Сеттеры/Геттеры -----------------------------
 +
{Устанавливает элемент с индексом ind равным x}
 +
procedure DynArray<DataType>.SetElem(ind: integer; x: DataType);
 
begin
 
begin
   write(ToString);
+
   if (ind < 0) or (ind > size-1) then
end;  
+
    raise new Exception(
 +
    'Попытка присвоить значение элементу за границей массива с индексом ' + IntToStr(ind) + '!');
 
   
 
   
procedure Queue<T>.Println;
+
   data[ind] := x;
begin
 
   writeln(ToString);
 
 
end;
 
end;
 
   
 
   
// ---------------------------------- DynArray ---------------------------------
+
{Возвращает элемент массива с индексом ind}
constructor DynArray<T>.Create;
+
function DynArray<DataType>.GetElem(ind: integer): DataType;
 
begin
 
begin
   Create(0);
+
   if (ind < 0) or (ind > size-1) then
 +
    raise new Exception(
 +
    'Попытка получить значение элемента за границей массива с индексом ' + IntToStr(ind) + '!');
 +
 +
  result := data[ind];
 
end;
 
end;
  
constructor DynArray<T>.Create(size: integer);
+
// ---------------------------- Стандартные методы ---------------------------
 +
{Создает массив размера pSize}
 +
constructor DynArray<DataType>.Create(pSize: integer);
 
begin
 
begin
   if size < 0 then
+
   if pSize < 0 then
     raise new Exception(NegativeArraySizeExceptionMessage + size.ToString);
+
     raise new Exception('Попытка присвоить размеру массива отрицательное значение ' + IntToStr(pSize) + '!');
 
   
 
   
   fSize := size;
+
   size := pSize;
   fCap := INC_CAP_FACTOR*size + MIN_CAP; // Устанавливаем емкость "с запасом"
+
   cap := INC_CAP_FACTOR*pSize + MIN_CAP; // Устанавливаем емкость "с запасом"
   SetLength(fData, fCap);
+
   SetLength(data, cap);
 
end;
 
end;
 
   
 
   
procedure DynArray<T>.Reserve(newCap: integer);
+
{Выделяет новую память. Емкость увеличивается до newCap.
 +
(Если newCap меньше текущей емкости, ничего не происходит) }
 +
procedure DynArray<DataType>.Reserve(newCap: integer);
 
begin
 
begin
   if newCap > fCap then  
+
   if newCap > cap then  
 
   begin
 
   begin
     SetLength(fData, newCap);
+
     SetLength(data, newCap);
     fCap := newCap;
+
     cap := newCap;
 
   end;
 
   end;
 
end;
 
end;
 
   
 
   
procedure DynArray<T>.Resize(newSize: integer);
+
{Устанавливает новый размер массива равным newSize}
 +
procedure DynArray<DataType>.Resize(newSize: integer);
 
begin
 
begin
 
   if newSize < 0 then
 
   if newSize < 0 then
     raise new Exception(NegativeArraySizeExceptionMessage + newSize.ToString);
+
     raise new Exception('Попытка присвоить размеру массива отрицательное значение ' + IntToStr(newSize) + '!');
 
   
 
   
   if newSize > fCap then
+
   if newSize > cap then
 
   begin
 
   begin
 
     Reserve(INC_CAP_FACTOR * newSize);
 
     Reserve(INC_CAP_FACTOR * newSize);
     for var i := fSize to newSize - 1 do // явным образом заполняем новые элементы
+
     for var i := size to newSize - 1 do // явным образом заполняем новые элементы
       fData[i] := default(T);
+
       data[i] := default(DataType);
 
   end;
 
   end;
   fSize := newSize;
+
   size := newSize;
 
end;
 
end;
 
   
 
   
procedure DynArray<T>.Add(x: T);
+
{Добавляет элемент x в конец массива }
 +
procedure DynArray<DataType>.Add(x: DataType);
 
begin
 
begin
   Resize(fSize + 1);
+
   Resize(size + 1);
   fData[fSize-1] := x;
+
   data[size-1] := x;
 
end;
 
end;
 
   
 
   
procedure DynArray<T>.Insert(pos: integer; x: T);
+
{Вставляет x элемент в позицию pos}
 +
procedure DynArray<DataType>.Insert(pos: integer; x: DataType);
 
begin
 
begin
   if (pos < 0) or (pos > fSize-1) then  
+
   if (pos < 0) or (pos > size-1) then  
     raise new Exception(InsOutOfArrayBoundExceptionMessage + pos.ToString);
+
     raise new Exception(
 +
    'Попытка вставки за границей массива в позицию ' + IntToStr(pos) + '!');
 
   
 
   
   Resize(fSize + 1);
+
   Resize(size + 1);
   for var i := fSize - 2 downto pos do // сдвиг элементов на 1 вправо, до позиции pos
+
   for var i := size - 2 downto pos do
     fData[i+1] := fData[i];
+
     data[i+1] := data[i];
   fData[pos] := x;
+
   data[pos] := x;
 
end;
 
end;
 
   
 
   
procedure DynArray<T>.Remove(pos: integer);
+
{Удаляет элемент массива из позиции pos}
 +
procedure DynArray<DataType>.Remove(pos: integer);
 
begin
 
begin
   if (pos < 0) or (pos > fSize-1) then  
+
   if (pos < 0) or (pos > size-1) then  
    raise new Exception(RemOutOfArrayBoundExceptionMessage + pos.ToString);
+
    raise new Exception(
 +
    'Попытка удаления за границей массива из позиции ' + IntToStr(pos) + '!');
 
   
 
   
   for var i := pos to fSize - 2 do     // сдвиг элементов влево на 1, начиная с позиции pos
+
   for var i := pos to size - 2 do // сдвиг элементов влево на 1, начиная с позиции pos
     fData[i] := fData[i+1];
+
     data[i] := data[i+1];
   Resize(fSize - 1);
+
   Resize(size - 1);
 
end;
 
end;
 
   
 
   
function DynArray<T>.Find(x: T): integer;
+
{Возвращает индекс первого элемента массива равного x
 +
или -1, если такого элемента нет}
 +
function DynArray<DataType>.Find(x: DataType): integer;
 
begin
 
begin
   Result := -1;
+
   result := -1;
   for var i := 0 to fSize - 1 do
+
   for var i := 0 to size - 1 do
     if fData[i].Equals(x) then
+
     if data[i] = x then
 
     begin
 
     begin
       Result := i;
+
       result := i;
 
       exit;
 
       exit;
 
     end;
 
     end;
 
end;
 
end;
 
   
 
   
procedure DynArray<T>.SetElem(index: integer; x: T);
+
// ---------------------------------- Вывод ----------------------------------
begin
+
{Выводит содержимое массива на консоль}
  if (index < 0) or (index > fSize-1) then
+
procedure DynArray<DataType>.Println();
    raise new Exception(SetElemOutOfBoundExceptionMessage + index.ToString);
 
 
  fData[index] := x;
 
end;
 
 
{Возвращает элемент массива с индексом index}
 
function DynArray<T>.GetElem(index: integer): T;
 
 
begin
 
begin
   if (index < 0) or (index > fSize-1) then
+
   for var i := 0 to size - 1 do
    raise new Exception(GetElemOutOfBoundExceptionMessage + index.ToString);
+
      write(data[i], ' ');  
+
   writeln();
   Result := fData[index];
 
 
end;
 
end;
 
   
 
   
function DynArray<T>.ToString: string;
+
{Выводит содержимое массива на консоль в обратном порядке}
 +
procedure DynArray<DataType>.PrintlnReverse();
 
begin
 
begin
  Result := '';
+
   for var i := size - 1 downto 0 do
   for var i := 0 to fSize - 2 do
+
      write(data[i], ' ');  
  begin
+
   writeln();
    var o: Object := fData[i];
 
    Result += o.ToString + ' ';
 
   end;
 
  var o := fData[fSize-1];
 
  Result += o.ToString;
 
    //Result += fData[i].ToString + ' ';
 
  //Result += fData[fSize-1].ToString;
 
 
end;
 
end;
 
   
 
   
procedure DynArray<T>.Print;
 
begin
 
  write(ToString);
 
end;
 
 
   
 
   
procedure DynArray<T>.Println;
+
// =========================================== SimpleSet =========================================
begin
 
  writeln(ToString);
 
end;
 
 
// -------------------------------- SimpleSet ----------------------------------
 
constructor SimpleSet<T>.Create;
 
begin
 
  fData := new DynArray<T>;
 
end;
 
  
procedure SimpleSet<T>.Add(x: T);
+
// ---------------------------- Стандартные методы ---------------------------
 +
{Добавляет элемент x во множество, если его там еще нет}   
 +
procedure SimpleSet<DataType>.Add(x: DataType);
 
begin
 
begin
   if fData.Find(x) = -1 then  
+
   if data.Find(x) = -1 then  
     fData.Add(x);
+
     data.Add(x);
 
end;
 
end;
 
   
 
   
procedure SimpleSet<T>.Remove(x: T);
+
{Удаляет элемент x из множества, если он там есть}
 +
procedure SimpleSet<DataType>.Remove(x: DataType);
 
begin
 
begin
   var xPos := fData.Find(x);
+
   var xPos := data.Find(x);
 
   if xPos <> -1 then
 
   if xPos <> -1 then
     fData.Remove(xPos);
+
     data.Remove(xPos);
 
end;
 
end;
 
   
 
   
function SimpleSet<T>.Contains(x: T): boolean;
+
{Возвращает истину, если множество содержит элемент x}   
 +
function SimpleSet<DataType>.Contains(x: DataType): boolean;
 
begin
 
begin
   Result := (fData.Find(x) <> -1);
+
   result := (data.Find(x) <> -1);
 
end;
 
end;
 
   
 
   
function SimpleSet<T>.ToString: string;
+
// ---------------------------------- Вывод ----------------------------------
 +
{Выводит содержимое множества на консоль}
 +
procedure SimpleSet<DataType>.Println();
 
begin
 
begin
   Result := fData.ToString;
+
   data.Println;
end;
 
 
 
procedure SimpleSet<T>.Print;
 
begin
 
  write(ToString);
 
end;
 
 
 
procedure SimpleSet<T>.Println;
 
begin
 
  writeln(ToString);
 
 
end;
 
end;
 
   
 
   
// -------------------------------- AssocArray ---------------------------------
+
constructor AssocArray<KeyType,ValueType>.Create;
+
// =========================================== AssocArray ========================================
begin
 
  fKeys := new DynArray<KeyType>;
 
  fValues := new DynArray<ValueType>;
 
end;
 
  
procedure AssocArray<KeyType,ValueType>.SetElem(key: KeyType; value: ValueType);
+
// ----------------------------- Сеттеры/Геттеры -----------------------------
 +
{Устанавливает значение элемента с ключом key равным value}
 +
procedure AssocArray<KeyType, ValueType>.SetElem(key: KeyType; value: ValueType);
 
begin
 
begin
   var ind := fKeys.Find(key);
+
   var ind := Keys.Find(key);
 
   if ind <> -1 then
 
   if ind <> -1 then
     fValues[ind] := value
+
     Values[ind] := value
 
   else
 
   else
 
   begin
 
   begin
     fKeys.Add(key);
+
     Keys.Add(key);
     fValues.Add(value);
+
     Values.Add(value);
 
   end;
 
   end;
 
end;
 
end;
 
   
 
   
function AssocArray<KeyType,ValueType>.GetElem(key: KeyType): ValueType;
+
{Возвращает значение элемента с ключом key}
 +
function AssocArray<KeyType, ValueType>.GetElem(key: KeyType): ValueType;
 
begin
 
begin
   var ind := fKeys.Find(key);
+
   var ind := Keys.Find(key);
 
   if ind <> -1 then
 
   if ind <> -1 then
     Result := fValues[ind]
+
     result := Values[ind]
 
   else
 
   else
 
   begin
 
   begin
     fKeys.Add(key);
+
     Keys.Add(key);
     fValues.Add(default(ValueType));
+
     Values.Add(default(ValueType));
     Result := default(ValueType);
+
     result := default(ValueType);
 
   end;
 
   end;
 
end;
 
end;
  
function AssocArray<KeyType, ValueType>.ToString: string;
+
// ---------------------------------- Вывод ----------------------------------
const NewLine = #13#10;
+
{Выводит содержимое ассоциативного массива на консоль}
 +
procedure AssocArray<KeyType, ValueType>.Println();
 
begin
 
begin
  Result := '';
+
   for var i := 0 to keys.Count - 1 do
   for var i := 0 to fKeys.Count - 2 do
+
     writeln(keys[i], ': ', values[i]);
  begin
 
     var oKey: Object := fKeys[i];
 
    var oVal: Object := fValues[i];
 
    Result += oKey.ToString + ' ' + oVal.ToString + NewLine;
 
  end;
 
  var oKey: Object := fKeys[fKeys.Count-1];
 
  var oVal: Object := fValues[fKeys.Count-1];
 
  Result += oKey.ToString + ' ' + oVal.ToString;
 
    //Result += fKeys[i].ToString + ' ' + fValues[i].ToString + NewLine;
 
  //Result += fKeys[fKeys.Count-1].ToString + ' ' + fValues[fKeys.Count-1].ToString
 
 
end;
 
end;
  
procedure AssocArray<KeyType, ValueType>.Print;
+
 
 +
// ========================================= LinkedListNode =======================================
 +
{Создает новый узел}
 +
constructor LinkedListNode<DataType>.Create(Data: DataType; Prev, Next: LinkedListNode<DataType>);
 
begin
 
begin
   write(ToString);
+
   fData := Data;
 +
  fPrev := Prev;
 +
  fNext := Next;
 
end;
 
end;
  
procedure AssocArray<KeyType, ValueType>.Println;
 
begin
 
  writeln(ToString);
 
end;
 
  
// -------------------------------- LinkedList ---------------------------------
+
// =========================================== LinkedList =========================================
constructor LinkedList<T>.Create;
 
begin
 
  fFirst := nil;
 
  fLast := nil;
 
end;
 
  
procedure LinkedList<T>.AddFirst(x: T);
+
// ---------------------------- Стандартные методы ---------------------------
 +
{Добавляет элемент x в начало списка}
 +
procedure LinkedList<DataType>.AddFirst(x: DataType);
 
begin
 
begin
   var val := new LinkedListNode<T>(x, nil, fFirst);
+
   var val := new LinkedListNode<DataType>(x, nil, fFirst);
 
   if fFirst <> nil then
 
   if fFirst <> nil then
 
     fFirst.fPrev := val;
 
     fFirst.fPrev := val;
Строка 704: Строка 758:
 
end;
 
end;
  
procedure LinkedList<T>.AddLast(x: T);
+
{Добавляет элемент x в конец списка}
 +
procedure LinkedList<DataType>.AddLast(x: DataType);
 
begin
 
begin
   var val := new LinkedListNode<T>(x, fLast, nil);
+
   var val := new LinkedListNode<DataType>(x, fLast, nil);
 
   if fLast <> nil then
 
   if fLast <> nil then
 
     fLast.fNext := val;
 
     fLast.fNext := val;
Строка 715: Строка 770:
 
end;
 
end;
  
procedure LinkedList<T>.RemoveFirst();
+
{Удаляет первый элемент списка}
 +
procedure LinkedList<DataType>.RemoveFirst();
 
begin
 
begin
 
   if fFirst = nil then
 
   if fFirst = nil then
     raise new Exception(RemoveFromNilListExceptionMessage);
+
     raise new Exception(
 +
    'Попытка удаления из пустого списка!');
 
    
 
    
 
   fFirst := fFirst.fNext;
 
   fFirst := fFirst.fNext;
Строка 727: Строка 784:
 
end;
 
end;
  
procedure LinkedList<T>.RemoveLast();
+
{Удаляет последний элемент списка}
 +
procedure LinkedList<DataType>.RemoveLast();
 
begin
 
begin
 
   if fLast = nil then
 
   if fLast = nil then
     raise new Exception(RemoveFromNilListExceptionMessage);
+
     raise new Exception(
 +
    'Попытка удаления из пустого списка!');
 
      
 
      
 
   fLast := fLast.fPrev;
 
   fLast := fLast.fPrev;
Строка 739: Строка 798:
 
end;
 
end;
  
procedure LinkedList<T>.AddBefore(node: LinkedListNode<T>; x: T);  
+
{Добавляет элемент x перед node}
 +
procedure LinkedList<DataType>.AddBefore(node: LinkedListNode<DataType>; x: DataType);  
 
begin
 
begin
 
   if node = nil then
 
   if node = nil then
     raise new Exception(AddNilNodeExceptionMessage);
+
     raise new Exception(
 +
    'Аргумент node метода является нулевой ссылкой!');
 
      
 
      
 
   if node = fFirst then
 
   if node = fFirst then
Строка 748: Строка 809:
 
   else
 
   else
 
   begin
 
   begin
     var val := new LinkedListNode<T>(x, node.fPrev, node);
+
     var val := new LinkedListNode<DataType>(x, node.fPrev, node);
 
     node.fPrev.fNext := val;
 
     node.fPrev.fNext := val;
 
     node.fPrev := val;
 
     node.fPrev := val;
Строка 754: Строка 815:
 
end;
 
end;
  
procedure LinkedList<T>.AddAfter(node: LinkedListNode<T>; x: T);
+
{Добавляет элемент x после node}
 +
procedure LinkedList<DataType>.AddAfter(node: LinkedListNode<DataType>; x: DataType);
 
begin
 
begin
 
   if node = nil then
 
   if node = nil then
     raise new Exception(AddNilNodeExceptionMessage);
+
     raise new Exception(
 +
    'Аргумент node метода является нулевой ссылкой!');
 
      
 
      
 
   if node = fLast then
 
   if node = fLast then
Строка 763: Строка 826:
 
   else
 
   else
 
   begin
 
   begin
     var val := new LinkedListNode<T>(x, node, node.fNext);
+
     var val := new LinkedListNode<DataType>(x, node, node.fNext);
 
     node.fNext.fPrev := val;
 
     node.fNext.fPrev := val;
 
     node.fNext := val;
 
     node.fNext := val;
Строка 769: Строка 832:
 
end;
 
end;
  
procedure LinkedList<T>.Remove(node: LinkedListNode<T>);
+
{Удаляет элемент node}
 +
procedure LinkedList<DataType>.Remove(node: LinkedListNode<DataType>);
 
begin
 
begin
 
   if node = nil then
 
   if node = nil then
     raise new Exception(RemoveNilNodeExceptionMessage);
+
     raise new Exception(
 +
    'Аргумент node метода является нулевой ссылкой!');
 
    
 
    
 
   if node = fFirst then
 
   if node = fFirst then
Строка 785: Строка 850:
 
end;
 
end;
  
function LinkedList<T>.ToString: string;
+
// ---------------------------------- Вывод ----------------------------------
 +
{Выводит содержимое списка на консоль}
 +
procedure LinkedList<DataType>.Println();
 
begin
 
begin
  Result := '';
 
 
   var cur := fFirst;
 
   var cur := fFirst;
 
   while cur <> nil do
 
   while cur <> nil do
 
   begin
 
   begin
     var o: Object := cur.Value;
+
     write(cur.Value, ' ');
    Result += o.ToString + ' ';
 
    //Result := cur.Value.ToString + ' ';
 
 
     cur := cur.Next;
 
     cur := cur.Next;
 
   end;
 
   end;
 +
  writeln();
 
end;
 
end;
  
procedure LinkedList<T>.Print;
+
{Выводит содержимое списка на консоль в обратном порядке}
 +
procedure LinkedList<DataType>.ReversePrintln();
 
begin
 
begin
   write(ToString);
+
   var cur := fLast;
 +
  while cur <> nil do
 +
  begin
 +
    write(cur.Value, ' ');
 +
    cur :=cur.Prev;
 +
  end;
 +
  writeln();
 
end;
 
end;
 
+
procedure LinkedList<T>.Println;
 
begin
 
  writeln(ToString);
 
end;
 
 
 
 
end.
 
end.
 
</source>
 
</source>

Версия 18:50, 7 мая 2009

Nodes (вспомогательный модуль)

/// Модуль содержит шаблоны классов
///   SingleNode — узла с одним полем связи
///   DoubleNode — узла с двумя полями связи
unit Nodes;

interface

type

//-------------------------------------------SINGLE_NODE-------------------------------------------
  /// Узел с одним полем связи
  SingleNode<DataType> = class
    /// Значение узла
    data: DataType;
    /// Ссылка на следующий элемент
    next: SingleNode<DataType>;
    
    /// <summary>
    /// Конструктор
    /// </summary>
    /// <param name="pData">Значение узла</param>
    /// <param name="pNext">Ссылка на следующий элемент</param>
    constructor Create(pData: DataType; pNext: SingleNode<DataType>);
  end;

// -------------------------------------------DOUBLE_NODE------------------------------------------  
  /// Узел с двумя полями связи
  DoubleNode<DataType> = class
    /// Значение узла
    data: DataType;
    /// Ссылка на следующий элемент
    next: DoubleNode<DataType>;
    /// Ссылка на предыдущий элемент
    prev: DoubleNode<DataType>;
    
    /// <summary>
    /// Конструктор
    /// </summary>
    /// <param name="pData">Значение узла</param>
    /// <param name="pNext">Ссылка на следующий элемент</param>
    /// <param name="pPrev">Ссылка на предыдущий элемент</param>
    constructor Create(pData: DataType; pPrev, pNext: DoubleNode<DataType>);
  end;

implementation

//-------------------------------------------SINGLE_NODE-------------------------------------------
{Конструктор
    pData — значение узла
    pNext — cсылка на следующий элемент}
constructor SingleNode<DataType>.Create(pData: DataType; pNext: SingleNode<DataType>);
begin
  data := pData;
  next := pNext;
end;

// -------------------------------------------DOUBLE_NODE------------------------------------------  
{Конструктор
    pData — значение узла
    pNext — cсылка на следующий элемент
    pPrev — ссылка на предыдущий элемент}
constructor DoubleNode<DataType>.Create(pData: DataType; pPrev, pNext: DoubleNode<DataType>);
begin
  data := pData;
  next := pNext;
  prev := pPrev;
end;

end.

Collections

/// Модуль содержит шаблоны классов
///   Stack — стек
///   Queue — очередь
///   DynArray — динамический массив с автоконтролем памяти
///   SimpleSet — простое множество (с минимальным набором операций)
///   AssocArray — ассоциативный массив
///   LinkedListNode — узел с двумя полями связи
///   LinkedList — двусвязный линейный список
unit Collections;
 
interface
 
uses Nodes;   // для использования типа SingleNode<DataType> — 
              // узла с одним полем связи
 
 
// ============================================= Stack ============================================
type
  /// Шаблон класса Stack [Стек]
  Stack<DataType> = class
  private 
    // ----------------------------------- Поля ----------------------------------
    /// Вершина стека
    fTop: SingleNode<DataType> := nil; 
 
  public 
    // ---------------------------- Стандартные методы ---------------------------
    /// Создает пустой стек
    constructor Create;
 
    /// <summary>
    /// Кладет элемент x на вершину стека
    /// </summary>
    /// <param name="x">Новый элемент</param>
    procedure Push(x: DataType);
    /// Возвращает значение элемента на вершине, снимая его со стека
    function Pop: DataType;
    /// Возвращает значение элемента на вершине стека, не снимая его
    function Top: DataType;
 
    /// Возвращает истину, если стек пуст
    function IsEmpty: boolean; 
    
    // ---------------------------------- Вывод ----------------------------------
    /// Выводит содержимое стека на консоль
    procedure Println();
  end;
 
 
// ============================================= Queue ============================================
type  
  /// Шаблон класса Queue [Очередь]
  Queue<DataType> = class
  private
    // ----------------------------------- Поля ----------------------------------
    /// Голова очереди
    head: SingleNode<DataType>;
    /// Хвост очереди
    tail: SingleNode<DataType>;
 
  public
    // ---------------------------- Стандартные методы ---------------------------
    /// Создает пустую очередь
    constructor Create;
 
    /// <summary>
    /// Добавляет элемент x в хвост очереди
    /// </summary>
    /// <param name="x">Добавляемый элемент</param>
    procedure Enqueue(x: DataType);
    /// Возвращает значение элемента в голове, удаляя его из очереди
    function Dequeue: DataType;
    /// Возвращает значение элемента в голове очереди, не удаляя его
    function Top: DataType;
 
    /// Возвращает истину, если очередь пуста
    function IsEmpty: boolean;
 
    // ---------------------------------- Вывод ----------------------------------
    /// Выводит содержимое очереди на консоль
    procedure Println();
  end;
 
 
// =========================================== DynArray ==========================================
const
  /// Минимальная емкость, устанавливаемая при создании массива
  MIN_CAP = 4;
  /// Коэффициент увеличения емкости массива при её нехватке
  INC_CAP_FACTOR = 2;
 
type
  /// Шаблон класса DynArray [Динамический массив с автоконтролем памяти]
  DynArray<DataType> = class
  private
    // ----------------------------------- Поля ----------------------------------
    /// Встроенный динамический массив, содержащий данные
    data: array of DataType;
    /// Размер массива
    size: integer;
    /// Емкость массива
    cap: integer;
    
    // ----------------------------- Сеттеры/Геттеры -----------------------------
    /// Устанавливает элемент с индексом ind равным x
    procedure SetElem(ind: integer; x: DataType);
    /// Возвращает элемент массива с индексом ind
    function GetElem(ind: integer): DataType;
 
  public
    // ---------------------------- Стандартные методы ---------------------------
    /// Создает массив размера pSize
    constructor Create(pSize: integer := 0);
 
    /// <summary>
    /// Выделяет новую память. Емкость увеличивается до newCap.
    /// (Если newCap меньше текущей емкости, ничего не происходит) 
    /// </summary>
    /// <param name="newCap">Новая емкость массива</param>
    procedure Reserve(newCap: integer);
    /// <summary>
    /// Устанавливает новый размер массива равным newSize
    /// </summary>
    /// <param name="newSize">Новый размер массива</param>
    procedure Resize(newSize: integer);
 
    /// <summary>
    /// Добавляет элемент x в конец массива 
    /// </summary>
    /// <param name="x">Добавляемый элемент</param>
    procedure Add(x: DataType);
    /// <summary>
    /// Вставляет элемент x в позицию pos
    /// </summary>
    /// <param name="pos">Позиция, в которую вставляется элемент</param>
    /// <param name="x">Вставляемый элемент</param>
    procedure Insert(pos: integer; x: DataType);
    /// <summary>
    /// Удаляет элемент массива из позиции pos
    /// </summary>
    /// <param name="pos">Позиция, из которой удаляется элемент</param>
    procedure Remove(pos: integer);
 
    /// <summary>
    /// Возвращает индекс первого элемента массива равного x
    /// или -1, если такого элемента нет
    /// </summary>
    /// <param name="x">Искомый элемент</param>
    function Find(x: DataType): integer;
    
    // --------------------------------- Свойства --------------------------------
    /// Количество элементов (размер) массива
    property Count: integer read size write Resize;
    /// Емкость массива (отведенная память)
    property Capacity: integer read cap write Reserve;
 
    /// Позволяет обращаться к элементам массива по индексу 
    /// (например, apples[5])
    property Elem[index: integer]: DataType read GetElem write SetElem; default;
 
    // ---------------------------------- Вывод ----------------------------------
    /// Выводит содержимое массива на консоль
    procedure Println();
    /// Выводит содержимое массива на консоль в обратном порядке
    procedure PrintlnReverse();
  end;
 
 
// =========================================== SimpleSet =========================================
type 
  /// Шаблон класса SimpleSet [Простое множество]
  SimpleSet<DataType> = class 
  private
    // ----------------------------------- Поля ----------------------------------
    /// Элементы множества
    data := new DynArray<DataType>;
 
  public
    // ---------------------------- Стандартные методы ---------------------------
    /// <summary>
    /// Добавляет элемент x во множество, если его там еще нет
    /// </summary>
    /// <param name="x">Добавляемый элемент</param>    
    procedure Add(x: DataType);
    /// <summary>
    /// Удаляет элемент x из множества, если он там есть
    /// </summary>
    /// <param name="x">Удаляемый элемент</param>
    procedure Remove(x: DataType);
 
    /// <summary>
    /// Возвращает истину, если множество содержит элемент x
    /// </summary>
    /// <param name="x">Искомый элемент</param>          
    function Contains(x: DataType): boolean;   
 
    // ---------------------------------- Вывод ----------------------------------
    ///Выводит содержимое множества на консоль
    procedure Println();
end;

 
// =========================================== AssocArray ========================================
type
  /// Шаблон класса AssocArray [Ассоциативный массив]
  AssocArray<KeyType, ValueType> = class
  private
    // ----------------------------------- Поля ----------------------------------
    /// Ключи
    keys: DynArray<KeyType> := new DynArray<KeyType>;
    /// Значения, соответствующие ключам
    values: DynArray<ValueType> := new DynArray<ValueType>;
    
    // ----------------------------- Сеттеры/Геттеры -----------------------------
    /// Устанавливает значение элемента с ключом key равным value
    procedure SetElem(key: KeyType; value: ValueType);
    /// Возвращает значение элемента с ключом key
    function GetElem(key: KeyType): ValueType;
 
  public
    // --------------------------------- Свойства --------------------------------
    /// Позволяет обращаться к элементам массива по ключу
    /// (Например, zoo['крокодил'])
    property Elem[key: KeyType]: ValueType read GetElem write SetElem; default;
    
    // ---------------------------------- Вывод ----------------------------------
    ///Выводит содержимое ассоциативного массива на консоль
    procedure Println();
  end;
  
  
// ========================================= LinkedListNode =======================================
type
  /// Узел с двумя полями связи
  LinkedListNode<DataType> = class
  private
    // ----------------------------------- Поля ----------------------------------
    /// Значение узла
    fData: DataType;
    /// Ссылка на предыдущий элемент
    fPrev: LinkedListNode<DataType>;
    /// Ссылка на следующий элемент
    fNext: LinkedListNode<DataType>;
    
  public
    // --------------------------------- Свойства --------------------------------
    /// Значение узла
    property Value: DataType read fData write fData;
    /// Ссылка на предыдущий элемент — только на чтение
    property Prev: LinkedListNode<DataType> read fPrev;
    /// Ссылка на следующий элемент — только на чтение
    property Next: LinkedListNode<DataType> read fNext;
    
    // ---------------------------- Стандартные методы ---------------------------
    /// <summary>
    /// Создает новый узел
    /// </summary>
    /// <param name="DataType">Значение узла</param>
    /// <param name="Prev">Ссылка на предыдущий элемент</param>
    /// <param name="Next">Ссылка на следующий элемент</param>
    constructor Create(Data: DataType; Prev, Next: LinkedListNode<DataType>);
  end;
  
  
// =========================================== LinkedList =========================================
type
  /// Двусвязный линейный список
  LinkedList<DataType> = class
  private
    // ----------------------------------- Поля ----------------------------------
    /// Первый элемент (голова)
    fFirst: LinkedListNode<DataType> := nil;
    /// Последний элемент (хвост)
    fLast: LinkedListNode<DataType> := nil;
    
  public
    // --------------------------------- Свойства --------------------------------
    /// Первый элемент (голова) — только на чтение
    property First: LinkedListNode<DataType> read fFirst;
    /// Последний элемент (хвост) — только на чтение
    property Last: LinkedListNode<DataType> read fLast;
    
    // ---------------------------- Стандартные методы ---------------------------
    /// <summary>
    /// Добавляет элемент x в начало списка
    /// </summary>
    /// <param name="x">Добавляемый элемент</param>
    procedure AddFirst(x: DataType);
    /// <summary>
    /// Добавляет элемент x в конец списка
    /// </summary>
    /// <param name="x">Добавляемый элемент</param>
    procedure AddLast(x: DataType);
    
    /// Удаляет первый элемент списка
    procedure RemoveFirst();
    /// Удаляет последний элемент списка
    procedure RemoveLast();
    
    /// <summary>
    /// Добавляет элемент x перед node
    /// </summary>
    /// <param name="node">Ссылка на элемент, перед которым нужно добавить новый</param>
    /// <param name="x">Добавляемый элемент</param>
    procedure AddBefore(node: LinkedListNode<DataType>; x: DataType); 
    /// <summary>
    /// Добавляет элемент x после node
    /// </summary>
    /// <param name="node">Ссылка на элемент, после которого нужно добавить новый</param>
    /// <param name="x">Добавляемый элемент</param>
    procedure AddAfter(node: LinkedListNode<DataType>; x: DataType);
    
    /// <summary>
    /// Удаляет элемент node
    /// </summary>
    /// <param name="node">Ссылка на элемент, который нужно удалить</param>
    procedure Remove(node: LinkedListNode<DataType>);
    
    // ---------------------------------- Вывод ----------------------------------
    /// Выводит содержимое списка на консоль
    procedure Println();
    /// Выводит содержимое списка на консоль в обратном порядке
    procedure ReversePrintln();
  end;
 
 
implementation
 
 
// ============================================= Stack ============================================
 
// ---------------------------- Стандартные методы ---------------------------
{Создает пустой стек}
constructor Stack<DataType>.Create;
begin
  fTop := nil;
end;
 
{Кладет элемент x на вершину стека} 
procedure Stack<DataType>.Push(x: DataType);
begin
  fTop := new SingleNode<DataType>(x, fTop);
end;
 
{Возвращает значение элемента на вершине, снимая его со стека}
function Stack<DataType>.Pop: DataType;
begin
  if IsEmpty then 
     raise new Exception('Попытка снятия элемента с пустого стека!');
 
  result := fTop.data;
  fTop := fTop.next;  // элемент снимается с вершины стека
                      // (т.е. вершиной становится следующий элемент)
end;
 
{Возвращает значение элемента на вершине стека, не снимая его}
function Stack<DataType>.Top: DataType;
begin
  if IsEmpty then 
     raise new Exception('Попытка получения элемента с пустого стека!');
 
  result := fTop.data;
end;
 
{Возвращает истину, если стек пуст}
function Stack<DataType>.IsEmpty: boolean;
begin
  result := (fTop = nil);
end;
 
// ---------------------------------- Вывод ----------------------------------
{Выводит содержимое стека на консоль}
procedure Stack<DataType>.Println();
begin
  if not IsEmpty then
  begin
    var curElem := fTop;
 
    while curElem <> nil do
    begin
      write(curElem.data, ' ');
      curElem := curElem.next;
    end;
  end;
  writeln();
end;
 
 
// ============================================= Queue ============================================
 
// ---------------------------- Стандартные методы ---------------------------
{Создает пустую очередь}
constructor Queue<DataType>.Create;
begin
  head := nil;
  tail := nil;
end;
 
{Добавляет элемент x в хвост очереди} 
procedure Queue<DataType>.Enqueue(x: DataType);
begin
  if IsEmpty then
  begin
    head := new SingleNode<DataType>(x, nil);
    tail := head;
  end
  else
  begin
    tail.next := new SingleNode<DataType>(x, nil);
    tail := tail.next;  // элемент удаляется из хвоста очереди
                        // (т.е. хвостом становится следующий элемент)
  end;
end;
 
{Возвращает значение элемента в голове, удаляя его из очереди}
function Queue<DataType>.Dequeue: DataType;
begin
  if IsEmpty then 
     raise new Exception('Попытка удаления элемента из пустой очереди!');
 
  result := head.data;
  head := head.next;  // элемент удаляется из головы очереди
                      // (т.е. головой становится следующий элемент)
  if head = nil then
    tail := nil;
end;
 
{Возвращает значение элемента в голове очереди, не удаляя его}
function Queue<DataType>.Top: DataType;
begin
  if IsEmpty then 
     raise new Exception('Попытка получения элемента из пустой очереди!');
 
  result := head.data;
end;
 
{Возвращает истину, если очередь пуста}
function Queue<DataType>.IsEmpty: boolean;
begin
  result := (head = nil);
  if result then
    Assert(tail = nil);
end;
 
// ---------------------------------- Вывод ----------------------------------
{Выводит содержимое очереди на консоль}
procedure Queue<DataType>.Println();
begin
  if not IsEmpty then
  begin
    var curElem := head;
 
    while curElem <> nil do
    begin
      write(curElem.data, ' ');
      curElem := curElem.next;
    end;
  end;
  writeln();
end;
 
 
// =========================================== DynArray ========================================== 

// ----------------------------- Сеттеры/Геттеры -----------------------------
{Устанавливает элемент с индексом ind равным x}
procedure DynArray<DataType>.SetElem(ind: integer; x: DataType);
begin
  if (ind < 0) or (ind > size-1) then 
     raise new Exception(
     'Попытка присвоить значение элементу за границей массива с индексом ' + IntToStr(ind) + '!');
 
  data[ind] := x;
end;
 
{Возвращает элемент массива с индексом ind}
function DynArray<DataType>.GetElem(ind: integer): DataType;
begin
  if (ind < 0) or (ind > size-1) then 
     raise new Exception(
     'Попытка получить значение элемента за границей массива с индексом ' + IntToStr(ind) + '!');
 
  result := data[ind];
end;

// ---------------------------- Стандартные методы ---------------------------
{Создает массив размера pSize}
constructor DynArray<DataType>.Create(pSize: integer);
begin
  if pSize < 0 then
    raise new Exception('Попытка присвоить размеру массива отрицательное значение ' + IntToStr(pSize) + '!');
 
  size := pSize;
  cap := INC_CAP_FACTOR*pSize + MIN_CAP; // Устанавливаем емкость "с запасом"
  SetLength(data, cap);
end;
 
{Выделяет новую память. Емкость увеличивается до newCap.
 (Если newCap меньше текущей емкости, ничего не происходит) }
procedure DynArray<DataType>.Reserve(newCap: integer);
begin
  if newCap > cap then 
  begin
    SetLength(data, newCap);
    cap := newCap;
  end;
end;
 
{Устанавливает новый размер массива равным newSize}
procedure DynArray<DataType>.Resize(newSize: integer);
begin
  if newSize < 0 then
    raise new Exception('Попытка присвоить размеру массива отрицательное значение ' + IntToStr(newSize) + '!');
 
  if newSize > cap then
  begin
    Reserve(INC_CAP_FACTOR * newSize);
    for var i := size to newSize - 1 do // явным образом заполняем новые элементы
      data[i] := default(DataType);
  end;
  size := newSize;
end;
 
{Добавляет элемент x в конец массива }
procedure DynArray<DataType>.Add(x: DataType);
begin
  Resize(size + 1);
  data[size-1] := x;
end;
 
{Вставляет x элемент в позицию pos}
procedure DynArray<DataType>.Insert(pos: integer; x: DataType);
begin
  if (pos < 0) or (pos > size-1) then 
     raise new Exception(
     'Попытка вставки за границей массива в позицию ' + IntToStr(pos) + '!');
 
  Resize(size + 1);
  for var i := size - 2 downto pos do
    data[i+1] := data[i];
  data[pos] := x;
end;
 
{Удаляет элемент массива из позиции pos}
procedure DynArray<DataType>.Remove(pos: integer);
begin
  if (pos < 0) or (pos > size-1) then 
     raise new Exception(
     'Попытка удаления за границей массива из позиции ' + IntToStr(pos) + '!');
 
  for var i := pos to size - 2 do // сдвиг элементов влево на 1, начиная с позиции pos
    data[i] := data[i+1];
  Resize(size - 1);
end;
 
{Возвращает индекс первого элемента массива равного x
 или -1, если такого элемента нет}
function DynArray<DataType>.Find(x: DataType): integer;
begin
  result := -1;
  for var i := 0 to size - 1 do
    if data[i] = x then
    begin
      result := i;
      exit;
    end;
end;
 
// ---------------------------------- Вывод ----------------------------------
{Выводит содержимое массива на консоль}
procedure DynArray<DataType>.Println();
begin
  for var i := 0 to size - 1 do
      write(data[i], ' '); 
  writeln();
end;
 
{Выводит содержимое массива на консоль в обратном порядке}
procedure DynArray<DataType>.PrintlnReverse();
begin
  for var i := size - 1 downto 0 do
      write(data[i], ' '); 
  writeln();
end;
 
 
// =========================================== SimpleSet =========================================

// ---------------------------- Стандартные методы ---------------------------
{Добавляет элемент x во множество, если его там еще нет}     
procedure SimpleSet<DataType>.Add(x: DataType);
begin
  if data.Find(x) = -1 then 
    data.Add(x);
end;
 
{Удаляет элемент x из множества, если он там есть}
procedure SimpleSet<DataType>.Remove(x: DataType);
begin
  var xPos := data.Find(x);
  if xPos <> -1 then
    data.Remove(xPos);
end;
 
{Возвращает истину, если множество содержит элемент x}    
function SimpleSet<DataType>.Contains(x: DataType): boolean;
begin
  result := (data.Find(x) <> -1);
end;
 
// ---------------------------------- Вывод ----------------------------------
 {Выводит содержимое множества на консоль}
procedure SimpleSet<DataType>.Println();
begin
  data.Println;
end;
 
 
// =========================================== AssocArray ========================================

// ----------------------------- Сеттеры/Геттеры -----------------------------
{Устанавливает значение элемента с ключом key равным value}
procedure AssocArray<KeyType, ValueType>.SetElem(key: KeyType; value: ValueType);
begin
  var ind := Keys.Find(key);
  if ind <> -1 then
    Values[ind] := value
  else
  begin
    Keys.Add(key);
    Values.Add(value);
  end;
end;
 
{Возвращает значение элемента с ключом key}
function AssocArray<KeyType, ValueType>.GetElem(key: KeyType): ValueType;
begin
  var ind := Keys.Find(key);
  if ind <> -1 then
    result := Values[ind]
  else
  begin
    Keys.Add(key);
    Values.Add(default(ValueType));
    result := default(ValueType);
  end;
end;

// ---------------------------------- Вывод ----------------------------------
{Выводит содержимое ассоциативного массива на консоль}
procedure AssocArray<KeyType, ValueType>.Println();
begin
  for var i := 0 to keys.Count - 1 do
    writeln(keys[i], ': ', values[i]);
end;


// ========================================= LinkedListNode =======================================
{Создает новый узел}
constructor LinkedListNode<DataType>.Create(Data: DataType; Prev, Next: LinkedListNode<DataType>);
begin
  fData := Data;
  fPrev := Prev;
  fNext := Next;
end;


// =========================================== LinkedList =========================================

// ---------------------------- Стандартные методы ---------------------------
{Добавляет элемент x в начало списка}
procedure LinkedList<DataType>.AddFirst(x: DataType);
begin
  var val := new LinkedListNode<DataType>(x, nil, fFirst);
  if fFirst <> nil then
    fFirst.fPrev := val;
  
  fFirst := val;
  if fLast = nil then
    fLast := fFirst;
end;

{Добавляет элемент x в конец списка}
procedure LinkedList<DataType>.AddLast(x: DataType);
begin
  var val := new LinkedListNode<DataType>(x, fLast, nil);
  if fLast <> nil then
    fLast.fNext := val;
    
  fLast := val;
  if fFirst = nil then
    fFirst := fLast;
end;

{Удаляет первый элемент списка}
procedure LinkedList<DataType>.RemoveFirst();
begin
  if fFirst = nil then
    raise new Exception(
    'Попытка удаления из пустого списка!');
  
  fFirst := fFirst.fNext;
  if fFirst = nil then
    fLast := nil
  else
    fFirst.fPrev := nil;
end;

{Удаляет последний элемент списка}
procedure LinkedList<DataType>.RemoveLast();
begin
  if fLast = nil then
    raise new Exception(
    'Попытка удаления из пустого списка!');
    
  fLast := fLast.fPrev;
  if fLast = nil then
    fFirst := nil
  else
    fLast.fNext := nil;
end;

{Добавляет элемент x перед node}
procedure LinkedList<DataType>.AddBefore(node: LinkedListNode<DataType>; x: DataType); 
begin
  if node = nil then
    raise new Exception(
    'Аргумент node метода является нулевой ссылкой!');
    
  if node = fFirst then
    AddFirst(x)
  else
  begin
    var val := new LinkedListNode<DataType>(x, node.fPrev, node);
    node.fPrev.fNext := val;
    node.fPrev := val;
  end;
end;

{Добавляет элемент x после node}
procedure LinkedList<DataType>.AddAfter(node: LinkedListNode<DataType>; x: DataType);
begin
  if node = nil then
    raise new Exception(
    'Аргумент node метода является нулевой ссылкой!');
    
  if node = fLast then
    AddLast(x)
  else
  begin
    var val := new LinkedListNode<DataType>(x, node, node.fNext);
    node.fNext.fPrev := val;
    node.fNext := val;
  end;
end;

{Удаляет элемент node}
procedure LinkedList<DataType>.Remove(node: LinkedListNode<DataType>);
begin
  if node = nil then
    raise new Exception(
    'Аргумент node метода является нулевой ссылкой!');
  
  if node = fFirst then
    RemoveFirst
  else if node = fLast then
    RemoveLast
  else
  begin
    node.fPrev.fNext := node.fNext;
    node.fNext.fPrev := node.fPrev;
  end;
end;

// ---------------------------------- Вывод ----------------------------------
{Выводит содержимое списка на консоль}
procedure LinkedList<DataType>.Println();
begin
  var cur := fFirst;
  while cur <> nil do
  begin
    write(cur.Value, ' ');
    cur := cur.Next;
  end;
  writeln();
end;

{Выводит содержимое списка на консоль в обратном порядке}
procedure LinkedList<DataType>.ReversePrintln();
begin
  var cur := fLast;
  while cur <> nil do
  begin
    write(cur.Value, ' ');
    cur :=cur.Prev;
  end;
  writeln();
end;
 
end.

См. также