<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>http://debianws.lexgopc.com/wiki143/index.php?action=history&amp;feed=atom&amp;title=Sentinel_node</id>
	<title>Sentinel node - Revision history</title>
	<link rel="self" type="application/atom+xml" href="http://debianws.lexgopc.com/wiki143/index.php?action=history&amp;feed=atom&amp;title=Sentinel_node"/>
	<link rel="alternate" type="text/html" href="http://debianws.lexgopc.com/wiki143/index.php?title=Sentinel_node&amp;action=history"/>
	<updated>2026-10-26T02:01:01Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.1</generator>
	<entry>
		<id>http://debianws.lexgopc.com/wiki143/index.php?title=Sentinel_node&amp;diff=2160777&amp;oldid=prev</id>
		<title>129.242.224.83: /* top */Fixed typo</title>
		<link rel="alternate" type="text/html" href="http://debianws.lexgopc.com/wiki143/index.php?title=Sentinel_node&amp;diff=2160777&amp;oldid=prev"/>
		<updated>2024-09-25T16:12:23Z</updated>

		<summary type="html">&lt;p&gt;&lt;span class=&quot;autocomment&quot;&gt;top: &lt;/span&gt;Fixed typo&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{Short description|Computer programming concept}}&lt;br /&gt;
{{about|the computer programming construct|the body part|Sentinel lymph node}}&lt;br /&gt;
{{distinguish|sentinel value}}&lt;br /&gt;
{{more citations needed|date=January 2021}}&lt;br /&gt;
&lt;br /&gt;
In computer programming, a &amp;#039;&amp;#039;&amp;#039;sentinel node&amp;#039;&amp;#039;&amp;#039; is a specifically designated [[node (computer science)|node]] used with [[linked list]]s and [[Tree (data structure)|trees]] as a traversal path terminator. This type of node does not hold or reference any data managed by the data structure.&lt;br /&gt;
&lt;br /&gt;
==Benefits==&lt;br /&gt;
{{unreferenced section|date=January 2016}}&lt;br /&gt;
Sentinels are used as an alternative over using [[null pointer|&amp;lt;code&amp;gt;NULL&amp;lt;/code&amp;gt;]] as the path terminator in order to get one or more of the following benefits:&lt;br /&gt;
* Marginally increased speed of operations&lt;br /&gt;
* Increased data structure [[Robustness (computer science)|robustness]] (arguably)&lt;br /&gt;
&lt;br /&gt;
==Drawbacks==&lt;br /&gt;
* Marginally increased memory usage, especially when linked list is short.&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
&lt;br /&gt;
=== Search in a linked list ===&lt;br /&gt;
Below are two versions of a subroutine (implemented in the [[C (programming language)|C programming language]]) for looking up a given search key in a [[Linked list#Singly linked list|singly linked list]]. The first one uses the [[sentinel value]] &amp;lt;code&amp;gt;NULL&amp;lt;/code&amp;gt;, and the second one a (pointer to the) sentinel node &amp;lt;code&amp;gt;Sentinel&amp;lt;/code&amp;gt;, as the end-of-list indicator. The declarations of the singly linked list data structure and the outcomes of both subroutines are the same.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct sll_node {                          // one node of the singly linked list&lt;br /&gt;
    struct sll_node *next;                 // end-of-list indicator or -&amp;gt; next node&lt;br /&gt;
    int key;&lt;br /&gt;
} sll, *first;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== First version using NULL as an end-of-list indicator ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line highlight=&amp;quot;7,10&amp;quot;&amp;gt;&lt;br /&gt;
// global initialization&lt;br /&gt;
first = NULL;                              // before the first insertion (not shown)&lt;br /&gt;
&lt;br /&gt;
struct sll_node *Search(struct sll_node *first, int search_key) {&lt;br /&gt;
    struct sll_node *node;&lt;br /&gt;
    for (node = first; &lt;br /&gt;
        node != NULL; &lt;br /&gt;
        node = node-&amp;gt;next)&lt;br /&gt;
    {&lt;br /&gt;
        if (node-&amp;gt;key == search_key)&lt;br /&gt;
            return node;                   // found&lt;br /&gt;
    }&lt;br /&gt;
    // search_key is not contained in the list:&lt;br /&gt;
    return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt;-loop contains two tests (yellow lines) per iteration:&lt;br /&gt;
* &amp;lt;code&amp;gt;node != NULL;&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;if (node-&amp;gt;key == search_key)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Second version using a sentinel node ====&lt;br /&gt;
The globally available pointer &amp;lt;code&amp;gt;sentinel&amp;lt;/code&amp;gt; to the deliberately prepared data structure &amp;lt;code&amp;gt;Sentinel&amp;lt;/code&amp;gt; is used as end-of-list indicator. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line&amp;gt;&lt;br /&gt;
// global variable&lt;br /&gt;
sll_node Sentinel, *sentinel = &amp;amp;Sentinel;&lt;br /&gt;
// global initialization&lt;br /&gt;
sentinel-&amp;gt;next = sentinel;&lt;br /&gt;
first = sentinel;                          // before the first insertion (not shown)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that the &amp;#039;&amp;#039;pointer&amp;#039;&amp;#039; sentinel has always to be kept at the end of the list.&lt;br /&gt;
This has to be maintained by the insert and delete functions. It is, however, about the same effort as when using a NULL pointer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; highlight=&amp;quot;6&amp;quot;&amp;gt;&lt;br /&gt;
struct sll_node *SearchWithSentinelnode(struct sll_node *first, int search_key) {&lt;br /&gt;
    struct sll_node *node;&lt;br /&gt;
    // Prepare the “node” Sentinel for the search:&lt;br /&gt;
    sentinel-&amp;gt;key = search_key;&lt;br /&gt;
    for (node = first; &lt;br /&gt;
        node-&amp;gt;key != search_key; &lt;br /&gt;
        node = node-&amp;gt;next)&lt;br /&gt;
    {}&lt;br /&gt;
 &lt;br /&gt;
    // Post-processing:&lt;br /&gt;
    if (node != sentinel)&lt;br /&gt;
        return node;                       // found&lt;br /&gt;
    // search_key is not contained in the list:&lt;br /&gt;
    return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt;-loop contains only one test (yellow line) per iteration:&lt;br /&gt;
* &amp;lt;code&amp;gt;node-&amp;gt;key != search_key;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Python implementation of a circular doubly-linked list ====&lt;br /&gt;
Linked 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.&lt;br /&gt;
&lt;br /&gt;
* The list starts out with a single node, the sentinel node which has the next and previous pointers point to itself. This condition determines if the list is empty.&lt;br /&gt;
* In a non-empty list, the sentinel node&amp;#039;s next pointer gives the head of the list, and the previous pointer gives the tail of the list.&lt;br /&gt;
&lt;br /&gt;
Following is a Python implementation of a circular doubly-linked list:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class Node:&lt;br /&gt;
    def __init__(self, data, next=None, prev=None):&lt;br /&gt;
        self.data = data&lt;br /&gt;
        self.next = next&lt;br /&gt;
        self.prev = prev&lt;br /&gt;
&lt;br /&gt;
    def __repr__(self) -&amp;gt; str:&lt;br /&gt;
        return f&amp;#039;Node(data={self.data})&amp;#039;&lt;br /&gt;
&lt;br /&gt;
class LinkedList:&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self._sentinel = Node(data=None)&lt;br /&gt;
        self._sentinel.next = self._sentinel&lt;br /&gt;
        self._sentinel.prev = self._sentinel&lt;br /&gt;
&lt;br /&gt;
    def pop_left(self) -&amp;gt; Node:&lt;br /&gt;
        return self.remove_by_ref(self._sentinel.next)&lt;br /&gt;
&lt;br /&gt;
    def pop(self) -&amp;gt; Node:&lt;br /&gt;
        return self.remove_by_ref(self._sentinel.prev)&lt;br /&gt;
&lt;br /&gt;
    def append_nodeleft(self, node):&lt;br /&gt;
        self.add_node(self._sentinel, node)&lt;br /&gt;
&lt;br /&gt;
    def append_node(self, node):&lt;br /&gt;
        self.add_node(self._sentinel.prev, node)&lt;br /&gt;
&lt;br /&gt;
    def append_left(self, data):&lt;br /&gt;
        node = Node(data=data)&lt;br /&gt;
        self.append_nodeleft(node)&lt;br /&gt;
&lt;br /&gt;
    def append(self, data):&lt;br /&gt;
        node = Node(data=data)&lt;br /&gt;
        self.append_node(node)&lt;br /&gt;
&lt;br /&gt;
    def remove_by_ref(self, node) -&amp;gt; Node:&lt;br /&gt;
        if node is self._sentinel:&lt;br /&gt;
            raise Exception(&amp;#039;Can never remove sentinel.&amp;#039;)&lt;br /&gt;
        node.prev.next = node.next&lt;br /&gt;
        node.next.prev = node.prev&lt;br /&gt;
        node.prev = None&lt;br /&gt;
        node.next = None&lt;br /&gt;
        return node&lt;br /&gt;
&lt;br /&gt;
    def add_node(self, curnode, newnode):&lt;br /&gt;
        newnode.next = curnode.next&lt;br /&gt;
        newnode.prev = curnode&lt;br /&gt;
        curnode.next.prev = newnode&lt;br /&gt;
        curnode.next = newnode&lt;br /&gt;
&lt;br /&gt;
    def search(self, value):&lt;br /&gt;
        self._sentinel.data = value&lt;br /&gt;
        node = self._sentinel.next&lt;br /&gt;
        while node.data != value:&lt;br /&gt;
            node = node.next&lt;br /&gt;
        self._sentinel.data = None&lt;br /&gt;
        if node is self._sentinel:&lt;br /&gt;
            return None&lt;br /&gt;
        return node&lt;br /&gt;
&lt;br /&gt;
    def __iter__(self):&lt;br /&gt;
        node = self._sentinel.next&lt;br /&gt;
        while node is not self._sentinel:&lt;br /&gt;
            yield node.data&lt;br /&gt;
            node = node.next&lt;br /&gt;
&lt;br /&gt;
    def reviter(self):&lt;br /&gt;
        node = self._sentinel.prev&lt;br /&gt;
        while node is not self._sentinel:&lt;br /&gt;
            yield node.data&lt;br /&gt;
            node = node.prev&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice how the &amp;lt;code&amp;gt;add_node()&amp;lt;/code&amp;gt; method takes the node that will be displaced by the new node in the parameter &amp;lt;code&amp;gt;curnode&amp;lt;/code&amp;gt;. For appending to the left, this is the head of a non-empty list, while for appending to right, it is the tail. But because of how the linkage is set up to refer back to the sentinel, the code just works for empty lists as well, where &amp;lt;code&amp;gt;curnode&amp;lt;/code&amp;gt; will be the sentinel node.&lt;br /&gt;
&lt;br /&gt;
=== Search in a binary tree ===&lt;br /&gt;
General declarations, similar to article [[Binary search tree]]:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct bst_node {                     // one node of the binary search tree&lt;br /&gt;
    struct bst_node *child[2];        // each: -&amp;gt;node  or  end-of-path indicator&lt;br /&gt;
    int key;&lt;br /&gt;
} ;&lt;br /&gt;
&lt;br /&gt;
struct bst {                          // binary search tree&lt;br /&gt;
    struct bst_node *root;            // -&amp;gt;node  or  end-of-path indicator&lt;br /&gt;
} *BST;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The globally available &amp;#039;&amp;#039;pointer&amp;#039;&amp;#039; &amp;lt;code&amp;gt;sentinel&amp;lt;/code&amp;gt; to the &amp;#039;&amp;#039;single&amp;#039;&amp;#039; deliberately prepared data structure &amp;lt;code&amp;gt;Sentinel = *sentinel&amp;lt;/code&amp;gt; is used to indicate the absence of a child.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line highlight=&amp;quot;12&amp;quot;&amp;gt;&lt;br /&gt;
// global variable&lt;br /&gt;
bst_node Sentinel, *sentinel = &amp;amp;Sentinel;&lt;br /&gt;
// global initialization&lt;br /&gt;
Sentinel.child[0] = Sentinel.child[1] = sentinel;&lt;br /&gt;
&lt;br /&gt;
BST-&amp;gt;root = sentinel;                 // before the first insertion (not shown)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note that the &amp;#039;&amp;#039;pointer&amp;#039;&amp;#039; sentinel has always to represent every leaf of the tree.&lt;br /&gt;
This has to be maintained by the insert and delete functions. It is, however, about the same effort as when using a NULL pointer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot; line=&amp;quot;11&amp;quot;&amp;gt;&lt;br /&gt;
struct bst_node *SearchWithSentinelnode(struct bst *bst, int search_key) {&lt;br /&gt;
    struct bst_node *node;&lt;br /&gt;
    // Prepare the “node” Sentinel for the search:&lt;br /&gt;
    sentinel-&amp;gt;key = search_key;&lt;br /&gt;
 &lt;br /&gt;
    for (node = bst-&amp;gt;root;;) {&lt;br /&gt;
        if (search_key == node-&amp;gt;key)&lt;br /&gt;
            break;&lt;br /&gt;
        if search_key &amp;lt; node-&amp;gt;key:&lt;br /&gt;
            node = node-&amp;gt;child[0];    // go left&lt;br /&gt;
        else&lt;br /&gt;
            node = node-&amp;gt;child[1];    // go right&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    // Post-processing:&lt;br /&gt;
    if (node != sentinel)&lt;br /&gt;
        return node;                  // found&lt;br /&gt;
    // search_key is not contained in the tree:&lt;br /&gt;
    return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Remarks:&lt;br /&gt;
# With the use of SearchWithSentinelnode searching loses the [[File-system permissions|read-only]] property. This means that in applications with [[Concurrent computing|concurrency]] it has to be protected by a [[mutex]], an effort which normally exceeds the savings of the sentinel.&lt;br /&gt;
# SearchWithSentinelnode does not support the tolerance of duplicates.&lt;br /&gt;
# There has to be exactly one “node” to be used as sentinel, but there may be extremely many pointers to it.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[Canary value]]&lt;br /&gt;
* [[Elephant in Cairo]]&lt;br /&gt;
* [[Guard (computer science)]], a boolean expression that must evaluate to true if the program execution is to continue in the branch in question&lt;br /&gt;
* [[Magic number (programming)]]&lt;br /&gt;
* [[Magic string]]&lt;br /&gt;
* [[Null object pattern]]&lt;br /&gt;
* [[Semipredicate problem]]&lt;br /&gt;
* [[Sentinel value]]&lt;br /&gt;
* [[Time formatting and storage bugs]]&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Linked lists]]&lt;br /&gt;
[[Category:Trees (data structures)]]&lt;/div&gt;</summary>
		<author><name>129.242.224.83</name></author>
	</entry>
</feed>