„Sentinel (Programmierung)“ – Versionsunterschied
[gesichtete Version] | [gesichtete Version] |
K →Beispiel: leichte Vereinheitlichung |
Präzisierungen |
||
Zeile 3: | Zeile 3: | ||
Mit diesem Trick wird die Anzahl der Abfragen ''innerhalb'' der Suchschleife um ''eine'', nämlich die Abfrage auf das Ende der Sequenz, verringert – auf Kosten geringfügig komplizierterer Erfordernisse und Aktionen ''außerhalb'' der Schleife. |
Mit diesem Trick wird die Anzahl der Abfragen ''innerhalb'' der Suchschleife um ''eine'', nämlich die Abfrage auf das Ende der Sequenz, verringert – auf Kosten geringfügig komplizierterer Erfordernisse und Aktionen ''außerhalb'' der Schleife. |
||
Im weiteren Sinn gilt (insbesondere im englischen Sprachraum) jede Form eines Terminators einer Sequenz, so auch das [[Nullzeichen]] bei [[Zeichenkette#Repräsentation mit Abschlusszeichen|Zeichenketten]], als Sentinel. |
Im weiteren Sinn gilt (insbesondere im englischen Sprachraum) jede Form eines Terminators einer Sequenz als eines normalerweise nicht vorkommenden speziellen Objekts, so auch das [[Nullzeichen]] bei [[Zeichenkette#Repräsentation mit Abschlusszeichen|Zeichenketten]], als Sentinel. |
||
== Beispiel == |
== Beispiel == |
||
In den beiden folgenden [[C (Programmiersprache)|C]]-Funktionen <code>Search</code> und <code>SearchWithSentinel</code> soll in einer [[Verkettete Liste|verketteten Liste]] vom Typ |
In den beiden folgenden [[C (Programmiersprache)|C]]-Funktionen <code>Search</code> und <code>SearchWithSentinel</code> soll in einer einfach [[Verkettete Liste|verketteten Liste]] vom Typ |
||
<syntaxhighlight lang="c" line> |
<syntaxhighlight lang="c" line> |
||
struct sll_node // ein Knoten der verketteten Liste sll |
struct sll_node // ein Knoten der verketteten Liste sll |
||
Zeile 13: | Zeile 13: | ||
struct sll_node *next; // -> nächster Knoten oder Terminator der Liste |
struct sll_node *next; // -> nächster Knoten oder Terminator der Liste |
||
} sll, |
} sll, |
||
*first; // |
*first; // Zeiger auf die verkettete Liste |
||
</syntaxhighlight> |
</syntaxhighlight> |
||
nach einem Schlüsselwert <code>search_key</code> gesucht werden – bei gleichem Suchergebnis. |
nach einem Schlüsselwert <code>search_key</code> gesucht werden – bei gleichem Suchergebnis. |
||
Zeile 19: | Zeile 19: | ||
=== Version mit NULL === |
=== Version mit NULL === |
||
Die Liste <code>sll</code> wird [[Liste (Datenstruktur)#Einfach verkettete Liste|terminiert]] durch den [[Nullwert]] <code>NULL</code>. |
Die Liste <code>sll</code> wird [[Liste (Datenstruktur)#Einfach verkettete Liste|terminiert]] durch den [[Nullwert]] <code>NULL</code>. |
||
<syntaxhighlight lang="c" line highlight=" |
<syntaxhighlight lang="c" line highlight="9,12"> |
||
// Global: |
|||
first = NULL; // Terminierung vor der ersten Einfügung |
first = NULL; // Terminierung vor der ersten Einfügung |
||
// NB: |
// NB: Die (nicht gezeigten) Operationen Einfügen und Löschen haben für ... |
||
// den immer gleichen Terminator (hier: Nullzeiger) zu sorgen. |
// den immer gleichen Terminator (hier: Nullzeiger) zu sorgen. |
||
Zeile 38: | Zeile 37: | ||
} |
} |
||
</syntaxhighlight> |
</syntaxhighlight> |
||
Die <code>for</code>-Schleife enthält pro Schleifenschritt die zwei (gelb |
Die <code>for</code>-Schleife enthält pro Schleifenschritt die zwei (gelb hinterlegten) Abfragen |
||
* <code>if (node != NULL)</code> und |
* <code>if (node != NULL)</code> und |
||
* <code>if (node->key == search_key)</code>. |
* <code>if (node->key == search_key)</code>. |
||
=== Version mit Sentinel === |
=== Version mit Sentinel === |
||
Der |
Der [[Zeiger (Informatik)|Zeiger]] <code>sentinel</code> zum Objekt <code>Sentinel</code> dient als Terminator der verketteten Liste <code>sll</code>. |
||
Das Objekt <code>Sentinel</code> ist für die Schleife gezielt zu präparieren. |
|||
⚫ | |||
(In diesem Sinn ist es Teil der Datenstruktur <code>sll</code>.) |
|||
// Globale Variable: |
|||
⚫ | |||
struct sll_node Sentinel, *sentinel = &Sentinel; |
struct sll_node Sentinel, *sentinel = &Sentinel; |
||
// Global: |
|||
sentinel->next = sentinel; |
sentinel->next = sentinel; |
||
first = sentinel; // Terminierung vor der ersten Einfügung |
first = sentinel; // Terminierung vor der ersten Einfügung |
||
// NB: |
// NB: Die (nicht gezeigten) Operationen Einfügen und Löschen haben für ... |
||
// den immer gleichen Terminator (hier: Zeigerwert) zu sorgen. |
// den immer gleichen Terminator (hier: Zeigerwert) zu sorgen. |
||
Zeile 72: | Zeile 71: | ||
* <code>if (node->key != search_key)</code>. |
* <code>if (node->key != search_key)</code>. |
||
;Bemerkung |
;Bemerkung |
||
Die Einführung des Wächterknotens macht aus der Operation Suchen, die ohne ihn eine [[Speicherzugriff|Nur-Lese-Operation]] wäre, eine ''modifizierende'' Operation (ähnlich Einfügen und Löschen). |
|||
Wird auf die Datenstruktur [[Parallele Programmierung|parallel]] (konkurrent) zugegriffen, dann gehört auch das Suchen per <code>SearchWithSentinel</code> |
Wird auf die Datenstruktur [[Parallele Programmierung|parallel]] (konkurrent) zugegriffen, dann gehört auch das Suchen per <code>SearchWithSentinel</code> in einen [[Kritischer Abschnitt|kritischen Abschnitt]], der durch ein [[Mutex]] abgesichert werden muss. |
||
Dieser zusätzliche Aufwand kann schwerer wiegen als das Einsparen einer Abfrage pro Schleifenschritt. |
|||
== Siehe auch == |
== Siehe auch == |
||
* [[Binärer Suchbaum#Suchen ohne Duplikate (iterativ und mit Sentinel)]] Wächterknoten in einem |
* [[Binärer Suchbaum#Suchen ohne Duplikate (iterativ und mit Sentinel)]] Wächterknoten in einem binären Suchbaum |
||
* Sentinel-Lymphknoten, siehe [[Wächterlymphknoten]] |
* Sentinel-Lymphknoten, siehe [[Wächterlymphknoten]] |
||
Version vom 21. Oktober 2019, 10:17 Uhr
Als Sentinel (Aussprache: Informatik, im Bereich der Programmierung, ein Konstrukt, welches eine Sequenz derart terminiert, dass die Programmlogik nach einer erfolglosen Inspektion aller echten Fälle abschließend (mit unechtem Erfolg) auf das Ergebnis »gefunden« läuft.[1] Wenn so geschehen, wird nachträglich das Ergebnis auf »nicht gefunden« korrigiert.
, engl. für Wächter), Wächter oder Wächterwert (im engeren Sinn) bezeichnet man in derMit diesem Trick wird die Anzahl der Abfragen innerhalb der Suchschleife um eine, nämlich die Abfrage auf das Ende der Sequenz, verringert – auf Kosten geringfügig komplizierterer Erfordernisse und Aktionen außerhalb der Schleife.
Im weiteren Sinn gilt (insbesondere im englischen Sprachraum) jede Form eines Terminators einer Sequenz als eines normalerweise nicht vorkommenden speziellen Objekts, so auch das Nullzeichen bei Zeichenketten, als Sentinel.
Beispiel
In den beiden folgenden C-Funktionen Search
und SearchWithSentinel
soll in einer einfach verketteten Liste vom Typ
struct sll_node // ein Knoten der verketteten Liste sll
{
int key;
struct sll_node *next; // -> nächster Knoten oder Terminator der Liste
} sll,
*first; // Zeiger auf die verkettete Liste
nach einem Schlüsselwert search_key
gesucht werden – bei gleichem Suchergebnis.
Version mit NULL
Die Liste sll
wird terminiert durch den Nullwert NULL
.
first = NULL; // Terminierung vor der ersten Einfügung
// NB: Die (nicht gezeigten) Operationen Einfügen und Löschen haben für ...
// den immer gleichen Terminator (hier: Nullzeiger) zu sorgen.
struct sll_node *Search(int search_key)
{
struct sll_node *node;
for (node = first;
node != NULL;
node = node->next)
{
if (node->key == search_key)
return node; // gefunden
}
return NULL; // nicht gefunden
}
Die for
-Schleife enthält pro Schleifenschritt die zwei (gelb hinterlegten) Abfragen
if (node != NULL)
undif (node->key == search_key)
.
Version mit Sentinel
Der Zeiger sentinel
zum Objekt Sentinel
dient als Terminator der verketteten Liste sll
.
Das Objekt Sentinel
ist für die Schleife gezielt zu präparieren.
(In diesem Sinn ist es Teil der Datenstruktur sll
.)
struct sll_node Sentinel, *sentinel = &Sentinel;
sentinel->next = sentinel;
first = sentinel; // Terminierung vor der ersten Einfügung
// NB: Die (nicht gezeigten) Operationen Einfügen und Löschen haben für ...
// den immer gleichen Terminator (hier: Zeigerwert) zu sorgen.
struct sll_node *SearchWithSentinel(int search_key)
{
struct sll_node *node;
// gezielte Präparation:
sentinel->key = search_key;
for (node = first;
node->key != search_key;
node = node->next)
{
}
if (node != sentinel)
return node; // gefunden
return NULL; // nicht gefunden
}
Die for
-Schleife enthält pro Schleifenschritt nur die eine (gelb hinterlegte) Abfrage
if (node->key != search_key)
.
- Bemerkung
Die Einführung des Wächterknotens macht aus der Operation Suchen, die ohne ihn eine Nur-Lese-Operation wäre, eine modifizierende Operation (ähnlich Einfügen und Löschen).
Wird auf die Datenstruktur parallel (konkurrent) zugegriffen, dann gehört auch das Suchen per SearchWithSentinel
in einen kritischen Abschnitt, der durch ein Mutex abgesichert werden muss.
Dieser zusätzliche Aufwand kann schwerer wiegen als das Einsparen einer Abfrage pro Schleifenschritt.
Siehe auch
- Binärer Suchbaum#Suchen ohne Duplikate (iterativ und mit Sentinel) Wächterknoten in einem binären Suchbaum
- Sentinel-Lymphknoten, siehe Wächterlymphknoten
Einzelnachweise
- ↑ Kurt Mehlhorn, Peter Sanders: Algorithms and Data Structures. The Basic Toolbox. Springer, Berlin / Heidelberg 2008, ISBN 978-3-540-77977-3, S. 63, doi:10.1007/978-3-540-77978-0. 3 Representing Sequences by Arrays and Linked Lists