Sentinel node
In computer programming, a sentinel node is a specifically designated node used with linked lists and trees as a traversal path terminator. This type of node does not hold or reference any data managed by the data structure. BenefitsSentinels are used as an alternative over using
Drawbacks
ExamplesSearch in a linked listBelow are two versions of a subroutine (implemented in the C programming language) for looking up a given search key in a singly linked list. The first one uses the sentinel value struct sll_node { // one node of the singly linked list
struct sll_node *next; // end-of-list indicator or -> next node
int key;
} sll, *first;
First version using NULL as an end-of-list indicator// global initialization
first = NULL; // before the first insertion (not shown)
struct sll_node *Search(struct sll_node *first, int search_key) {
struct sll_node *node;
for (node = first;
node != NULL;
node = node->next)
{
if (node->key == search_key)
return node; // found
}
// search_key is not contained in the list:
return NULL;
}
The
Second version using a sentinel nodeThe globally available pointer // global variable
sll_node Sentinel, *sentinel = &Sentinel;
// global initialization
sentinel->next = sentinel;
first = sentinel; // before the first insertion (not shown)
Note that the pointer sentinel has always to be kept at the end of the list. This has to be maintained by the insert and delete functions. It is, however, about the same effort as when using a NULL pointer. struct sll_node *SearchWithSentinelnode(struct sll_node *first, int search_key) {
struct sll_node *node;
// Prepare the “node” Sentinel for the search:
sentinel->key = search_key;
for (node = first;
node->key != search_key;
node = node->next)
{}
// Post-processing:
if (node != sentinel)
return node; // found
// search_key is not contained in the list:
return NULL;
}
The
Python implementation of a circular doubly-linked listLinked list implementations, especially one of a circular, doubly-linked list, can be simplified remarkably using a sentinel node to demarcate the beginning and end of the list.
Following is a Python implementation of a circular doubly-linked list: class Node:
def __init__(self, data, next=None, prev=None):
self.data = data
self.next = next
self.prev = prev
def __repr__(self) -> str:
return f'Node(data={self.data})'
class LinkedList:
def __init__(self):
self._sentinel = Node(data=None)
self._sentinel.next = self._sentinel
self._sentinel.prev = self._sentinel
def pop_left(self) -> Node:
return self.remove_by_ref(self._sentinel.next)
def pop(self) -> Node:
return self.remove_by_ref(self._sentinel.prev)
def append_nodeleft(self, node):
self.add_node(self._sentinel, node)
def append_node(self, node):
self.add_node(self._sentinel.prev, node)
def append_left(self, data):
node = Node(data=data)
self.append_nodeleft(node)
def append(self, data):
node = Node(data=data)
self.append_node(node)
def remove_by_ref(self, node) -> Node:
if node is self._sentinel:
raise Exception('Can never remove sentinel.')
node.prev.next = node.next
node.next.prev = node.prev
node.prev = None
node.next = None
return node
def add_node(self, curnode, newnode):
newnode.next = curnode.next
newnode.prev = curnode
curnode.next.prev = newnode
curnode.next = newnode
def search(self, value):
self._sentinel.data = value
node = self._sentinel.next
while node.data != value:
node = node.next
self._sentinel.data = None
if node is self._sentinel:
return None
return node
def __iter__(self):
node = self._sentinel.next
while node is not self._sentinel:
yield node.data
node = node.next
def reviter(self):
node = self._sentinel.prev
while node is not self._sentinel:
yield node.data
node = node.prev
Notice how the Search in a binary treeGeneral declarations, similar to article Binary search tree: struct bst_node { // one node of the binary search tree
struct bst_node *child[2]; // each: ->node or end-of-path indicator
int key;
} ;
struct bst { // binary search tree
struct bst_node *root; // ->node or end-of-path indicator
} *BST;
The globally available pointer // global variable
bst_node Sentinel, *sentinel = &Sentinel;
// global initialization
Sentinel.child[0] = Sentinel.child[1] = sentinel;
BST->root = sentinel; // before the first insertion (not shown)
Note that the pointer sentinel has always to represent every leaf of the tree. This has to be maintained by the insert and delete functions. It is, however, about the same effort as when using a NULL pointer. struct bst_node *SearchWithSentinelnode(struct bst *bst, int search_key) {
struct bst_node *node;
// Prepare the “node” Sentinel for the search:
sentinel->key = search_key;
for (node = bst->root;;) {
if (search_key == node->key)
break;
if search_key < node->key:
node = node->child[0]; // go left
else
node = node->child[1]; // go right
}
// Post-processing:
if (node != sentinel)
return node; // found
// search_key is not contained in the tree:
return NULL;
}
See also
References |
Portal di Ensiklopedia Dunia