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

Класс dlnode реализует следующие методы:
dlnode — Создайте узел и присвойте значение, переданное как входной параметр свойству Data
insertAfter Вставьте этот узел после заданного узла
insertBefore Вставьте этот узел перед заданным узлом
removeNode — Удалите этот узел из списка и повторно подключите остающиеся узлы
clearList — Удалите большие списки эффективно
удаление Закрытый метод, вызванный 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.
Должен быть путь к нескольким переменным, чтобы относиться к тому же объекту. Класс handle MATLAB обеспечивает средние значения и для x и для n2, чтобы относиться к тому же узлу.
Класс Handle задает метод eq (используйте methods('handle'), чтобы перечислить методы класса Handle), который включает использование оператора == со всеми объектами указателя.
Для получения дополнительной информации о классах Handle смотрите Сравнение Классов Указателя и Значения.
резюме Класса dlnodeВ этом разделе описываются реализацию класса dlnode.
| Пример кода | Обсуждение |
|---|---|
classdef dlnode < handle
| |
properties Data end | дизайн Класса dlnode |
properties (SetAccess = private) Next = dlnode.empty Prev = dlnode.empty end | Атрибуты свойств: Инициализируйте эти свойства к Для получения общей информации о свойствах, см. Синтаксис свойств |
methods
| Для получения общей информации о методах, seeMethods в Дизайне Класса |
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 теперь установлен to 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 является классом Handle, этот новый класс является классом Handle также.
Определение класса NamedNodeЧтобы использовать класс, создайте папку под названием @NamedNode и сохраните NamedNode.m в эту папку. Родительская папка @NamedNode должна быть на пути MATLAB. Также сохраните NamedNode.m в папку path.
Следующее определение класса показывает, как вывести класс 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: []