cards-deck: 100-199_university::111-120_theoretic_cs::111_algorithms_datastructures
B-Bäume
anchored to [[111.00_anchor]] requires [[111.08_algo_datastructures#Trees Grundlegende Definition]] and [[111.36_balanced_search_trees]]
Overview |
Wir möchten folgend eine spezifischere Version von Bäumen betrachten:
[!Definition] B-Bäume welche drei Eigenscahften hat ein B-Baum. Worin besteht die Motivation von B-Trees? #card Wir sprechen bei einem Bau von einem B-Baum, wenn dieser der Ordnung ist und er folgende Eigenschaften aufweist:
- alle Blätter haben die gleiche Tiefe –> sonst wäre er unbalanced!
- die Wurzel des Baumes hat Kinder, und weiterhin haben alle weiteren Knoten dann immer Kinder
- die inneren Knoten ( also nicht die Kinder ganz links und rechts von einem Knoten ) haben zwingend Kinder!
B-Trees nutzen wir, weil sie in ihrer Struktur / Definition große Datenmengen in flachen Bäumen speichern können, denn sie können pro Knoten mehrere Kinder aufweisen. Dabei kann jetzt jeder Knoten mehrere Keys aufweisen, wodurch sie sich größer auffächern können. Weiterhin geben wir aber eine obere Grenze von Keys an, sodass der Tree balanciert wird ( ein Knoten darf nicht über keys haben und somit nur Kinder haben!) ^1706630244046
[!Warning] Was wird mit einem inneren Knoten gemeint? #card Ein innerer Knoten in einem Baum ist solcher, der auf seiner Höhe noch weitere Nachbarn hat und somit nicht die Wurzel oder ein Blatt ( also Boden vom Baum) ist! ^1706630244058
Eigenschaften |
Es ergeben sich für diese Datenstruktur jetzt folgende Eigenschaften:
[!Important] In welchem Größenbereich ( Range, abhängig von Ordnung und Höhe ) kann sich befinden? #card Sofern ein B-Baum der Ordnung mit Blättern und einer Höhe von ist, gilt jetzt folgend:
Beweisen können wir es folgend: Die Zahl der Blätter ist minimal, wenn der innere Knoten die Minimalanzahl von Kindern hat. Also genau dann, wenn diese inneren Knoten was laut 3. Bedingung gefordert ist! Weiterhin ist die Blattzahl maximal, wenn die Konten eine Maximalzahl von Kindern haben, denn dann folgt zwingend: wobei angibt, wie viele wir davon haben!
Es gilt dann folgend: ^1706630244066
Folgend können wir uns noch anschauen, wie in einem Knoten eines von Kindern gefunden bzw spezifisch ausgewählt werden kann.
[!Definition] Schlüssel eines Knoten , welche Speicherorientierung liegt vor? was gilt für einen Schlüssel und dessen Teilbaum dazu? #card Wir betrachten einen Knoten . Dieser hat Schlüssel ( welche dabei Im Knoten direkt gespeichert werden ) –> also knotenorientierte Speicherung und jedem Schlüssel ist jeweils ein Unterbaum zugeschrieben, unter welchem wir weiter expandieren.
![[Pasted image 20240124150952.png]]
Diese Schlüssel sind geordnet und somit gilt jetzt folgend für die Knoten im Teilbaum von einem Schlüssel : wenn –> also der linkeste Schlüssel im Knoten, dann: –> also alle Schlüssel im Teilbaum müssen zwingend kleiner sein, als der Schlüssel von im Knoten –> von wo aus wir schauen!
falls ( also einer der zwischen dem linkesten /rechtesten Schlüssel im Knoten liegt), dann gilt: –> also alle Schlüssel innerhalb dieses Teilbaums von müssen größer als der Schlüssel links von () und kleiner als der Schlüssel rechts von ( ) sein
falls jetzt noch: , also der Schlüssel ganz rechts vom Knoten , dann ist der Schlüssel größer und somit alle Elemente des Teilbaumes, größer als die linken Nachbarn ^1706630244074
Zugreifen / Suchen
Wir möchten folgend den Verlauf einer Suche bzw eines Zugriffes in einem B-Baum betrachten:
[!Information] Zugriff mit Schlüssel und B-Baum wie suchen wir jetzt entsprechend nach unserem Inhalt? whats the resulting runtime? #card Wir beginnen in der Wurzel unseres Baumes Wenn in wir da schon unseren Schlüssel in der Liste der Schlüssel ( es kann ja mehr als 2 geben!) finden, dann sind wir schon fertig. Sonst , schauen wir, wo sich der Schlüssel befinden kann ( wir wissen ja, dass die Schlüssel sortiert und die Schlüssel derer Teilbäume auch wieder kleiner sein müssen) und suchen dann mit dieser Information den Schlüssel Wir finden ihn / oder auch nicht Wir können jetzt den Eintrag in finden –> weil wir ja pro Teilbaum maximal Elemente betrachten werden! ^1706630244082
Einfügen
Auch hierfür möchten wir eine sinnige Implementation finden, die es uns ermöglicht neue Elemente in den Baum einzufügen, so dass die Struktur erhalten bleibt!
[!Definition] Einfügen von Schlüssel wie gehen wir vor? Was passiert bzw was ist wichtig für den Knoten, wo er eingefügt wird? #card Wir wollen nach folgendem Ablauf agieren / arbeiten:
- Zugriff für Element . Wir werden an einem Punkt ein Ende erreichen ( das Element existiert noch nicht!)
- An diesem Blatt und dessen “verorten wir jetzt ”, weil wir ja nach der Suche immer nach den Keys traversieren und abbiegen, bis wir beim gesuchten Key angekommen sind ( oder unser gesuchter kleiner/größer ist)
- Sei dann jetzt bei diesem Parent der kleinste Schlüssel, wobei hier jetzt weiter ( und wenn dieser Eintrag existiert, ist der zuvor gefundene Eintrag das -te Blatt, was größer ist! )
- Wir fügen jetzt folgend als Schlüssel in links von ein und erweitern weiterhin den Bereich links von a um das Blatt . und den Bereich rechts von ( also größer , aber kleiner ) um ( den wir zuvor schon hatten) Wir erhalten folgende Struktur: ![[Pasted image 20240125210739.png]] nach dem einfügen –> der Knoten hat einen weiteren Schlüssel –> Prüfen, ob wir noch Kinder haben, sonst müssen wir aufspalten ^1706630244091
Am Ende wird ein mögliches Problem beim einfügen eines neuen Elementes genannt, welches wir betrachten und zur Not kompensieren müssen. Für diesen Fall, dass jetzt also der Knoten mehr Kinder hat, als erlaubt, müssen wir den Baum entsprechend erweitern/ anpassen.
[!Definition] Aufspalten, wenn wir im Knoten Kinder/Schlüssel haben! wie müssen wir jetzt vorgehen,um die verletzte Eigenschaft aufzulösen? #card Wir sehen jetzt, dass unser erweiterte Knoten mit Knoten zu groß ist, also müssen wir aufspalten. Dafür brauchen wir den Parent von und werden jetzt folgend in zwei Knoten mit jeweils Kindern aufspalten.
- Wir nehmen uns den Schlüssel aus dem Knoten ( weil dieser die Mitte bildet! also alles links ist kleiner, alles rechts größer) und werden diesen als Schlüssel im Parent einfügen.
- Jetzt wissen wir, dass alle Schlüssel kleiner sind, als und somit können wir den Baum mit diesen Schlüsseln jetzt in die Lücke links von im Knoten einbringen
- Weiterhin gilt selbiges für die Elemente rechts von also und die binden wir nach selbigen Prinzip rechts von im Knoten also dem Parent! Beachte, dass jetzt einen Schlüssel mehr hat und wir müssen somit schauen, das auch für diesen die Menge von Schlüssel ist Sonst müssen wir weiter aufteilen, anch selbigen Prinzip ![[Pasted image 20240125212923.png]] ^1706630244099
[!Information] Overview Einfügen in einen B-Baum was müssen wir beachten, wenn wir ein neues Element einfügen möchten? #card Wir suchen zuerst den Punkt im Baum, wo wir dann den neuen Schlüssel einfügen können ( also da, wo < und (irgendwo im Teilbaum ist unser Schlüssel passend!)). Dann werden wir folgend das Element als neuen Schlüssel einfügen und müssen bei erreichen von Kindern in einem Knoten diesen in zwei Knoten und aufteilen und dabei dann in den Parent-Knoten als neuen Schlüssel einfügen. Hier kann es dabei wieder zu Problemen kommen –> es kann dabei bis zur Wurzel iterieren.
Nur bei Eintreten dieses Falles wird die Höhe des Baumes um 1 erhöht ^1706630244108
Entfernen / Removing from B-trees
Nach der Suche und dem Einfügen, möchten wir noch das entfernen von Elementen betrachten. Man kann schon vermuten, dass es Fälle gibt, wo dann ein Teilbaum bzw Knoten angepasst oder verändert werden muss ( sonst könnten wir irgendwann nur noch Hüllen haben, visuell betrachtet)
[!Definition] Entfernen von Schlüssel wie gehen wir vor, was müssen wir nach der Ausführung betrachten? #card Auch hier möchten wir zuerst mit nach dem Element suchen, damit wir damit anschließend arbeiten können. Wir haben das Element dann im Knoten am ten Schlüssel gefunden. Sei dann jetzt der Unterbaum links von . Wenn er nur aus einem Blatt besteht, können wir den Schlüssel löschen, weil wir damit keinen Verlust erleben. Dabei verringert sich die Zahl von Kindern im Knoten . Wenn der Teilbaum jetzt größer ist, dann ist der rechteste Schlüssel innerhalb des betrachteten Teilbaums . Wir entfernen dieses Element aus dem Teilbaum und nehmen es als neuen Schlüssel statt -> wir haben also entfernt und werden das größte Element des linken Teilbaums davon als neuen Schlüssel nehmnen. Problem was jetzt auftreten könnte: Wir haben weniger als Kinder in einem Knoten –> wir verletzten also eine Grundeigenschaft ^1706630244116
Wie obig beschrieben kann es dazu kommen, dass beim Entfernen eines Elementes ein Knoten weniger als Elemente aufweist und somit die Eigenschaft verletzt, die sie haben müssen. Wir möchten das jetzt noch betrachten und eine Lösung dafür konzipiern.
[!Definition] Entfernen | Wie gehen wir vor, wenn von einem Knoten nach dem löschen weniger als Kinder auftreten? Was müssen wir bei dem neuen Knoten beachten? #card Wenn eine Wurzel mit einem einzigen Kind ist, dann können wir diese Wurzel entfernen. –> Denn wir können das Element dann als Schlüssel im darüberliegenden Knoten übernehmen! Dabei verringert sich die Höhe des Baumes!
Wenn jetzt keine Wurzel ist, dann probieren wir diesen Knoten mit dem Geschwisterknoten zu vereinigen. Das heißt wir schauen uns von Schlüssel den Nachbarknoten an, wo der Baum dazwischen liegt (also etwa oder ), und versuchen dann die beiden zu verbinden und zu einem Knoten zu vereinigen. Visuell folgend: ![[Pasted image 20240125215506.png]] Dabei wir jetzt der neue Knoten eventuell zuviele Kinder haben mit Wenn das der Fall ist, dann spalten wir nochmals auf, bis wir entsprechend genug / wenige Knoten haben ->Diese Operation ist immer möglich! ^1706630244125
Wir können jetzt aus der obigen Betrachtung heraus folgende Eigenschaften zu B-Bäumen festhalten:
[!Important] Eigenschaften von B-Bäumen im Bezug auf die Operationen auf diesen was ist die Laufzeit für alle Operationen?, warum? #card Jegliche B-Bäume der Ordnung haben bei den Operationen Search,Einfügen,Entfernen eine Laufzeit von Wie groß wählt man dann jetzt ? Das ist stark variable und kommt drauf an, wo man diese Struktur anwendet: -> Bei Festplatten schaut man, dass ein einziger Knoten auf das Paging eines Hauptspeichers passt ( man also nur einmal laden und dann mit schnellem Zugriff damit arbeiten kann) Das wäre meist so 4MB! ^1706630244133