For the class definition code listing, see dlnode Class Synopsis.
To use the class, create a folder named @dlnode
and
save dlnode.m
to this folder. The parent folder
of @dlnode
must be on the MATLAB® path. Alternatively,
save dlnode.m
to a path folder.
dlnode
Class Designdlnode
is a class for creating doubly linked
lists in which each node contains:
Data array
Handle to the next node
Handle to the previous node
Each node has methods that enable the node to be:
Inserted before a specified node in a linked list
Inserted after a specific node in a linked list
Removed from a list
The dlnode
class implements each node as
a handle object with three properties:
Data
— Contains the data
for this node
Next
— Contains the handle
of the next node in the list (SetAccess = private
)
Prev
— Contains the handle
of the previous node in the list (SetAccess = private
)
This diagram shows a list with three-nodes n1
, n2
,
and n3
. It also shows how the nodes reference the
next and previous nodes.
The dlnode
class implements the following
methods:
dlnode
— Construct a node
and assign the value passed as an input to the Data
property
insertAfter
— Insert this
node after the specified node
insertBefore
— Insert this
node before the specified node
removeNode
— Remove this
node from the list and reconnect the remaining nodes
clearList
— Remove large
lists efficiently
delete
— Private method
called by MATLAB when deleting the list.
Create a node by passing the node's data to the dlnode
class
constructor. For example, these statements create three nodes with
data values 1
, 2
, and 3
:
n1 = dlnode(1); n2 = dlnode(2); n3 = dlnode(3);
Build these nodes into a doubly linked list using the class methods designed for this purpose:
n2.insertAfter(n1) % Insert n2 after n1 n3.insertAfter(n2) % Insert n3 after n2
Now the three nodes are linked:
n1.Next % Points to n2
ans = dlnode with properties: Data: 2 Next: [1x1 dlnode] Prev: [1x1 dlnode]
n2.Next.Prev % Points back to n2
ans = dlnode with properties: Data: 2 Next: [1x1 dlnode] Prev: [1x1 dlnode]
n1.Next.Next % Points to n3
ans = dlnode with properties: Data: 3 Next: [] Prev: [1x1 dlnode]
n3.Prev.Prev % Points to n1
ans = dlnode with properties: Data: 1 Next: [1x1 dlnode] Prev: []
Each node is unique in that no two nodes can be previous to or next to the same node.
For example, a node object, node
, contains
in its Next
property the handle of the next node
object, node.Next
. Similarly, the Prev
property
contains the handle of the previous node, node.Prev
.
Using the three-node linked list defined in the previous section,
you can demonstrate that the following statements are true:
n1.Next == n2 n2.Prev == n1
Now suppose that you assign n2
to x
:
x = n2;
The following two equalities are then true:
x == n1.Next x.Prev == n1
But each instance of a node is unique so there is only one node
in the list that can satisfy the conditions of being equal to n1.Next
and
having a Prev
property that contains a handle to n1
.
Therefore, x
must point to the same node as n2
.
There has to be a way for multiple variables to refer to the
same object. The MATLAB handle
class provides
a means for both x
and n2
to
refer to the same node.
The handle class defines the eq
method (use methods('handle')
to
list the handle class methods), which enables the use of the ==
operator
with all handle objects.
For more information on handle classes, see Comparison of Handle and Value Classes.
dlnode
Class SynopsisThis section describes the implementation of the dlnode
class.
Example Code | Discussion |
---|---|
classdef dlnode < handle
| |
properties Data end | dlnode Class Design |
properties (SetAccess = private) Next = dlnode.empty Prev = dlnode.empty end | Property Attributes: Initialize
these properties to For general information about properties, see Property Syntax |
methods
| For general information about methods, seeMethods in Class Design |
function node = dlnode(Data) if (nargin > 0) node.Data = Data; end end | Creating an individual node (not connected) requires only the data. For general information about constructors, see Guidelines for Constructors |
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 | Insert node into a doubly linked list after specified
node, or link the two specified nodes if there is not already a list.
Assigns the correct values for |
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 | Insert node into doubly linked list before specified
node, or link the two specified nodes if there is not already a list.
This method assigns correct values for See Insert Nodes |
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 | Remove node and fix the list so that remaining nodes
are properly connected. Once there are no references to node, MATLAB deletes it. |
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 | Avoid recursive calls to destructor as a result of clearing
the list variable. Loop through list to disconnect each node. When
there are no references to a node, MATLAB calls the class destructor
(see the |
methods (Access = private) function delete(node) clearList(node) end | Class destructor method. MATLAB calls the |
end end | End of private methods and end of class definition. |
Only dlnode
class methods can set the Next
and Prev
properties
because these properties have private set access (SetAccess
= private
). Using private set access prevents client code
from performing any incorrect operation with these properties. The dlnode
class
methods perform all the operations that are allowed on these nodes.
The Data
property has public set and get
access, allowing you to query and modify the value of Data
as
required.
Here is how the dlnode
class defines the
properties:
properties Data end properties(SetAccess = private) Next = dlnode.empty; Prev = dlnode.empty; end
To create a node object, specify the node's data as an argument to the constructor:
function node = dlnode(Data) if nargin > 0 node.Data = Data; end end
There are two methods for inserting nodes into the list — insertAfter
and insertBefore
.
These methods perform similar operations, so this section describes
only insertAfter
in detail.
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
How insertAfter
Works. First, insertAfter
calls the removeNode
method
to ensure that the new node is not connected to any other nodes. Then, insertAfter
assigns
the newNode
Next
and Prev
properties
to the handles of the nodes that are after and before the newNode
location
in the list.
For example, suppose that you want to insert a new node, nnew
,
after an existing node, n1
, in a list containing n1—n2—n3
.
First, create nnew
:
nnew = dlnode(rand(3));
Next, call insertAfter
to insert nnew
into
the list after n1
:
nnew.insertAfter(n1)
The insertAfter
method performs the following
steps to insert nnew
in the list between n1
and n2
:
Set nnew.Next
to n1.Next
(n1.Next
is n2
):
nnew.Next = n1.Next;
Set nnew.Prev
to n1
nnew.Prev = n1;
If n1.Next
is not empty, then n1.Next
is
still n2
, so n1.Next.Prev
is n2.Prev
,
which is set to nnew
n1.Next.Prev = nnew;
n1.Next
is now set to nnew
n1.Next = nnew;
The removeNode
method removes a node from
a list and reconnects the remaining nodes. The insertBefore
and insertAfter
methods
always call removeNode
on the node to insert before
attempting to connect it to a linked list.
Calling removeNode
ensures that the node
is in a known state before assigning it to the Next
or Prev
property:
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
For example, suppose that you remove n2
from
a three-node list (n1–n2–n3
):
n2.removeNode;
removeNode
removes n2
from
the list and reconnects the remaining nodes with the following steps:
n1 = n2.Prev; n3 = n2.Next; if n1 exists, then n1.Next = n3; if n3 exists, then n3.Prev = n1
The list is rejoined because n1
connects
to n3
and n3
connects to n1
.
The final step is to ensure that n2.Next
and n2.Prev
are
both empty (that is, n2
is not connected):
n2.Next = dlnode.empty; n2.Prev = dlnode.empty;
Suppose that you create a list with 10 nodes and save the handle to the head of the list:
head = dlnode(1); for i = 10:-1:2 new = dlnode(i); insertAfter(new,head); end
Now remove the third node (Data
property
assigned the value 3
):
removeNode(head.Next.Next)
Now the third node in the list has a data value of 4
:
head.Next.Next
ans = dlnode with properties: Data: 4 Next: [1x1 dlnode] Prev: [1x1 dlnode]
And the previous node has a Data
value of 2
:
head.Next
ans = dlnode with properties: Data: 2 Next: [1x1 dlnode] Prev: [1x1 dlnode]
To delete a node, call the removeNode
method
on that node. The removeNode
method disconnects
the node and reconnects the list before allowing MATLAB to destroy
the removed node. MATLAB destroys the node once references to
it by other nodes are removed and the list is reconnected.
When you create a linked list and assign a variable that contains, for example, the head or tail of the list, clearing that variable causes the destructor to recurse through the entire list. With large enough list, clearing the list variable can result in MATLAB exceeding its recursion limit.
The clearList
method avoids recursion and
improves the performance of deleting large lists by looping over the
list and disconnecting each node. clearList
accepts
the handle of any node in the list and removes the remaining nodes.
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
For example, suppose that you create a list with many nodes:
head = dlnode(1); for k = 100000:-1:2 nextNode = dlnode(k); insertAfter(nextNode,head) end
The variable head
contains the handle to
the node at the head of the list:
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]
You can call clearList
to remove the whole
list:
clearList(head)
The only nodes that have not been deleted by MATLAB are
those nodes for which there exists an explicit reference. In this
case, those references are head
and nextNode
:
head
head = dlnode with properties: Data: 1 Next: [] Prev: []
nextNode
nextNode = dlnode with properties: Data: 2 Next: [] Prev: []
You can remove these nodes by clearing the variables:
clear head nextNode
The delete
method simply calls the clearList
method:
methods (Access = private) function delete(node) clearList(node) end end
The delete
method has private access to prevent
users from calling delete
when intending to delete
a single node. MATLAB calls delete
implicitly
when the list is destroyed.
To delete a single node from the list, use the removeNode
method.
dlnode
ClassThe dlnode
class implements a doubly linked
list and provides a convenient starting point for creating more specialized
types of linked lists. For example, suppose that you want to create
a list in which each node has a name.
Rather than copying the code used to implement the dlnode
class,
and then expanding upon it, you can derive a new class from dlnode
(that
is, subclass dlnode
). You can create a class that
has all the features of dlnode
and also defines
its own additional features. And because dlnode
is
a handle class, this new class is a handle class too.
NamedNode
Class DefinitionTo use the class, create a folder named @NamedNode
and
save NamedNode.m
to this folder. The parent folder
of @NamedNode
must be on the MATLAB path.
Alternatively, save NamedNode.m
to a path folder.
The following class definition shows how to derive the NamedNode
class
from the dlnode
class:
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
The NamedNode
class adds a Name
property
to store the node name.
The constructor calls the class constructor for the dlnode
class,
and then assigns a value to the Name
property.
NamedNode
to Create a Doubly Linked ListUse the NamedNode
class like the dlnode
class,
except that you specify a name for each node object. For example:
n(1) = NamedNode('First Node',100); n(2) = NamedNode('Second Node',200); n(3) = NamedNode('Third Node',300);
Now use the insert methods inherited from dlnode
to
build the list:
n(2).insertAfter(n(1)) n(3).insertAfter(n(2))
A single node displays its name and data when you query its properties:
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: []