Dies ist ein als lesenswert ausgezeichneter Artikel.

B-Baum

aus Wikipedia, der freien Enzyklopädie
Zur Navigation springenZur Suche springen

EinB-Baum (englischB-tree) ist in derInformatik eineDaten- oderIndexstruktur, die häufig inDatenbanken undDateisystemen eingesetzt wird. Ein B-Baum ist ein immer vollständigbalancierter Baum, der Daten nachSchlüsseln sortiert speichert. Er kann binär sein, ist aber im Allgemeinen keinBinärbaum. Das Einfügen, Suchen und Löschen von Daten in B-Bäumen ist inamortisiert logarithmischer Zeit möglich. B-Bäume wachsen und schrumpfen, anders als viele Suchbäume, von den Blättern hin zur Wurzel.

Inhaltsverzeichnis

Geschichte und Namensgebung

[Bearbeiten |Quelltext bearbeiten]

Der B-Baum wurde1972 vonRudolf Bayer undEdward M. McCreight entwickelt. Er erwies sich als ideale Datenstruktur zur Verwaltung von Indizes für dasrelationale Datenbankmodell, das 1970 vonEdgar F. Codd entwickelt worden war. Diese Kombination führte zur Entwicklung des erstenSQL-DatenbanksystemsSystem R beiIBM.

Die Erfinder lieferten keine Erklärung für die Herkunft des NamensB-Baum. Die häufigste Interpretation ist, dassB fürbalanciert steht. Weitere Interpretationen sindB fürBayer,Barbara (nach seiner Frau),Broad,Busch,Bushy,Boeing (da Rudolf Bayer fürBoeing Scientific Research Labs gearbeitet hat),Banyanbaum (ein Baum, bei dem Äste und Wurzeln ein Netz erstellen) oderbinär aufgrund der ausgeführtenbinären Suche innerhalb eines Knotens.

Eigenschaften

[Bearbeiten |Quelltext bearbeiten]

In einemB-Baum kann ein Knoten – im Unterschied zuBinärbäumen – mehr als 2 Kind-Knoten haben. Dies ermöglicht es, mit einer variablen Anzahl Schlüssel (oder Datenwerte) pro Knoten die Anzahl der bei einer Datensuche zu lesenden Knoten zu reduzieren. Die maximale erlaubte Anzahl der Schlüssel ist von einem Parametert{\displaystyle t} (in der Literatur manchmal auch alsd{\displaystyle d},k{\displaystyle k} oderm{\displaystyle m} definiert), dem Verzweigungsgrad (oder Ordnung) des B-Baumes, abhängig. Die Bedeutung vont{\displaystyle t} ist je nach Definition unterschiedlich: Entweder bezeichnett{\displaystyle t} die maximale Anzahl von Kindknoten – in diesem Fall ist die maximal erlaubte Anzahl von Schlüsselnt1{\displaystyle t-1}, oder die minimal erlaubte Anzahl von Kindknoten[1] – in dem Fall wäre die maximal erlaubte Anzahl an Schlüsseln2t1{\displaystyle 2t-1}.

Anwendung finden B-Bäume unter anderem bei Datenbanksystemen, die mit sehr großen Datenmengen umgehen müssen, von denen nur ein Bruchteil gleichzeitig in den Hauptspeicher eines Rechners passt. Die Daten sind daherpersistent auf Hintergrundspeicher (z. B.Festplatten) abgelegt und könnenblockweise gelesen werden. Ein Knoten des B-Baumes kann dann als ein Block gelesen bzw. gespeichert werden. Durch den großen Verzweigungsgrad beiB-Bäumen wird die Baumhöhe und damit die Anzahl der (langsamen) Schreib-/Lesezugriffe reduziert. Die variable Schlüsselmenge pro Knoten vermeidet zusätzlich häufigesBalancieren des Baumes. Im Kontext von Datenbanksystemen werden abweichend der o. g. Definition vont{\displaystyle t}, folgendes definiert. Wenn über den Verzweigungsgrad des B-Baumes gesprochen wird, definiertt{\displaystyle t}, welches beim Verzweigungsgrad alsk{\displaystyle k} bezeichnet wird, die minimale Anzahl von Schlüsseln eines Knotens und2k{\displaystyle 2k} die maximale Belegung eines Knotens. Daraus ergibt sich die Anzahl der Kindknoten. Wennn{\displaystyle n} die Anzahl vorhandener Schlüsselwerte in einem Knoten ist, dann hat dieser Knotenn+1{\displaystyle n+1} Kindknoten. Mit anderen Worten hat ein Knoten mindestensk+1{\displaystyle k+1} und maximal2k+1{\displaystyle 2k+1} Kindknoten[2]. Die Ordnung eines B-Baumesm{\displaystyle m} beschreibt im Gegensatz zum Verzweigungsgrad zunächst die Anzahl der Kindknoten. Ein Knoten eines Baumes mit der Ordnungm{\displaystyle m} besitzt minimalm/2{\displaystyle \lceil m/2\rceil } und maximalm{\displaystyle m} Kindknoten. Wenn nunn{\displaystyle n} die Anzahl vorhandener Kindknoten ist, dann hat der Vaterknotenn1{\displaystyle n-1} Schlüssel.

Alle Blattknoten sind auf gleicher Höhe. Ein B-Baum wird durch den Mindestgradt{\displaystyle t} definiert. Der Wert vont{\displaystyle t} hängt von der Größe derSpeicherblöcke ab. Jeder Knoten außer dem Wurzelknoten muss mindestenst1{\displaystyle t-1} Schlüssel enthalten. Der Wurzelknoten darf mindestens 1 Schlüssel enthalten. Alle Knoten einschließlich dem Wurzelknoten dürfen höchstens2t1{\displaystyle 2t-1} Schlüssel enthalten. Die Anzahl der Kindknoten eines Knotens ist gleich der Anzahl der darin enthaltenen Schlüssel plus 1. Alle Schlüssel eines Knotens sind in aufsteigender Reihenfolge sortiert. Der Kindknoten zwischen zwei Schlüsselnk1{\displaystyle k_{1}} undk2{\displaystyle k_{2}} enthält alle Schlüssel im Bereich vonk1{\displaystyle k_{1}} undk2{\displaystyle k_{2}}. Der B-Baum wächst und schrumpft vom Wurzelknoten, was im Gegensatz zubinären Suchbäumen steht. Wie bei anderen balancierten binären Suchbäumen ist dieZeitkomplexität zum Suchen, Einfügen und Löschen gleichO(log(n)){\displaystyle O(\log(n))}. Das Einfügen eines Knotens in den B-Baum erfolgt nur am Blattknoten.[3]

Ein vollständig besetzter B-Baum, in demt{\displaystyle t} als die maximal erlaubte Anzahl von Kindknoten und h als die Höhe des Baums definiert ist, speichert geradeth+11{\displaystyle t^{h+1}-1} Schlüssel. So können etwa bei einem entsprechend groß gewähltent{\displaystyle t} (z. B.t=1024{\displaystyle t=1024}) bei einer Höhe vonh=3{\displaystyle h=3} bereits102441=(210)41=2401=1099511627775{\displaystyle 1024^{4}-1=(2^{10})^{4}-1=2^{40}-1={1\,099\,511\,627\,775}} Schlüssel gespeichert werden. Da eine Suchoperation höchstensh+1{\displaystyle h+1} Knotenzugriffe benötigt, müssen für jede Suchanfrage in einem solchen Baum höchstens fünf Baumknoten inspiziert werden.

Höhe

[Bearbeiten |Quelltext bearbeiten]

Für die Höheh{\displaystyle h} eines B-Baumes mitn{\displaystyle n} gespeicherten Datenelementen gilt:

log2t1(n+1)hlogt(n+12)+1{\displaystyle \log _{2t-1}\left(n+1\right)\leq h\leq \log _{t}\left({\frac {n+1}{2}}\right)+1}

Damit sind im schlimmsten Fall immer noch Zugriffe aufO(log(n)){\displaystyle O(\log(n))} Baumknoten zum Auffinden eines Datenelements notwendig. Die Konstante dieser Abschätzung ist aber deutlich geringer als bei (balancierten)binären Suchbäumen mit Höhelog2(n){\displaystyle \log _{2}(n)}:

log2(n)logt(n+12)log2(t){\displaystyle {\log _{2}(n) \over {\log _{t}({n+1 \over 2})}}\approx \log _{2}(t)}

Bei einem minimalen Verzweigungsgrad vont=1024{\displaystyle t=1024} benötigt ein B-Baum damit Zugriffe auf zehnmal weniger Knoten zum Auffinden eines Datenelements. Wenn der Zugriff auf einen Knoten die Dauer der gesamten Operation dominiert (wie das beim Zugriff auf Hintergrundspeicher der Fall ist), ergibt sich dadurch eine zehnfach erhöhte Ausführungsgeschwindigkeit.[4][5][6]

Definitionen

[Bearbeiten |Quelltext bearbeiten]
Abbildung 1: B-Baum
  1. Ein Knoten eines B-Baumes speichert
    • eine variable Anzahls{\displaystyle s} von Schlüsselnk1,,ks{\displaystyle k_{1},\ldots ,k_{s}} (und optional ein pro Schlüssel zugeordnetes Datenelement),
    • eine MarkierungisLeaf, die angibt, ob es sich bei dem Knoten um ein Blatt oder einen inneren Knoten handelt.
    • Falls es sich um einen inneren Knoten handelt, zusätzlichs+1{\displaystyle s+1} Verweise auf Kindknoten.
  2. Für die Schlüssel in einem B-Baum gilt eine gegenüber binären Suchbäumen verallgemeinerte Sortierungsbedingung:
  3. Alle Blattknoten des B-Baumes befinden sich in gleicher Tiefe. Die Tiefe der Blattknoten ist gleich der Höheh{\displaystyle h} des Baumes.
  4. Es gilt folgende Beschränkung für die erlaubte Anzahl von Kindverweisen bzw. Schlüsseln pro Knoten. Dazu wird eine Konstantet{\displaystyle t} festgelegt, die den minimalen Verzweigungsgrad von Baumknoten angibt.

Spezialfälle und Varianten

[Bearbeiten |Quelltext bearbeiten]

Für den Spezialfallt=2{\displaystyle t=2} spricht man von2-3-4-Bäumen, da Knoten in einem solchen Baum 2, 3 oder 4 Kinder haben können. Verbreitete Varianten des B-Baumes sindB+-Bäume, in denen die Daten nur in den Blättern gespeichert werden, undB*-Bäume, die durch eine modifizierte Überlaufbehandlung immer zu2/3{\displaystyle 2/3} gefüllt sind. Alle diese Varianten werden wie auch der reguläre B-Baum in der Praxis oft eingesetzt.

Auch einR-Baum kann als balancierter Baum als Erweiterung des B-Baumes bezeichnet werden.

Operationen

[Bearbeiten |Quelltext bearbeiten]

Suchen

[Bearbeiten |Quelltext bearbeiten]

Die Suche nach einem Schlüsselk{\displaystyle k} liefert denjenigen Knotenx{\displaystyle x}, der diesen Schlüssel speichert, und die Positionj{\displaystyle j} innerhalb dieses Knotens, für die gilt, dassk=x.kj{\displaystyle k=x.k_{j}}. Enthält der Baum den Schlüsselk{\displaystyle k} nicht, liefert die Suche das Ergebnisnicht enthalten.

Die Suche läuft in folgenden Schritten ab:

  1. Die Suche beginnt mit dem Wurzelknotenr{\displaystyle r} als aktuellem Knotenx{\displaystyle x}.
  2. Istx{\displaystyle x} ein innerer Knoten,
  3. Istx{\displaystyle x} ein Blattknoten,
Abbildung 2: Suche im B-Baum

In Abbildung 2 ist die Situation während der Suche nach dem Schlüsselk=9{\displaystyle k=9} dargestellt. Im Schritt 2 aus obigem Algorithmus wird im aktuellen Knotenx{\displaystyle x} die kleinste Positionj{\displaystyle j} gesucht, für die9x.kj{\displaystyle 9\leq x.k_{j}} gilt. Im konkreten Beispiel wird die Position2{\displaystyle 2} gefunden, da5913{\displaystyle 5\leq 9\leq 13} gilt. Die Suche wird daher im rot markierten Unterbaumx.c2{\displaystyle x.c_{2}} fortgesetzt, weil sich aufgrund der B-Baum-Eigenschaft (2) der gesuchte Schlüssel9{\displaystyle 9} nur in diesem Unterbaum befinden kann.

Einfügen

[Bearbeiten |Quelltext bearbeiten]
Abbildung 3: Teilen eines vollen B-Baum-Knotens.

Das Einfügen eines Schlüsselsk{\displaystyle k} in einen B-Baum geschieht immer in einem Blattknoten.

  1. In einem vorbereitenden Schritt wird der Blattknotenxinsert{\displaystyle x_{\mathrm {insert} }} gesucht, in den eingefügt werden muss. Dabei werden Vorkehrungen getroffen, damit die Einfügeoperation nicht die B-Baum-Bedingungen verletzt und einen Knoten erzeugt, der mehr als2t1{\displaystyle 2t-1} Schlüssel enthält.
  2. In einem abschließenden Schritt wirdk{\displaystyle k} unter Berücksichtigung der Sortierreihenfolge lokal inx{\displaystyle x} eingefügt.

Die Suche vonxinsert{\displaystyle x_{\mathrm {insert} }} läuft mit zwei Unterschieden so ab, wie unterSuchen beschrieben. Diese Unterschiede sind:

  • Das Einfügen eines neuen Schlüsselsk{\displaystyle k} geschieht immer in einem Blattknoten. Dem Einfügen muss daher immer ein vollständiger Suchlauf vorhergehen, der ergibt, dass der Schlüsselk{\displaystyle k} noch nicht existiert, und der ermittelt, in welchen Knoten er einzutragen ist. Dies kann nur ein Blattknoten sein, denn diese Aussage ist erst nach dem Durchsuchen über die gesamte Höhe des Baumes zulässig. Die Suche bricht jedoch in einem inneren Knoten ab, wenn dort der Schlüsselk{\displaystyle k} bereits gefunden wird und ein Einfügen deshalb nicht notwendig ist.
  • Bevor die Suche zu einem Kindknotenx.cj{\displaystyle x.c_{j}} absteigt, wird überprüft, obx.cj{\displaystyle x.c_{j}} voll ist, d. h. bereits2t1{\displaystyle 2t-1} Schlüssel enthält. In diesem Fall wirdx.cj{\displaystyle x.c_{j}} vorsorglich geteilt. Dies garantiert, dass die Einfügeoperation mit einem einzigen Baumabstieg durchgeführt werden kann und keine anschließenden Reparaturmaßnahmen zur Wiederherstellung der B-Baum-Bedingungen durchgeführt werden müssen.

Das Teilen eines vollen Baumknotens geschieht, wie in Abbildung 3 gezeigt. Die Suche ist an Knotenx{\displaystyle x} angekommen und würde zum Kindknotenx.c2{\displaystyle x.c_{2}} absteigen (roter Pfeil). Das heißt, die Suchposition istj=2{\displaystyle j=2}. Da dieser Kindknoten voll ist, muss er vor dem Abstieg geteilt werden, um zu garantieren, dass ein Einfügen möglich ist. Ein voller Knoten hat mit2t1{\displaystyle 2t-1} immer eine ungerade Anzahl von Schlüsseln. Der mittlere davon (in der Abbildung ist das Schlüsselx.c2.k3{\displaystyle x.c_{2}.k_{3}}) wird im aktuellen Knoten an der Suchpositionj{\displaystyle j} eingefügt. Der Knotenx.c2{\displaystyle x.c_{2}} wird in zwei gleich große Knoten mit jeweilst1{\displaystyle t-1} Schlüsseln geteilt und diese über die beiden neuen Zeigerpositionen verlinkt (zwei rote Pfeile im Ergebnis). Die Suche steigt anschließend entweder in den Unterbaumx.c2{\displaystyle x.c_{2}} oderx.c3{\displaystyle x.c_{3}} ab, je nachdem, ob der einzufügende Schlüssel kleiner oder gleich dem mittleren Schlüssel des geteilten Knotens ist oder nicht.

Löschen

[Bearbeiten |Quelltext bearbeiten]

Das Löschen eines Schlüsselskdelete{\displaystyle k_{\mathrm {delete} }} ist eine komplexere Operation als das Einfügen, da hier auch der Fall betrachtet werden muss, dass ein Schlüssel aus einem inneren Knoten gelöscht wird. Der Ablauf ist dabei wie die Suche nach einem geeigneten Platz zum Einfügen eines Schlüssels, allerdings mit dem Unterschied, dass vor dem Abstieg in einen Unterbaum überprüft wird, ob dieser genügend Schlüssel (t{\displaystyle \geq t}) enthält, um eine eventuelle Löschoperation ohne Verletzung der B-Baum-Bedingungen durchführen zu können. Dieses Vorgehen ist analog zum Einfügen und vermeidet anschließende Reparaturmaßnahmen.

Enthält der Unterbaum, den die Suche für den Abstieg ausgewählt hat, die minimale Anzahl von Schlüsselnt1{\displaystyle t-1}, wird entweder eineVerschiebung oder eineVerschmelzung durchgeführt. Wird der gesuchte Schlüssel in einem Blattknoten gefunden, kann er dort direkt gelöscht werden. Wird er dagegen in einem inneren Knoten gefunden, passiert die Löschung wie inLöschen aus inneren Knoten beschrieben.

Verschiebung

[Bearbeiten |Quelltext bearbeiten]
Abbildung 4: Verschieben eines Schlüssels im B-Baum.

Enthält der für den Abstieg ausgewählte Unterbaum nur die minimale Schlüsselanzahlt1{\displaystyle t-1}, aber ein vorausgehender oder nachfolgender Geschwisterknoten hat mindestenst{\displaystyle t} Schlüssel, wird ein Schlüssel in den ausgewählten Knoten verschoben, wie in Abbildung 4 gezeigt. Die Suche hat hierx.c2{\displaystyle x.c_{2}} für den Abstieg ausgewählt (dax.k1<kdelete<x.k2{\displaystyle x.k_{1}<k_{\mathrm {delete} }<x.k_{2}}), dieser Knoten enthält aber nurt1{\displaystyle t-1} Schlüssel (roter Pfeil). Da der nachfolgende Geschwisterknotenx.c3{\displaystyle x.c_{3}} ausreichend viele Schlüssel enthält, kann von dort der kleinste Schlüsselx.c3.k1{\displaystyle x.c_{3}.k_{1}} in den Vaterknoten verschoben werden, um im Gegenzug den Schlüsselx.k2{\displaystyle x.k_{2}} als zusätzlichen Schlüssel in den für den Abstieg ausgewählten Knoten zu verschieben. Dazu wird der linke Unterbaum vonx.c3.k1{\displaystyle x.c_{3}.k_{1}} zum neuen rechten Unterbaum des verschobenen Schlüsselsx.k2{\displaystyle x.k_{2}}. Man kann sich leicht davon überzeugen, dass dieseRotation die Sortierungsbedingungen erhält, da für alle Schlüsselk{\displaystyle k} im verschobenen Unterbaum vor und nach der Verschiebung die Forderungx.k2kx.c3.k1{\displaystyle x.k_{2}\leq k\leq x.c_{3}.k_{1}} gilt. Eine symmetrische Operation kann zur Verschiebung eines Schlüssels aus einem vorausgehenden Geschwisterknoten durchgeführt werden.

Verschmelzung

[Bearbeiten |Quelltext bearbeiten]
Abbildung 5: Verschmelzen zweier B-Baum Kindknoten.

Enthalten sowohl der für den Abstieg ausgewählte Unterbaumx.c2{\displaystyle x.c_{2}} als auch sein unmittelbar vorausgehender und nachfolgender Geschwisterknoten genau die minimale Schlüsselanzahl, ist eineVerschiebung nicht möglich. In diesem Fall wird eine Verschmelzung des ausgewählten Unterbaumes mit dem vorausgehenden oder nachfolgenden Geschwisterknoten gemäß Abbildung 5 durchgeführt. Dazu wird der Schlüssel aus dem Vaterknotenx{\displaystyle x}, welcher die Wertebereiche der Schlüssel in den beiden zu verschmelzenden Knoten trennt, als mittlerer Schlüssel in den verschmolzenen Knoten verschoben. Die beiden Verweise auf die jetzt verschmolzenen Kindknoten werden durch einen Verweis auf den neuen Knoten ersetzt.

Da der Algorithmus vor dem Abstieg in einen Knoten sicherstellt, dass dieser mindestenst{\displaystyle t} anstelle der von den B-Baum-Bedingungen gefordertent1{\displaystyle t-1} Schlüssel enthält, ist gewährleistet, dass der Vaterknotenx{\displaystyle x} eine ausreichende Schlüsselanzahl enthält, um einen Schlüssel für die Verschmelzung zur Verfügung zu stellen. Nur im Fall, dass zwei Kinder des Wurzelknotens verschmolzen werden, kann diese Bedingung verletzt sein, da die Suche bei diesem Knoten beginnt. Die B-Baum-Bedingungen fordern für den Wurzelknoten mindestens einen Schlüssel, wenn der Baum nicht leer ist. Bei Verschmelzung der letzten zwei Kinder des Wurzelknotens, wird aber sein letzter Schlüssel in das neu entstehende einzige Kind verschoben, was zu einem leeren Wurzelknoten in einem nicht leeren Baum führt. In diesem Fall wird der leere Wurzelknoten gelöscht und durch sein einziges Kind ersetzt.

Löschen aus inneren Knoten

[Bearbeiten |Quelltext bearbeiten]
Abbildung 6: Löschen eines Schlüssels aus einem inneren Knoten.

Wird der zu löschende Schlüsselkdelete{\displaystyle k_{\mathrm {delete} }} bereits in einem inneren Knoten gefunden (kdelete=x.k2{\displaystyle k_{\mathrm {delete} }=x.k_{2}} in Abbildung 6), kann dieser nicht direkt gelöscht werden, weil er für die Trennung der Wertebereiche seiner beiden Unterbäumex.c2{\displaystyle x.c_{2}} undx.c3{\displaystyle x.c_{3}} benötigt wird. In diesem Fall wird sein symmetrischer Vorgänger (oder sein symmetrischer Nachfolger) gelöscht und an seine Stelle kopiert. Der symmetrische Vorgänger ist der größte Blattknoten im linken Unterbaumx.c2{\displaystyle x.c_{2}}, befindet sich also dort ganz rechts außen. Der symmetrische Nachfolger ist entsprechend der kleinste Blattknoten im rechten Unterbaumx.c3{\displaystyle x.c_{3}} und befindet sich dort ganz links außen. Die Entscheidung, in welchen Unterbaum der Abstieg für die Löschung stattfindet, wird davon abhängig gemacht, welcher genügend Schlüssel enthält. Haben beide nur die minimale Schlüsselanzahl, werden die Unterbäume verschmolzen. Damit wird keine Trennung der Wertebereiche mehr benötigt und der Schlüssel kann direkt gelöscht werden.

Beispiel

[Bearbeiten |Quelltext bearbeiten]
Abbildung 7: Evolution eines B-Baumes

Abbildung 7 zeigt die Entwicklung eines B-Baumes mit minimalem Verzweigungsgradt=2{\displaystyle t=2}. Knoten in einem solchen Baum können minimal einen und maximal drei Schlüssel speichern und haben zwischen zwei und vier Verweise auf Kindknoten. Man spricht daher auch von einem2-3-4-Baum. In einer praktischen Anwendung würde man dagegen einen B-Baum mit wesentlich größerem Verzweigungsgrad verwenden.

Folgende Operationen wurden auf einem 2-4 Baum (siehe Abbildung 7) durchgeführt:

  • a–c) Einfügen von 5, 13 und 27 in einen anfangs leeren Baum.
  • d–e) Einfügen von 9 führt zum Teilen des Wurzelknotens.
  • f) Einfügen von 7 in einen Blattknoten.
  • g–h) Einfügen von 3 führt zum Teilen eines Knotens.
  • i–j) Um 9 löschen zu können, wird ein Schlüssel aus einem Geschwisterknoten verschoben.
  • k–l) Das Löschen von 7 führt zum Verschmelzen von zwei Knoten.
  • m) Löschen von 5 aus einem Blatt.
  • n–q) Löschen von 3 führt zur Verschmelzung der letzten zwei Kinder des Wurzelknotens. Der entstehende leere Wurzelknoten wird durch sein einziges Kind ersetzt.

Programmierung

[Bearbeiten |Quelltext bearbeiten]

Das folgende Beispiel in derProgrammierspracheC++ zeigt die Implementierung eines B-Baums mit denFunktionensearch (suchen),insert (einfügen) undtraverse (durchlaufen). Der B-Baum wird alsKlasseBTree und seine Knoten als KlasseBTreeNode deklariert. Bei der Ausführung des Programms wird die Funktionmain verwendet.[7]

Code-Schnipsel  
#include<iostream>usingnamespacestd;// Deklariert die Klasse für die Knoten des B-BaumsclassBTreeNode{int*keys;// Zeiger auf das Array mit den SchlüsselnBTreeNode**childNodes;// Array von Zeigern auf das Array mit den KindknotenBTreeNode*root;// Zeiger auf den Wurzelknoten des B-Baumsintt;// Mindestgrad des Knotens (Mindestanzahl der Kindknoten, Mindestanzahl der Schlüssel plus 1)intn;// Aktuelle Zahl der SchlüsselboolisLeafNode;// Gibt an, ob der Schlüssel ein Blattknoten istpublic:// Deklariert die Klasse BTree als friend class von BTreeNode, damit BTreeNode auf private Attribute von BTree zugreifen kannfriendclassBTree;// KonstruktorBTreeNode(int_t,bool_isLeafNode){t=_t;keys=newint[2*t-1];// Deklariert ein Array für die maximale Anzahl der SchlüsselchildNodes=newBTreeNode*[2*t];// Deklariert ein Array für die maximale Anzahl der Kindknoten// Initialisiert die Attributeroot=NULL;n=0;isLeafNode=_isLeafNode;}// Diese rekursive Funktion durchläuft alle Knoten des Teilbaums mit dem aktuellen Knoten als Wurzelknoten und gibt sie auf der Konsole ausvoidtraverse(){inti;// Index für den aktuellen Kindknoten und aktuellen Schlüssel// Diese for-Schleife durchläuft alle Kindknoten und Schlüssel des aktuellen Knotensfor(i=0;i<n;i++){// Wenn der aktuelle Knoten kein Blattknoten istif(!isLeafNode){childNodes[i]->traverse();// Rekursiver Aufruf für den aktuellen Kindknoten}cout<<" "<<keys[i];// Ausgabe auf der Konsole}// Wenn der aktuelle Knoten kein Blattknoten istif(!isLeafNode){childNodes[i]->traverse();// Rekursiver Aufruf für den Kindknoten}}// Diese rekursive Funktion durchläuft die Knoten des Teilbaums mit dem aktuellen Knoten als Wurzelknoten und sucht einen Schlüssel mit dem gegebenen Wert// Diese Funktion gibt einen Zeiger auf den Knoten mit dem angegebenen Wert zurück, wenn vorhanden, sonst einen NullzeigerBTreeNode*search(intvalue){inti=0;// Initialisiert den Index für den aktuellen Schlüssel// Diese while-Schleife durchläuft das Array mit den Schlüsseln, bis ein Schlüssel größer oder gleich dem gegebenen Wert gefunden oder das Ende des Arrays erreicht istwhile(i<n&&keys[i]<value){i++;}// Wenn der gefundene Schlüssel gleich dem gegebenen Wert ist, wird ein Zeiger auf den Knoten zurückgegebenif(keys[i]==value){returnthis;}// Wenn kein Schlüssel gefunden wurde und der aktuelle Knoten ein Blattknoten ist, wird ein Nullzeiger zurückgegebenif(isLeafNode){returnNULL;}returnchildNodes[i]->search(value);// Rekursiver Aufruf der Funktion für den Kindknoten vor dem Schlüssel, der größer oder gleich dem gegebenen Wert ist}// Diese Funktion fügt den gegebenen Schlüssel in den Teilbaums mit dem aktuellen Knoten als Wurzelknoten einvoidinsert(intkey){// Wenn der Baum leer ist, wird ein Wurzelknoten mit dem gegebenen Schlüssel eingefügtif(root==NULL){root=newBTreeNode(t,true);// Erzeugt den Wurzelknotenroot->keys[0]=key;// Initialisiert den Schlüsselroot->n=1;// Aktualisiert das Attribut für die Anzahl der Schlüssel}else// Wenn der Baum nicht leer ist{// Wenn der Wurzelknoten voll istif(root->n==2*t-1){BTreeNode*newRoot=newBTreeNode(t,false);// Erzeugt einen neuen WurzelknotennewRoot->childNodes[0]=root;// Macht den alten Wurzelknoten zum Kindknoten des neuen WurzelknotensnewRoot->splitChild(0,root);// Aufruf der Funktion, teilt den alten Wurzelknotensinti=0;// Index für den Kindknotenif(newRoot->keys[0]<key)// Wenn der Schlüssel kleiner als der gegebene Schlüssel ist, Index um 1 erhöhen{i++;}newRoot->childNodes[i]->insertNonFull(key);// Fügt den Schlüssel in den Teilbaum mit dem Kindknoten als Wurzelknoten einroot=newRoot;// Setzt den neuen Wurzelknoten}else// Wenn der Wurzelknoten nicht voll ist{root->insertNonFull(key);// Aufruf der Funktion insertNonFull für den Wurzelknoten}}}// Diese rekursive Funktion fügt den gegebenen Schlüssel in einen Knoten ein, der nicht voll sein darfvoidinsertNonFull(intkey){inti=n-1;// Initialisiert den Index des Schlüssels mit dem Maximumif(isLeafNode)// Wenn der Knoten ein Blattknoten ist{// Diese while-Schleife bestimmt den Index, wo der Schlüssel eingefügt wird und schiebt alle größeren Schlüssel um einen Index weiterwhile(i>=0&&keys[i]>key){keys[i+1]=keys[i];i--;}keys[i+1]=key;// Fügt den gegebenen Schlüssel für diesen Index einn++;// Aktualisiert das Attribut für die Anzahl der Schlüssel}else// Wenn der Knoten kein Blattknoten ist{// Diese while-Schleife bestimmt den Index des Kindknotens, in den der Schlüssel eingefügt wirdwhile(i>=0&&keys[i]>key){i--;}if(childNodes[i+1]->n==2*t-1)// Wenn der Kindknoten voll ist{splitChild(i+1,childNodes[i+1]);// Teilt den Kindknoten// Bestimmt, ob der gegebene Schlüssel, links oder rechts vom mittleren Schlüssel eingefügt wirdif(keys[i+1]<key)// Wenn der Schlüssel kleiner als der gegebene Schlüssel ist, wird der Schlüssel rechts vom mittleren Schlüssel eingefügt, sonst links{i++;}}childNodes[i+1]->insertNonFull(key);// Rekursiver Aufruf für den Kindknoten, fügt den Schlüssel in den zugehörigen Teilbaum ein}}// Diese Funktion teilt den gegebenen Kindknoten des aktuellen Knotens, der voll sein mussvoidsplitChild(intindex,BTreeNode*_node){BTreeNode*node=newBTreeNode(_node->t,_node->isLeafNode);// Erzeugt einen neuen Knotennode->n=t-1;// Initialisiert das Attribut für die Anzahl der Schlüssel des neuen Knotens// Diese for-Schleife kopiert die letzten t - 1 Schlüssel vom gegebenen Kindknoten in den neuen Knotenfor(inti=0;i<t-1;i++){node->keys[i]=_node->keys[i+t];}// Wenn der Knoten kein Kindknoten istif(!node->isLeafNode){// Diese for-Schleife kopiert die letzten t Kindknoten in den neuen Knotenfor(inti=0;i<t;i++){node->childNodes[i]=_node->childNodes[i+t];}}node->n=t-1;// Aktualisiert das Attribut für die Anzahl der Schlüssel des neuen Knotens// Diese for-Schleife bestimmt den Index des Kindknotens, in den der Schlüssel eingefügt wird// Der Kindknoten rechts vom gegebenen Kindknoten um einen Index weiter geschobenfor(inti=n;i>=index+1;i--){childNodes[i+1]=childNodes[i];}childNodes[index+1]=node;// Setzt den neuen Knoten als Kindknoten mit diesem Index// Die Schlüssel rechts vom gegebenen Kindknoten werden um einen Index weiter geschobenfor(inti=n-1;i>=index;i--){keys[i+1]=keys[i];}keys[index]=_node->keys[t-1];// Kopiert den mittleren Schlüssel in den Knotenn++;// Aktualisiert das Attribut für die Anzahl der Schlüssel des aktuellen Knotens}};// Deklariert die Klasse für den B-BaumclassBTree{BTreeNode*root;// Zeiger auf den Wurzelknotenintt;// Mindestgrad der Knoten (Mindestanzahl der Kindknoten, Mindestanzahl der Schlüssel plus 1)public:// KonstruktorBTree(int_t){root=NULL;t=_t;}// Diese Funktion durchläuft alle Knoten des Baums und gibt sie auf der Konsole aufvoidtraverse(){if(root!=NULL){root->traverse();// Aufruf der Funktion für den Wurzelknoten}}// Diese sucht einen Schlüssel mit dem gegebenen Wert// Diese Funktion gibt einen Zeiger auf den Knoten mit dem angegebenen Wert zurück, wenn vorhanden, sonst einen NullzeigerBTreeNode*search(intk){returnroot==NULL?NULL:root->search(k);// Aufruf der Funktion für den Wurzelknoten}// Diese Funktion fügt den gegebenen Schlüssel einvoidinsert(intkey){if(root==NULL){root=newBTreeNode(t,true);root->keys[0]=key;root->n=1;}else{if(root->n==2*t-1){BTreeNode*newRoot=newBTreeNode(t,false);newRoot->childNodes[0]=root;newRoot->splitChild(0,root);inti=0;if(newRoot->keys[0]<key){i++;}newRoot->childNodes[i]->insertNonFull(key);root=newRoot;}else{root->insertNonFull(key);}}}};// Hauptfunktion die das Programm ausführtintmain(){// Erzeugt einen B-Baum mit Mindestgrad 3 und fügt 8 Knoten einBTreebTree(3);bTree.insert(10);bTree.insert(20);bTree.insert(5);bTree.insert(6);bTree.insert(12);bTree.insert(30);bTree.insert(7);bTree.insert(17);cout<<"Durchlauf des erzeugten B-Baums:"<<endl;// Ausgabe auf der KonsolebTree.traverse();// Aufruf der Funktion, die die Knoten durchläuft und die Schlüssel auf der Konsole ausgibtcout<<endl;// Ruft die Funktion auf, die einen Knoten mit dem Schlüssel 6 sucht und gibt das Ergebnis auf der Konsole ausintk=6;bTree.search(k)!=NULL?cout<<"Es ist ein Knoten mit dem Schlüssel "<<k<<" vorhanden"<<endl:cout<<"Es ist kein Knoten mit dem Schlüssel "<<k<<" vorhanden"<<endl;// Ruft die Funktion auf, die einen Knoten mit dem Schlüssel 15 sucht und gibt das Ergebnis auf der Konsole ausk=15;bTree.search(k)!=NULL?cout<<"Es ist ein Knoten mit dem Schlüssel "<<k<<" vorhanden"<<endl:cout<<"Es ist kein Knoten mit dem Schlüssel "<<k<<" vorhanden"<<endl;}

Ähnliche Baumstrukturen

[Bearbeiten |Quelltext bearbeiten]

Literatur

[Bearbeiten |Quelltext bearbeiten]

Deutsch

Englisch

  • R. Bayer, E. McCreight:Organization and Maintenance of Large Ordered Indexes. In:Proceedings of the 1970 ACM SIGFIDET (Now SIGMOD) Workshop on Data Description, Access and Control. 1970, S. 107–141.[8]
  • R. Bayer, E. McCreight:Organization and Maintenance of Large Ordered Indexes. In:Acta Informatica, Band 1, 1972, S. 173–189.
  • R. Bayer, E. McCreight:Symmetric binary B-Trees: data structure and maintenance algorithms. In:Acta Informatica, Band 1, 1972, S. 290–306.

Weblinks

[Bearbeiten |Quelltext bearbeiten]

Tools zum Ausprobieren von B-Bäumen:

Einzelnachweise

[Bearbeiten |Quelltext bearbeiten]
  1. Thomas H. Cormen,Charles E. Leiserson,Ronald L. Rivest, Clifford Stein:Introduction to Algorithms. 2. Auflage. MIT Press, Cambridge MA 2001,ISBN 0-262-03293-7,S. 439 (englisch). 
  2. Alfons Kemper, André Eickler:Datenbanksysteme eine Einführung. 8. aktualisierte und erw. Auflage. Oldenbourg Verlag, München 2011,ISBN 978-3-486-59834-6,S. 217. 
  3. GeeksforGeeks:Introduction of B-Tree
  4. Ludwig-Maximilians-Universität München, Institut für Informatik:B-Bäume I
  5. T. Härder, Universität Kaiserslautern:Mehrwegbäume, B-Bäume, Höhe des B-Baumes
  6. Prof. Dr. E. Rahm, Universität Leipzig, Institut für Informatik:Algorithmen und Datenstrukturen 2
  7. GeeksforGeeks:Insert Operation in B-Tree
  8. R. Bayer, E. McCreight:Organization and Maintenance of Large Ordered Indices. In:Proceedings of the 1970 ACM SIGFIDET (Now SIGMOD) Workshop on Data Description, Access and Control (= SIGFIDET ’70). ACM, New York NY 1970,S. 107–141,doi:10.1145/1734663.1734671 (acm.org [abgerufen am 20. Februar 2019]). 
Dieser Artikel wurde am 7. Dezember 2005 indieser Version in die Liste derlesenswerten Artikel aufgenommen.
Abgerufen von „https://de.wikipedia.org/w/index.php?title=B-Baum&oldid=253957706
Kategorien: