„Sentinel (Programmierung)“ – Versionsunterschied

[gesichtete Version][gesichtete Version]
Inhalt gelöscht Inhalt hinzugefügt
MerlBot (Diskussion | Beiträge)
+QS: Kategorien fehlen
K Abschnittlink korrigiert
 
(18 dazwischenliegende Versionen von 4 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
Als '''Sentinel''' (Aussprache: {{Audio|en-us-sentinel.ogg|sentinel}}, engl. für ''Wächter''), '''Wächterknoten''' oder '''Wächterwert''' (im engeren Sinn) bezeichnet man in der [[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.<ref>{{BibISBN|9783540779773|Seite=63}} 3 Representing Sequences by Arrays and Linked Lists</ref> Wenn so geschehen, wird nachträglich das Ergebnis auf »nicht gefunden« korrigiert.
{{QS-Antrag|3. Januar 2016| [[WP:Wikifizieren]]: [[Wikipedia:Kategorien|Kategorien]] fehlen -- [[Benutzer:MerlBot/AutoQS|MerlBot]] 19:55, 3. Jan. 2016 (CET)}}
Als '''Sentinel''' (engl. für ''Wächter''), '''Wächter''' oder '''Wächterwert''' bezeichnet man in der [[Informatik]], dort im Bereich der [[Programmierung]], ein Konstrukt, welches beim Durchsuchen z.&nbsp;B. von Listen nach Inspektion aller echten Fälle auf jeden Fall gefunden wird.


Damit wird die Anzahl der Abfragen ''innerhalb'' der Suchschleife um ''eine'' verringert auf Kosten geringfügig komplizierterer 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 Terminierung einer Sequenz durch ein normalerweise dort nicht vorkommendes spezielles Objekt, so bspw. das [[Nullzeichen]] bei [[Zeichenkette#Repräsentation mit Abschlusszeichen|Zeichenketten]], als Sentinel.


== Beispiel ==
== Beispiel ==
In den beiden folgenden Suchschleifen <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">
<syntaxhighlight lang="c" line>
struct sll_node // ein Knoten der verketteten Liste sll
// Globale Variable:
{
struct Node {
int key;
int key;
struct Node *next;
struct sll_node *next; // -> nächster Knoten oder Terminator der Liste
} sll,
} List, *first;
*first; // Zeiger auf die verkettete Liste
</syntaxhighlight>
</syntaxhighlight>
nach einem Schlüsselwert <code>Datum</code> gesucht werden – bei gleichem Suchergebnis.
nach einem Schlüsselwert <code>search_key</code> gesucht werden – bei gleichem Suchergebnis.


=== Version mit Nullzeiger ===
<ul>
Die Liste <code>sll</code> wird [[Liste (Datenstruktur)#Einfach verkettete Listen|terminiert]] durch den [[Nullwert#Nullwert als grundverschiedener Wert|Nullzeiger]] <code>NULL</code>.<ref>Ein [[Zeiger (Informatik)|Zeiger]], der den Wert 0 haben kann, muss vor der [[Dereferenzierung]] ohnehin auf 0 abgefragt werden, da die Dereferenzierung sonst auf den meisten Betriebssystem-Maschinen-Kombinationen zum Crash führt.</ref>
<li>Version ohne Sentinel:
<syntaxhighlight lang="c" line highlight="9,12">
Die Liste <code>List</code> wird [[Liste (Datenstruktur)#Einfach verkettete Liste|terminiert]] durch <code>NULL</code>.
first = NULL; // Terminierung vor der ersten Einfügung
<syntaxhighlight lang="c">
// NB: Die (nicht gezeigten) Operationen Einfügen und Löschen haben für ...
// Global:
// den immer gleichen Terminator (hier: NULL) zu sorgen.
first = NULL; // vor der ersten Einfügung


Search(struct Node *first, int Datum) {
struct sll_node *Search(int search_key)
{
struct Node *node;
struct sll_node *node;
for (node = first; node != NULL; node=node->next) {
if (node->key == Datum) return node;
for (node = first;
node != NULL;
node = node->next)
{
if (node->key == search_key)
return node; // gefunden
}
}
// Nicht gefunden
return NULL; // nicht gefunden
return NULL;
}
}
</syntaxhighlight>
</syntaxhighlight>
Die <code>for</code>-Schleife enthält pro Schleifenschritt die zwei Abfragen
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 == Datum)</code>.
* <code>if (node->key == search_key)</code>.


<li>Version mit Sentinel:
=== Version mit Sentinel ===
Der [[Zeiger (Informatik)|Zeiger]] <code>sentinel</code> zum Objekt <code>Sentinel</code> dient als Terminator der verketteten Liste <code>sll</code>.
Die Liste <code>List</code> wird terminiert durch <code>sentinel</code>.<syntaxhighlight lang="c">
Das Objekt <code>Sentinel</code> ist für die Schleife gezielt zu präparieren.
// Globale Variable:
(In diesem Sinn ist es Teil der Datenstruktur <code>sll</code>.)
struct Node Sentinel, *sentinel = &Sentinel;
<syntaxhighlight lang="c" line highlight="14">
// Global:
struct sll_node Sentinel, *sentinel = &Sentinel;
first = sentinel; // vor der ersten Einfügung
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)
SearchWithSentinel(struct Node *first, int Datum) {
{
struct Node *node;
sentinel->key = Datum;
struct sll_node *node;
// gezielte Präparation:
for (node = first; node->key != Datum; node=node->next) {
sentinel->key = search_key;

for (node = first;
node->key != search_key;
node = node->next)
{
}
}
if (node != sentinel) return node;
if (node != sentinel)
// Nicht gefunden:
return node; // gefunden
return NULL;
return NULL; // nicht gefunden
}
}
</syntaxhighlight>
</syntaxhighlight>
Die <code>for</code>-Schleife enthält pro Schleifenschritt nur die eine Abfrage
Die <code>for</code>-Schleife enthält pro Schleifenschritt nur die eine (gelb hinterlegte) Abfrage
#<code>if (node->key != Datum)</code>.
* <code>if (node->key != search_key)</code>.
;Bemerkung
</ul>
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> 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ären Suchbaum
* Suchmethode [[:en:Elephant in Cairo]] (englisch), die auf einen satirischen Essay über verschiedene Suchmethoden nach Elefanten in Afrika zurückgeht.
* Sentinel-Lymphknoten, siehe [[Wächterlymphknoten]]
* Sentinel-Lymphknoten, siehe [[Wächterlymphknoten]]

== Einzelnachweise ==
<references/>

[[Kategorie:Programmierung]]

Aktuelle Version vom 29. April 2021, 11:46 Uhr

Als Sentinel (Aussprache: sentinel/?, engl. für Wächter), Wächterknoten oder Wächterwert (im engeren Sinn) bezeichnet man in der 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.

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 Terminierung einer Sequenz durch ein normalerweise dort nicht vorkommendes spezielles Objekt, so bspw. 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 Nullzeiger

Die Liste sll wird terminiert durch den Nullzeiger NULL.[2]

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: NULL) 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) und
  • if (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

Einzelnachweise

  1. 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
  2. Ein Zeiger, der den Wert 0 haben kann, muss vor der Dereferenzierung ohnehin auf 0 abgefragt werden, da die Dereferenzierung sonst auf den meisten Betriebssystem-Maschinen-Kombinationen zum Crash führt.