Читаем Фундаментальные алгоритмы и структуры данных в Delphi полностью

Для изменения приоритета элемента мы просто изменяем значение приоритета элемента и сообщаем очереди о том, что произошло, передавая ей дескриптор элемента. Затем очередь может восстановить свойство пирамидальное™. Операция исключения из очереди работает так же, как и ранее (дескриптор элемента не нужно передавать, поскольку очередь сама определит наибольший элемент). Однако очередь уничтожит дескриптор возвращенного элемента, поскольку он больше не присутствует в очереди. Если элементы являются записями или объектами, дескриптор данного элемента можно хранить внутри самого элемента наряду с приоритетом и другими полями.

В рамках операционной системы дескриптор, который, как правило, представляет собой своего рода замаскированный указатель, обычно имеет тип длинного целого. В рассматриваемой реализации мы используем всего лишь нетипизированный указатель.

<p>Реализация расширенной очереди по приоритету</p>

С точки зрения пользователя очереди по приоритету новый интерфейс лишь немногим сложнее рассмотренного ранее. Код интерфейса класса расширенной очереди по приоритету TtdPriorityQueueEx приведен в листинге 9.9.

Листинг 9.9. Интерфейс класса TtdPriorityQueueEx

type

TtdPQHandle = pointer;

TtdPriorityQueueEx = class private

FCompare : TtdCompareFunc;

FHandles : pointer;

FList : TList;

FName : TtdNameString;

protected

function pqGetCount : integer;

procedure pqError(aErrorCode : integer;

const aMethodName : TtdNameString);

procedure pqBubbleUp(aHandle : TtdPQHandle);

procedure pqTrickleDown(aHandle : TtdPQHandle);

public

constructor Create(aCompare : TtdCompareFunc);

destructor Destroy; override;

procedure ChangePriority(aHandle : TtdPQHandle);

procedure Clear;

function Dequeue : pointer;

function Enqueue(alt em : pointer): TtdPQHandle;

function Examine : pointer;

function IsEmpty : boolean;

function Remove(aHandle : TtdPQHandle): pointer;

property Count : integer read pqGetCount;

property Name : TtdNameString read FName write FName;

end;

Как видите, единственное реальное различие между этим классом и классом TtdPriorityQueue состоит в наличии методов Remove и ChangePriority и в том, что метод Enqueue возвращает дескриптор.

Так как же реализован этот интерфейс? Внутренне очередь, как обычно, содержит сортирующее дерево, но на этот раз она должна поддерживать определенную дополнительную информацию, чтобы иметь возможность отслеживать позицию каждого элемента в сортирующем дереве. Кроме того, очередь должна идентифицировать каждый элемент дескриптором, чтобы поиск элемента по заданному дескриптору выполнялся быстро и эффективно - теоретически быстрее, чем в дереве двоичного поиска, где время поиска определяется соотношением O(log(n)).

Поэтому мы сделаем следующее: когда пользователь будет ставить элемент в очередь, мы будем добавлять элемент в связный список. Это будет сопряжено с определением и использованием узла и, по меньшей мере, двух указателей: указателя самого этого элемента и указателя следующего элемента, хотя по причинам, которые станут понятны несколько позже, мы будем использовать двухсвязный список и поэтому нам потребуется также и предыдущий указатель. Передаваемый нами обратно дескриптор элемента будет адресом узла. Теперь наступает важный момент. Узел хранит также целочисленное значение - позицию элемента в массиве, посредством которого реализовано сортирующее дерево. Сортирующее дерево не хранит сами элементы, а только их дескрипторы (т.е. узлы связного списка). Каждый раз, когда для выполнения сравнения ему нужно будет обратиться к самому элементу, оно будет разыменовывать дескриптор.

К сожалению, мы не можем использовать описанный в главе 3 класс связного списка, поскольку нам требуется доступ к узлам, а этот класс был разработан с целью сокрытия структуры узлов. Это один из случаев, когда нельзя использовать заранее стандартные классы и требуется выполнить кодирование от начала до конца. В случае применения двухсвязного списка это не так страшно, поскольку эта структура достаточно проста. Мы создадим связный список с явными начальным и конечным узлами. В результате удаление обычного узла превращается в исключительно простую задачу. Удаление узлов будет выполняться с применением обоих методов Dequeue и Remove класса расширенной очереди по приоритету.

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

Листинг 9.10. Постановка в очередь и пузырьковый подъем в расширенной очереди по приоритету

procedure TtdPriorityQueueEx.pqBubbleUp(aHandle : pointer);

var

FromInx : integer;

ParentInx : integer;

ParentHandle : PpqexNode;

Перейти на страницу:

Похожие книги

C++
C++

С++ – это универсальный язык программирования, задуманный так, чтобы сделать программирование более приятным для серьезного программиста. За исключением второстепенных деталей С++ является надмножеством языка программирования C. Помимо возможностей, которые дает C, С++ предоставляет гибкие и эффективные средства определения новых типов. Используя определения новых типов, точно отвечающих концепциям приложения, программист может разделять разрабатываемую программу на легко поддающиеся контролю части. Такой метод построения программ часто называют абстракцией данных. Информация о типах содержится в некоторых объектах типов, определенных пользователем. Такие объекты просты и надежны в использовании в тех ситуациях, когда их тип нельзя установить на стадии компиляции. Программирование с применением таких объектов часто называют объектно-ориентированным. При правильном использовании этот метод дает более короткие, проще понимаемые и легче контролируемые программы. Ключевым понятием С++ является класс. Класс – это тип, определяемый пользователем. Классы обеспечивают сокрытие данных, гарантированную инициализацию данных, неявное преобразование типов для типов, определенных пользователем, динамическое задание типа, контролируемое пользователем управление памятью и механизмы перегрузки операций. С++ предоставляет гораздо лучшие, чем в C, средства выражения модульности программы и проверки типов. В языке есть также усовершенствования, не связанные непосредственно с классами, включающие в себя символические константы, inline-подстановку функций, параметры функции по умолчанию, перегруженные имена функций, операции управления свободной памятью и ссылочный тип. В С++ сохранены возможности языка C по работе с основными объектами аппаратного обеспечения (биты, байты, слова, адреса и т.п.). Это позволяет весьма эффективно реализовывать типы, определяемые пользователем. С++ и его стандартные библиотеки спроектированы так, чтобы обеспечивать переносимость. Имеющаяся на текущий момент реализация языка будет идти в большинстве систем, поддерживающих C. Из С++ программ можно использовать C библиотеки, и с С++ можно использовать большую часть инструментальных средств, поддерживающих программирование на C. Эта книга предназначена главным образом для того, чтобы помочь серьезным программистам изучить язык и применять его в нетривиальных проектах. В ней дано полное описание С++, много примеров и еще больше фрагментов программ.

Бьёрн Страуструп , Бьярн Страустрап , Мюррей Хилл

Программирование, программы, базы данных / Программирование / Книги по IT