Описание кода определения класса см. в разделе Описание класса dlnode.
Чтобы использовать класс, создайте папку с именем @dlnode и сохранить dlnode.m в эту папку. Родительская папка @dlnode должен находиться в тракте MATLAB ®. Также можно сохранитьdlnode.m к папке пути.
dlnode Дизайн классаdlnode является классом для создания двойных связанных списков, в которых каждый узел содержит:
Массив данных
Переход к следующему узлу
Дескриптор к предыдущему узлу
Каждый узел имеет методы, которые позволяют узлу быть:
Вставляется перед указанным узлом в списке связей
Вставляется после определенного узла в связанный список
Удалено из списка
dlnode класс реализует каждый узел как объект-дескриптор с тремя свойствами:
Data - Содержит данные для этого узла
Next - Содержит дескриптор следующего узла в списке (SetAccess = private)
Prev - Содержит дескриптор предыдущего узла в списке (SetAccess = private)
На этой схеме показан список с тремя узлами n1, n2, и n3. Здесь также показано, как узлы ссылаются на следующий и предыдущий узлы.

dlnode класс реализует следующие методы:
dlnode - Построить узел и назначить значение, переданное в качестве входных данных Data собственность
insertAfter - Вставить этот узел после указанного узла
insertBefore - Вставить этот узел перед указанным узлом
removeNode - Удаление этого узла из списка и повторное подключение оставшихся узлов
clearList - Эффективное удаление больших списков
delete - частный метод, вызываемый MATLAB при удалении списка.
Создание узла путем передачи данных узла в dlnode конструктор класса. Например, эти инструкции создают три узла со значениями данных 1, 2, и 3:
n1 = dlnode(1); n2 = dlnode(2); n3 = dlnode(3);
Создайте эти узлы в список с двойными связями, используя методы классов, разработанные для этой цели:
n2.insertAfter(n1) % Insert n2 after n1 n3.insertAfter(n2) % Insert n3 after n2
Теперь три узла связаны:
n1.Next % Points to n2ans =
dlnode with properties:
Data: 2
Next: [1x1 dlnode]
Prev: [1x1 dlnode]n2.Next.Prev % Points back to n2ans =
dlnode with properties:
Data: 2
Next: [1x1 dlnode]
Prev: [1x1 dlnode]n1.Next.Next % Points to n3ans =
dlnode with properties:
Data: 3
Next: []
Prev: [1x1 dlnode]n3.Prev.Prev % Points to n1ans =
dlnode with properties:
Data: 1
Next: [1x1 dlnode]
Prev: []Каждый узел уникален тем, что два узла не могут предшествовать одному узлу или располагаться рядом с ним.
Например, объект узла, node, содержит в себе Next свойство дескриптор объекта следующего узла, node.Next. Аналогично, Prev содержит дескриптор предыдущего узла, node.Prev. Используя список трехузловых связей, определенный в предыдущем разделе, можно продемонстрировать, что следующие операторы верны:
n1.Next == n2 n2.Prev == n1
Теперь предположим, что вы назначили n2 кому x:
x = n2;
Следующие два равенства верны:
x == n1.Next x.Prev == n1
Но каждый экземпляр узла уникален, поэтому в списке есть только один узел, который может удовлетворять условиям равенства n1.Next и имеющие Prev свойство, содержащее дескриптор для n1. Поэтому x должен указывать на тот же узел, что и n2.
Должен существовать способ ссылки нескольких переменных на один и тот же объект. MATLAB handle класс обеспечивает средство для обоих x и n2 для ссылки на один и тот же узел.
Класс дескриптора определяет eq метод (использование methods('handle') для перечисления методов класса дескрипторов), что позволяет использовать == оператор со всеми объектами-дескрипторами.
Дополнительные сведения о классах дескрипторов см. в разделе Сравнение классов дескрипторов и значений.
dlnode Синопсис классаВ этом разделе описывается реализация dlnode класс.
| Пример кода | Обсуждение |
|---|---|
classdef dlnode < handle
| |
properties Data end | Конструкция класса dlnode |
properties (SetAccess = private) Next = dlnode.empty Prev = dlnode.empty end | Атрибуты свойства: Инициализировать эти свойства для Общие сведения о свойствах см. в разделе Синтаксис свойств |
methods
| Общие сведения о методах см. в разделе Методы проектирования классов |
function node = dlnode(Data) if (nargin > 0) node.Data = Data; end end | Для создания отдельного узла (не подключенного) требуются только данные. Общие сведения о конструкторах см. в разделе Рекомендации по конструкторам. |
function insertAfter(newNode, nodeBefore) removeNode(newNode); newNode.Next = nodeBefore.Next; newNode.Prev = nodeBefore; if ~isempty(nodeBefore.Next) nodeBefore.Next.Prev = newNode; end nodeBefore.Next = newNode; end | Вставка узла в список двойных связей после указанного узла или связывание двух указанных узлов, если список еще не существует. Назначает правильные значения для |
function insertBefore(newNode, nodeAfter) removeNode(newNode); newNode.Next = nodeAfter; newNode.Prev = nodeAfter.Prev; if ~isempty(nodeAfter.Prev) nodeAfter.Prev.Next = newNode; end nodeAfter.Prev = newNode; end | Вставка узла в список двойных связей перед указанным узлом или связывание двух указанных узлов, если список еще не существует. Этот метод присваивает правильные значения См. Вставка узлов |
function removeNode(node) if ~isscalar(node) error('Nodes must be scalar') end prevNode = node.Prev; nextNode = node.Next; if ~isempty(prevNode) prevNode.Next = nextNode; end if ~isempty(nextNode) nextNode.Prev = prevNode; end node.Next = = dlnode.empty; node.Prev = = dlnode.empty; end | Удалите узел и исправьте список, чтобы остальные узлы были правильно подключены. Если ссылки на узел отсутствуют, MATLAB удаляет его. |
function clearList(node) prev = node.Prev; next = node.Next; removeNode(node) while ~isempty(next) node = next; next = node.Next; removeNode(node); end while ~isempty(prev) node = prev; prev = node.Prev; removeNode(node) end end | Избегайте рекурсивных вызовов деструктора в результате очистки переменной списка. Закольцовывание списка для разъединения каждого узла. При отсутствии ссылок на узел MATLAB вызывает деструктор класса (см. |
methods (Access = private) function delete(node) clearList(node) end | Метод деструктора класса. MATLAB вызывает |
end end | Конец частных методов и конец определения класса. |
Только dlnode методы класса могут устанавливать Next и Prev свойства, поскольку эти свойства имеют доступ к частному набору (SetAccess = private). Использование доступа к частному аппарату предотвращает выполнение кодом клиента неправильной операции с этими свойствами. dlnode методы класса выполняют все операции, разрешенные на этих узлах.
Data свойство имеет открытый набор и доступ, позволяющий запрашивать и изменять значение Data при необходимости.
Вот как dlnode класс определяет свойства:
properties Data end properties(SetAccess = private) Next = dlnode.empty; Prev = dlnode.empty; end
Чтобы создать объект узла, укажите данные узла в качестве аргумента конструктора:
function node = dlnode(Data) if nargin > 0 node.Data = Data; end end
Существует два метода вставки узлов в список - insertAfter и insertBefore. Эти методы выполняют аналогичные операции, поэтому в этом разделе описываются только insertAfter подробно.
function insertAfter(newNode, nodeBefore) removeNode(newNode); newNode.Next = nodeBefore.Next; newNode.Prev = nodeBefore; if ~isempty(nodeBefore.Next) nodeBefore.Next.Prev = newNode; end nodeBefore.Next = newNode; end
Как insertAfter Работает. Во-первых, insertAfter вызывает removeNode чтобы гарантировать, что новый узел не подключен к другим узлам. Затем, insertAfter назначает newNode
Next и Prev свойства для дескрипторов узлов, которые находятся после и перед newNode расположение в списке.
Например, предположим, что требуется вставить новый узел, nnew, после существующего узла, n1, в списке, содержащем n1—n2—n3.
Сначала создайте nnew:
nnew = dlnode(rand(3));
Далее, звонок insertAfter вставить nnew в список после n1:
nnew.insertAfter(n1)
insertAfter метод выполняет следующие шаги для вставки nnew в списке между n1 и n2:
Набор nnew.Next кому n1.Next (n1.Next является n2):
nnew.Next = n1.Next;
Набор nnew.Prev кому n1
nnew.Prev = n1;
Если n1.Next не пуст, то n1.Next по-прежнему n2, так n1.Next.Prev является n2.Prev, для которого установлено значение nnew
n1.Next.Prev = nnew;
n1.Next теперь имеет значение nnew
n1.Next = nnew;

removeNode метод удаляет узел из списка и повторно подключает оставшиеся узлы. insertBefore и insertAfter методы всегда вызывают removeNode на узле, который требуется вставить, прежде чем пытаться подключить его к связанному списку.
Запрос removeNode гарантирует, что узел находится в известном состоянии, прежде чем назначить его Next или Prev свойство:
function removeNode(node) if ~isscalar(node) error('Input must be scalar') end prevNode = node.Prev; nextNode = node.Next; if ~isempty(prevNode) prevNode.Next = nextNode; end if ~isempty(nextNode) nextNode.Prev = prevNode; end node.Next = dlnode.empty; node.Prev = dlnode.empty; end
Например, предположим, что вы удалили n2 из трехузлового списка (n1–n2–n3):
n2.removeNode;

removeNode удаляет n2 из списка и повторно подключает оставшиеся узлы с помощью следующих шагов:
n1 = n2.Prev; n3 = n2.Next; if n1 exists, then n1.Next = n3; if n3 exists, then n3.Prev = n1
Список вновь присоединен, поскольку n1 подключается к n3 и n3 подключается к n1. Последним шагом является обеспечение того, чтобы n2.Next и n2.Prev оба пусты (то есть n2 не подключен):
n2.Next = dlnode.empty; n2.Prev = dlnode.empty;
Предположим, что создается список с 10 узлами и сохраняется маркер перемещения в заголовке списка:
head = dlnode(1); for i = 10:-1:2 new = dlnode(i); insertAfter(new,head); end
Теперь удалите третий узел (Data свойству присвоено значение 3):
removeNode(head.Next.Next)
Теперь третий узел в списке имеет значение данных 4:
head.Next.Next
ans =
dlnode with properties:
Data: 4
Next: [1x1 dlnode]
Prev: [1x1 dlnode]И предыдущий узел имеет Data значение 2:
head.Next
ans =
dlnode with properties:
Data: 2
Next: [1x1 dlnode]
Prev: [1x1 dlnode]Чтобы удалить узел, вызовите removeNode метод на этом узле. removeNode метод разъединяет узел и повторно подключает список, прежде чем разрешить MATLAB уничтожить удаленный узел. MATLAB уничтожает узел после удаления ссылок на него другими узлами и повторного подключения списка.

При создании связанного списка и назначении переменной, содержащей, например, заголовок или конец списка, удаление этой переменной приводит к рекурсии деструктора по всему списку. При наличии достаточно большого списка очистка переменной списка может привести к превышению предела рекурсии MATLAB.
clearList метод позволяет избежать рекурсии и повысить производительность удаления больших списков путем закольцовывания списка и отключения каждого узла. clearList принимает дескриптор любого узла в списке и удаляет оставшиеся узлы.
function clearList(node) if ~isscalar(node) error('Input must be scalar') end prev = node.Prev; next = node.Next; removeNode(node) while ~isempty(next) node = next; next = node.Next; removeNode(node); end while ~isempty(prev) node = prev; prev = node.Prev; removeNode(node) end end
Например, предположим, что создается список со многими узлами:
head = dlnode(1); for k = 100000:-1:2 nextNode = dlnode(k); insertAfter(nextNode,head) end
Переменная head содержит дескриптор узла в начале списка:
head
head =
dlnode with properties:
Data: 1
Next: [1x1 dlnode]
Prev: []head.Next
ans =
dlnode with properties:
Data: 2
Next: [1x1 dlnode]
Prev: [1x1 dlnode]Вы можете позвонить clearList для удаления всего списка:
clearList(head)
Единственными узлами, которые не были удалены MATLAB, являются узлы, для которых существует явная ссылка. В этом случае эти ссылки head и nextNode:
head
head =
dlnode with properties:
Data: 1
Next: []
Prev: []
nextNode
nextNode =
dlnode with properties:
Data: 2
Next: []
Prev: []Можно удалить эти узлы, очистив переменные:
clear head nextNode
delete метод просто вызывает clearList способ:
methods (Access = private) function delete(node) clearList(node) end end
delete метод имеет частный доступ для предотвращения вызовов пользователей delete при намерении удалить один узел. Вызовы MATLAB delete неявно при уничтожении списка.
Чтобы удалить один узел из списка, используйте removeNode способ.
dlnode Класс dlnode класс реализует двойной связанный список и обеспечивает удобную отправную точку для создания более специализированных типов связанных списков. Например, предположим, что требуется создать список, в котором каждый узел будет иметь имя.
Вместо копирования кода, используемого для реализации dlnode класс, а затем разворачивая его, можно вывести новый класс из dlnode (то есть подкласс dlnode). Можно создать класс, который имеет все возможности dlnode а также определяет свои собственные дополнительные особенности. И потому что dlnode является классом дескриптора, этот новый класс также является классом дескриптора.
NamedNode Определение классаЧтобы использовать класс, создайте папку с именем @NamedNode и сохранить NamedNode.m в эту папку. Родительская папка @NamedNode должен находиться в пути MATLAB. Также можно сохранить NamedNode.m к папке пути.
Следующее определение класса показывает, как получить NamedNode класс из dlnode класс:
classdef NamedNode < dlnode properties Name = '' end methods function n = NamedNode (name,data) if nargin == 0 name = ''; data = []; end n = n@dlnode(data); n.Name = name; end end end
NamedNode класс добавляет Name для хранения имени узла.
Конструктор вызывает конструктор класса для dlnode класс, а затем присваивает значение Name собственность.
NamedNode Создание списка двойных связейИспользуйте NamedNode класс, как dlnode класс, за исключением указания имени для каждого объекта узла. Например:
n(1) = NamedNode('First Node',100); n(2) = NamedNode('Second Node',200); n(3) = NamedNode('Third Node',300);
Теперь используйте методы вставки, унаследованные от dlnode для построения списка:
n(2).insertAfter(n(1)) n(3).insertAfter(n(2))
Один узел отображает свое имя и данные при запросе его свойств:
n(1).Next
ans =
NamedNode with properties:
Name: 'Second Node'
Data: 200
Next: [1x1 NamedNode]
Prev: [1x1 NamedNode]n(1).Next.Next
ans =
NamedNode with properties:
Name: 'Third Node'
Data: 300
Next: []
Prev: [1x1 NamedNode]n(3).Prev.Prev
ans =
NamedNode with properties:
Name: 'First Node'
Data: 100
Next: [1x1 NamedNode]
Prev: []