B-Baum-Tool Erweiterung und Redesign

Werbung
Leopold-Franzens-Universität Innsbruck
Institut für Informatik
Datenbanken und Informationssysteme
B-Baum-Tool
Erweiterung und Redesign
Bachelor-Arbeit
Felix Putz
betreut von
Prof. Dr. Günther Specht
MSc PhD Michael Tschuggnall
Innsbruck, 7. November 2016
Zusammenfassung
Im Zuge der Optimierung von Datenbankanwendungen auf Festplatten
gewannen speziell dafür entwickelte Datenstrukturen wie B-Bäume zunehmend an Bedeutung. Es lassen sich damit nicht nur Datenabfragen verkürzen, sondern auch abschätzen. Eine Datenbankanwendung
kann somit gezielter auf Anforderungen, und in Verbindung mit der
benötigten Hardware aufgebaut werden. In dieser Arbeit wird ein webbasiertes Tool entwickelt, welches die Operationen und Besonderheiten
von B-Bäumen verständlich zu visualisieren versucht. Dabei wird zum
Verständnis zuerst eine Einführung mit Hintergrundinformationen gegeben, und folgend typische Operationen auf B-Bäume beispielhaft erklärt. Die zweite Hälfte der Arbeit beschäftigt sich hauptsächlich mit
der Programmierung, die Schritt für Schritt aufgebaut wird. Zahlreiche Beispiele und Anmerkungen verdeutlichen die Vorgehensweise und
komplexere Inhalte.
Danksagung
III
Vorwort
Diese Arbeit soll eine solide Einführung rund um die Idee bis zur programmierten Umsetzung der B-Bäume geben. Dabei werden komplizierte Teilbereiche durch Hintergrundinformationen und Bildern Schritt für
Schritt erklärt. Zudem sind Abkürzungen und schwierige Begriffe, die im
Laufe der Arbeit eingeführt werden, durch Unterstrich markiert, und in
einem Glossar mit kurzer Beschreibung zusammengefasst. So soll dem
Leser ein besonders leichter und schneller Einstieg zu den Inhalten gelingen. Im Besonderen wird parallel zu dieser Arbeit ein webbasiertes-Tool
entwickelt, welches auch Studenten zum Zwecke des Lernerfolgs dienen
soll. Ich bin der Überzeugung, dass Interessenten mit dieser Arbeit sehr
entsprochen werden kann, lege aber darüber hinaus auch ein gewisses
Engagement zur eigenen Übung Nahe, um sich in diesem Teilgebiet der
Informatik selbst festigen zu können.
V
Inhaltsverzeichnis
1 Einleitung
1
2 Definition (Varianten) der
2.1 B-Baum nach Bayer . .
2.2 B+-Baum . . . . . . . .
2.3 B*-Baum . . . . . . . .
B-Bäume
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
3 Operationen
3.1 Search . . . . . . . . . .
3.2 Insert . . . . . . . . . .
3.3 Delete . . . . . . . . . .
3.4 Laufzeit für Datenzugriff
3.4.1 Vereinfachung 1 3.4.2 Vereinfachung 2 -
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
Laufzeitverhalten
Laufzeitverhalten
4 B-Baum-Tool
4.1 Analytische Vorbereitung . . . . . . . . . .
4.1.1 Ziel . . . . . . . . . . . . . . . . . .
4.1.2 Problemstellung . . . . . . . . . . .
4.1.3 Anforderungen . . . . . . . . . . . .
4.2 Ausarbeitung . . . . . . . . . . . . . . . . .
4.2.1 Server und Verzeichnisbaum . . . . .
4.2.2 Der B-Baum in JavaScript . . . . . .
4.2.3 Die grafische Darstellung . . . . . .
4.2.4 Transformationen und Animationen
4.3 Benutzerschnittstelle (GUI) . . . . . . . . .
4.3.1 Laden von Beispielbäumen . . . . .
4.3.2 Erstellen eines neuen Baumes . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
3
4
4
.
.
.
.
.
.
5
. 5
. 6
. 7
. 10
. 12
. 12
.
.
.
.
.
.
.
.
.
.
.
.
15
15
15
15
16
16
17
18
18
20
22
23
25
.
.
.
.
.
.
.
.
.
.
.
.
5 Auswertung und Ausblick
29
Glossar
30
Literaturverzeichnis
31
VII
Kapitel 1
Einleitung
Vor allem Datenbanken sind auf ein schnelles Abgreifen von benötigten
Daten angewiesen, um Abfragezeiten möglichst kurz zu halten. Meist
sind Datenbanken jedoch zu groß, um sie in einen schnellen flüchtigen
Speicher laden zu können. Auch wenn über die Jahre ein Plattenzugriff
etwas schneller geworden ist, erreicht man heute kaum Zugriffszeiten von
10 Millisekunden. [BZ13] Dies ist die benötigte Zeit, um den Lesekopf in
die richtige Spur zu positionieren, und dort auf das Eintreffen der Daten
auf der drehenden Platte zu warten. Im Vergleich zum Arbeitsspeicher,
wo ein Zugriff etwa 25 Nanosekunden braucht, ist eine Festplatte dabei
um 400.000 mal langsamer. Um auf Daten im Festspeicher effizienter
zugreifen zu können, musste deshalb eine Strategie entwickelt werden,
diese Daten so abzuspeichern, damit diese Schwäche des Festspeichers
minimiert wird. Die Idee war es, eine Indexstruktur zu entwerfen, die
sich möglichst gut an den Festspeicher anpassen lässt, um die Anzahl
der Datenzugriffe klein zu halten. Dazu entwickelten Rudolf Bayer und
Edward M. McCreight den B-Baum [Bay72]. Dessen Knoten lassen sich
auf die Seiten einer Festplatte, welche in einem Schritt gelesen werden,
abbilden. Eine weitere Besonderheit des B-Baumes ist seine Eigenschaft
”nach oben zu wachsen”, wodurch er auch seine balancierte Struktur
behält. Je nach Datenfülle lässt sich dann die Anzahl an Seitenzugriffen
abschätzen.
Kategorisch ist ein B-Baum eine Indexstruktur; im Besonderen ein balancierter Suchbaum. Eine Indexstruktur ist eine spezielle Anordnung
von Daten, die mit Hilfe eines gewählten Suchkriteriums schneller gefunden werden können. Ein Beispiel dafür wäre eine Mitarbeiterkartei,
wobei die Nachnamen nach dem Anfangsbuchstaben sortiert sind. Eine Suche nach einem bestimmten Buchstaben öffnet dann die richtige
Stelle in der Kartei, wo alle Mitarbeiter mit gewähltem Anfangsbuchstaben vorliegen. Ein Suchbaum ist eine Datenstruktur die, wie der Name
erahnen lässt, baumförmig angeordnet ist. Man stelle sich den Baum
1
KAPITEL 1. EINLEITUNG
kopfüber hängend vom Wurzelstamm bis zu den Blättern vor. Dabei
sind die Wege bis zu den Blättern durch “Schlüssel“ verbunden, die den
richtigen Weg (Referenz) zu den gesuchten Daten zeigen. Es kann jedoch
bald zu einem Ungleichgewicht kommen, wenn sich ähnliche Daten (nach
Suchkriterium) gehäuft in nahem Umfeld einfügen. Eine Suche lässt sich
dann nicht mehr genauer abschätzen, und effizient durchführen. Um dem
entgegenzuwirken kann man Bäume ausbalancieren, wobei jeder Datensatz dann nach gewissen Schritten gefunden wird.
Unterteilen lassen sich B-Bäume beispielsweise in der minimal geforderten Datenbelegung, und der Möglichkeit die Daten auszulagern. In den
ersten Jahren wurden diese Variationen von unterschiedlichen Autoren
als B+ und B* -Bäume mit unterschiedlichen Kriterien zusammengefasst. 1979 wurden diese dann von Douglas Comer [Com79] genauer
voneinander abgegrenzt. Das National Institute of Standards and Technology (NIST) 1 nahm sich später dieser Beschreibungen an.
Von den Autoren wurde der B-Baum begrifflich nicht näher erleutert.
Über die Jahre spekulierte man für das ”B”mit Namen wie: ”balanced,
broad, bushy”. Auch ”Boeing”wäre eine Möglichkeit, da Bayer und McCreight zur Entstehungszeit für Boeing in der Forschung tätig waren.
Vielleicht ist es jedoch bei all diesen Interpretationen am sinnvollsten
von ”Bayer”Bäumen zu sprechen, wie es bereits Douglas Comer vorschlug.
Beispielhafter B-Baum
1
Offizielle Internetseite: https://www.nist.gov/
Publikationen lassen sich schnell und einfach über die Suche aufrufen.
2
Kapitel 2
Definition (Varianten) der
B-Bäume
2.1
B-Baum nach Bayer
Nach Rudolf Bayer wurde der B-Baum mit folgenden Anforderungen
definiert [Bay72] :
• Jeder Knoten des Baumes kann zwischen n und 2n Datensätze
aufnehmen. Die Wurzel des Baumes ist davon ausgenommen. N
steht dann für die Ordnung des Baumes.
• Ein einzelner Datensatz besteht aus einem eindeutig bestimmten
Schlüssel und dem eigentlichen Datenteil.
• Wenn m die Anzahl der tatsächlichen Datensätze eines Knotens
ist, so hat er m+1 Nachfolgeknoten (Kindknoten). Ausgenommen
sind die Knoten der untersten Ebene. Diese, man nennt sie Blätter
oder Blattknoten, haben keine Nachfolger unter sich.
Siehe Beispielbaum- Referenz.
• Die Datensätze sind im Baum nach dem Schlüssel geordnet.
In weiterer Folge ergeben sich verschiedene Möglichkeiten solch einen
Baum umzusetzen. Beispielsweise müsste der Datenteil eine fixierte maximale Größe haben, damit alle Datensätze eines Knotens auf einer Seite
Platz finden. Dies wäre mit einem kleinen Datenteil gut umsetzbar. Bei
größerem Datenteil ist es hingegen vorteilhafter, wenn ein Datensatz nur
eine Referenz (Pointer) zu dem eigentlichen Datenteil halten muss. Dadurch haben mehrere Schlüssel in einer Seite Platz, und der Baum weist
eine geringere Höhe auf. Man beachte dabei, dass durch die Datenreferenzierung ein weiterer Seitensprung erforderlich wird.
3
KAPITEL 2. DEFINITION (VARIANTEN) DER B-BÄUME
2.2
B+-Baum
Eine andere Variante des B-Baumes stellt der B+-Baum dar [KE09].
Sein Ziel ist es den Aufbau so zu verändern, damit häufige Abfragen auf
nachliegende Datenbereiche ohne ein erneutes Durchlaufen des Baumes
möglich ist. Eine mögliche Frage wäre: ”Gib mir alle Namen aus, die zwischen Bayer und McCreight liegen!”. Dazu müssen sämtliche Datensätze
auf die unterste Ebene ausgelagert werden. Diese Knoten in der Blattebene werden dann als doppelt verkettete Liste verknüpft. Der Baum
selbst behält im Durchlauf nur mehr den Schlüsselteil für eine effiziente
Suche bis zu den Datensätzen.
Entnommen aus [Sch13]
2.3
B*-Baum
Bei dieser Form des B-Baums setzt man auf einen höheren Füllgrad
der einzelnen Knoten. Dabei muss beispielsweise ein Knoten mindestens
mehr als 3/4 befüllt sein. Man erhofft sich dadurch ein Flacher-Werden
des Baumes, und dadurch eine Minderung an Seitenzugriffen. Allerdings
werden die Operationen komplizierter, und bei ungeschickt hoher Wahl
des Füllgrads eine öfter auftretende und eventuell weitreichendere Umstrukturierung des Baumes notwendig.
4
Kapitel 3
Operationen
3.1
Search
Die Suche nach einem Datensatz erfolgt mit Hilfe des Schlüssels, welcher
dem eigentlichen Datenteil zugeordnet ist. Da die Schlüssel geordnet
vorliegen, lassen sich folgende Regeln definieren:
1. Lese Wurzelknoten.
2. Suche KEY in aktuellem Knoten.
• Wenn gefunden, dann gib Datensatz aus. ENDE.
• Wenn nicht gefunden, bestimme nächsten Kindknoten.
– Nächster Kindknoten ist NULL.
KEY nicht gefunden. ENDE.
– Lese Kindknoten, und gehe zu Punkt 2.
Der Pfad für einen typischen Durchlauf veranschaulicht den Such-Algorithmus,
und ist von der Wurzel beginnend in gelber Farbe hervorgehoben:
Die Suche nach dem Schlüsseleintrag 15. Dabei wird der Wurzelknoten
gelesen, und Eintrag 32 mit 15 verglichen. 15 ist kleiner als 32, so wird
im linken Kindknoten weiter gesucht. Da 15 größer ist als 11, wird zum
rechten Nachbarelement weiter gegangen. 15 ist kleiner als 17, so wird
in seinem linken Kindknoten weiter gesucht. In diesem Knoten wurde
15 gefunden.
5
KAPITEL 3. OPERATIONEN
3.2
Insert
Beim Einfügen eines Schlüssels entsteht ein Knotenüberlauf, sobald die
Vereinbarung für die Maximalanzahl an erlaubten Elementen im Knoten
(2n) überschritten wird. Die anschließende Behandlung lässt den Baum
von unten nach oben wachsen.
1. Suche KEY im Baum
• Wenn gefunden, dann breche ab. ENDE.
• Wenn nicht gefunden, bleibe bei Knoten.
2. Füge KEY in Knoten ein.
3. Prüfe, ob Anzahl an Datensätzen <2n
• Ja, kein Überlauf. ENDE.
• Nein, Überlauf.
– Wähle KEYn+1 (mittlerer Schlüssel).
– Hänge linke, und rechte Schlüssel im Knoten
als linken und rechten Kindknoten an KEYn+1 an.
– Füge KEYn+1 in Elternknoten ein, und gehe zu Punkt 3.
Wie beschriebener Knotensplit funktioniert, wird im folgenden veranschaulicht.
Überlaufbehandlung
Man nehme wieder den selben Baum, wie bereits für die Schlüsselsuche
eingeführt. Der Fokus wird hierbei auf den linken Teilbaum gelegt. Um
einen Überlauf zu provozieren, wird der Schlüssel 9 eingefügt. Da nun
der Knoten mit 2,6,8,9,10 mehr als 2n Einträge hat, wird der Knotensplit als Überlaufbehandlung durchgeführt. Dazu wird das mittlere Element 8 gewählt, und seine linken und rechten Schlüsselnachbarn ihm
als Kindknoten angehängt. Anschließend wird die 8 als Elternelement
im Elternknoten eingefügt. Der daraus entstandene Teilbaum sieht wie
folgt aus:
−→
6
KAPITEL 3. OPERATIONEN
3.3
Delete
Vor dem Löschen müssen zuerst ein paar Vereinbarungen definiert werden. Denn gelöschte Positionen müssen meist durch andere Elemente
besetzt werden, um die Baumintegrität zu bewahren. Dabei sollte klar
sein, wo solch ein Schlüssel zu suchen ist. Auch sind manchmal Umstrukturierungen notwendig, wobei fest stehen sollte, in welche Richtung sich
diese orientieren. Der grundlegende Algorithmus wird nun eingeführt.
1. Suche KEY im Baum
• Wenn nicht gefunden, dann breche ab. ENDE.
• Wenn gefunden, bleibe bei Knoten.
2. Lösche KEY aus Knoten.
• Wenn Knoten ist Elternknoten.
– Ersetze KEY-Position durch nächstkleineres oder
nächstgrößeres Element der Kindknoten.
(Ordne dessen Kind richtig ein!)
– Setze Kindknoten als aktuellen Knoten.
3. Prüfe auf Unterlauf
• Wenn Anzahl an Elemente >n.
ENDE.
4. Unterlaufbehandlung
• Knoten hat Nachbarknoten mit genau n Einträgen
– Zusammenfassen mit dem Nachbarknoten und gemeinsamen Elternelement.
– Setze für diesen Elternknoten bei Punkt 3 fort.
• Ansonsten führe Rotation durch.
– Wähle linken oder rechten Nachbarknoten für Rotation.
– Verschiebe gemeinsames Elternelement in aktuellen Knoten.
– Ersetze ursprüngliche Position des Elternelements durch
sein nächst-kleineres bzw. nächst-größeres Element des
gewählten Nachbarknoten.
Es wurde bewusst die Möglichkeit für die Entscheidungen nach links
oder rechts offen gelassen. Man könnte nun den Algorithmus dahingehend verbessern, indem bei Entscheidungssituationen beide Wege in Betracht gezogen werden. Würde beim Löschen in einem Elternknoten das
7
KAPITEL 3. OPERATIONEN
nächstkleinere Element einen Unterlauf provozieren, könnte stattdessen
auch beim Nächstgrößeren nachgesehen werden, wo dies nicht der Fall
sein könnte. Ähnliche Vorgehensweise wäre auch für die Unterlaufbehandlung eine Optimierung, die größere Umstrukturierungen vermeiden
könnte. Zur Verdeutlichung werden nun repräsentative Beispiele für den
Löschalgorithmus gezeigt, um Besonderheiten hervorzuheben. Es wird
vom selben Baum ausgegangen, welcher bereits bei der Suche eingeführt
wurde.
Löschen in Elternknoten
Der Schlüssel 11 soll gelöscht werden. Nach der erfolgreichen Suche wird
sich seine Position gemerkt, und anschließend das nächstkleinere Element in seinem linken Teilbaum gesucht. Somit wurde 10 bestimmt,
und anstelle des gelöschten Schlüssels eingetragen.
−→
Unterlaufbehandlung durch Zusammenfassen
Durch Knotenzusammenfassungen sind auch Höhenschrumpfungen möglich:
Ein Löschen von Schlüssel 40, und anschließend 48, bewirkt im rechten
Teilbaum ein Zusammenfassen beider Knoten.
8
KAPITEL 3. OPERATIONEN
Dabei wird das gemeinsame Elternelement 44 miteinsortiert. Dadurch
entsteht ein erneuter Unterlauf mit darauffolgendem Zusammenfassen.
Der gemeinsame elterliche Schlüssel ist 32. Dieser wird mit den anderen
zusammengelegt, wodurch sich der Baum in der Höhe vermindert:
Unterlaufbehandlung durch Rotation
Lassen sich keine Nachbarn mit genau n Elementen finden, wird eine
Rotation durchgeführt. Um solche Situation herbeizuführen, wird dem
Baum, wie bereits bei der Einfüge-Operation getan, der Schlüssel 9 hinzugefügt. Man erhält dadurch folgenden Baum:
Anschließend wird 48 gelöscht, und eine Rotation vom rechten Nachbarknoten nach links durchgeführt. Dabei bekommt der unterlaufene Knoten das gemeinsame Elternelement 49, und auf seiner ursprünglichen
Position durch das nächstgrößere Kindelement ersetzt. Hierbei muss9
KAPITEL 3. OPERATIONEN
ten keine Teilbäume verschoben werden, da die Rotation auf Blattebene
stattfand.
Um nun eine Rotation zu provozieren, wo auch Teilbäume umgehängt
werden müssen, löscht man den Schlüssel 58. Denn das bewirkt ein Zusammenfassen mit Elternelement 50, wodurch dieser Elternknoten dann
eine Unterlaufbehandlung durchführen muss.
Wie in der Abbildung hervorgehoben, wird eine Rotation vom linken
Nachbarknoten nach rechts durchgeführt. Man beachte das richtige Einordnen des kindlichen Teilbaums (hier: Knoten auf Blattebene).
3.4
Laufzeit für Datenzugriff
Die entstehenden Kosten für das Auffinden und Zugreifen auf einen Datensatz werden hier am Beispiel der Suchfunktion gezeigt. Grundsätzlich
berechnet sich solch eine Abschätzung durch die Anzahl an Knotenzugriffen innerhalb des Baumes, sowie dem schlussendlichen Zugriff auf die
gesuchten Daten, und der dafür jeweils benötigten Speicherzugriffszeit.
Hierfür wird angenommen, dass ein Knoten unter einmal vollständig
eingelesen werden kann. Die Anzahl an Knotenzugriffen richtet sich
10
KAPITEL 3. OPERATIONEN
nach der Höhe h des Baumes. Diese ist im wesentlichen Abhängig vom
Verzweigungsgrad. Wenn man von einer Minimalbelegung ausgeht, entspricht der Verzweigungsgrad der Ordnung des Baumes, plus einem weiteren Kindknoten. Wie viele Datensätze ein Baum der Ordnung n und
der Höhe h fasst, wird nun schrittweise berechnet:
Auf der Ebene 0 befindet sich die Wurzel. Es wird 1 Knoten gezählt.
Die Wurzel selbst verweist in nächster Ebene auf 2 Kindknoten. Ebene zwei umfasst folgend mindestens 2*(n+1)Knoten. Je nach Höhe des
Baumes werden für jede weitere Ebene (n+1) Kindknoten dazu multipliziert. Es befinden sich demnach:
2*(n+1)h−1 Knoten auf einer beliebigen Ebene.
Da sich, wie angenommen, in jedem Knoten genau n Datensätze befinden, gibt es:
2n*(n+1)h−1 Datensätze auf Ebene h.
Um nun herauszufinden wie viele Datensätze ein Baum mindestens hat,
müssen alle Ebenen aufsummiert werden. Somit gilt für die Wurzel, und
alle Nachfolgeknoten:
P
1+ hi=1 2n*(n+1)i−1
Durch Vereinfachung des Terms (siehe 3.4.1, Seite 12) erhält man:
2(n+1)h -1
Um nun herauszufinden, welche Höhe h ein minimal belegter B-Baum
mit N Datensätze hat, setzt man
N = 2(n+1)h -1
und erhält für die Höhe (siehe 3.4.2, Seite 12)
log( N +1 )
2
h = log(n+1)
Diese theoretische Höhe entspricht nun einer Minimalbelegung, und muss
noch auf die nächst-größere ganze Zahl aufgerundet werden, um die
tatsächliche Höhe des B-Baums zu erhalten, wo alle Datensätze Platz
finden. (Sofern die Höhe, wie in den meisten Fällen, keiner ganzen Zahl
entspricht.)
Ein Beispiel:
Man nehme an, jeder Österreicher [SA16] steht im Telefonbuch, und
dieses sei in einem B-Baum gespeichert. Wie viele Seitenzugriffe werden
für die 8.700.471 Datensätze benötigt, wenn man von einer optimalen
Seitengröße von 4kB ausgeht, wobei ein Indexeintrag 16B belegt?
(Unter “optimal“ wird eine Knotengröße verstanden, die genau einer
Speicherseite entspricht. Des weiteren ist für den Indexeintrag die weiterführende Referenz bereits inkludiert.)
11
KAPITEL 3. OPERATIONEN
3.4.1
Vereinfachung 1 - Laufzeitverhalten
Um den Term zu vereinfachen, gleicht man die Summe der
Ph i
1−z h+1
Lösungsformel der Geometrischen-Reihe
an, und
i=0 z =
1−z
wendet diese dann an.
1+ hi=1 2n*(n+1)i−1
Herausziehen des Faktors 2n.
P
1+2n* hi=1 (n+1)i−1
Angleichen der Summe.
P
i
1+2n* h−1
i=0 (n+1)
Anwenden der Lösungsformel der Geometrischen-Reihe.
(h−1)+1
1+2n* 1−(n+1)
1−(n+1)
Durch Berechnung erhält man
h
1+2n* 1−(n+1)
−n
Minus des Nenners aus dem Bruch nehmen, und n kürzen.
1+(-2*(1-(n+1)h ))
Durch weiteres Berechnen erhält man
1-2+2(n+1)h
Nach dem letzten Schritt kann nicht weiter vereinfacht werden,
und man erhält:
2(n+1)h -1
P
3.4.2
Vereinfachung 2 - Laufzeitverhalten
Gesucht ist die Höhe h. Man forme nun so um, bis h auf einer Seite
der Gleichung steht. Da h als Exponent vorkommt, wird zur Hilfe der
Logarithmus eingesetzt. (log zh = h* log z)
N = 2(n+1)h -1
1 addieren, dann durch 2 dividieren.
N +1
h
2 = (n+1)
Logarithmus anwenden.
log N 2+1 = h* log(n+1)
Durch dividieren von log(n+1) erhält man
h=
12
log( N2+1 )
log(n+1)
KAPITEL 3. OPERATIONEN
Zuerst berechnet man die Ordnung des Baumes. Die mögliche Anzahl
an Einträgen in einer Seite ist demnach
4096 / 16 = 256
Und die Ordnung des Baumes ist somit
n = 256 / 2 = 128
Durch Einsetzen
in die erarbeitete Formel erhält man
log( 8700471+1
)
2
h = log(128+1) = 3, ...
Auf die nächst-größere Zahl aufgerundet, beträgt die Höhe dieses Baumes 4.
Man könnte nun sein Ergebnis überprüfen, und berechnet sich die Minimalbelegung für h=3, und h=4, wobei die beispielhafte Anzahl an
Datensätze dazwischen liegen muss.
2(n+1)3 -1 ≤ N ≥ 2(n+1)4 -1
2(128+1)3 -1 ≤ 8700471 ≥ 2(128+1)4 -1
4.293.377 ≤ 8.700.471 ≥ 553.845.761
Somit stimmt die beispielhafte Berechnung.
Wenn man nun davon ausgeht, dass sich die gesuchten Daten nicht direkt
im Knoten des Baumes befinden, sondern dessen Referenzen, muss noch
ein Seitenzugriff zur Baumhöhe dazu-addiert werden. Damit erhält man
5 Seitenzugriffe. Wie in der Einleitung beschrieben, könnte man mit Zugriffszeiten von 10 Millisekunden rechnen, dabei würde die beispielhafte
Suche nach genau einem Telefonbucheintrag 50 Millisekunden dauern.
13
Kapitel 4
B-Baum-Tool
4.1
4.1.1
Analytische Vorbereitung
Ziel
Ziel dieser Arbeit ist es, ein webbasiertes Tool zu erstellen, welches für
den universitären Einsatz verwendet werden kann. Im speziellen soll es
zum Lernerfolg der Studierenden beitragen, indem die Funktionsweisen
und Algorithmen interaktiv erklärt, und nachvollziehbar dargestellt werden. Dabei soll jeder einzelne Schritt veranschaulicht werden. Zudem
können verschiedene Parameter, wie beispielsweise der Verzweigungsgrad (abhängig von der Ordnung des Baumes) eingestellt werden. Des
weiteren werden vom Tool ganze Bäume nach ausgewählten Kriterien
eigenständig generiert. Lehrreiche Beispielbäume können vom Administrator neu hinzugefügt, und vom Anwender nach Belieben abgerufen
werden. Zur Unterstützung all dieser Funktionen werden Technologien
ausgenützt, welche zur Usability und User-Experience beitragen. Dabei
soll eine intuitive Bedienung erreicht werden, die das Benützen des Tool
als Erlebnis abrundet.
4.1.2
Problemstellung
Es muss ein Konsens zwischen den B-Baum-Algorithmen und der grafischen Darstellung gefunden werden. Zudem braucht die visuelle Ausgabe eine Schnittstelle für User-Interaktionen. Dazu wurde ein Prototyp
des B-Baums erstellt, und darauf aufbauend ein Einsatz von Canvas,
SVG, und reinem HTML ausgiebig miteinander verglichen. Auch sollen
keine langen, und unnötigen Wartezeiten für den Anwender entstehen.
Deshalb wäre es zudem vorteilhaft, eine Strategie für die grafische Ausgabe zu finden, um den Baumstatus nach durchgeführten Operationen
dauerhaft zu erhalten, ohne den gesamten Baum stets neu aufbauen zu
müssen. Sind dann erstmals die B-Baum-Algorithmen implementiert,
15
KAPITEL 4. B-BAUM-TOOL
stellt es eine weitere Herausforderung dar, diese dem Anwender Schritt
für Schritt animiert anzuzeigen.
4.1.3
Anforderungen
Unter Einbeziehung der angeführten Ziele und der daraus folgenden Problemanalyse ergeben sich folgende Anforderungen an die Umsetzung des
Systems:
• Es wird ein PHP-Server installiert, der dem Client das Programm
übermittelt. Gewisse administrative Einstellungen sind in einer
config.php am Server hinterlegt.
• Das Programm wird in JavaScript programmiert, und läuft am
Client-Computer.
• Der Baum wird dem Anwender durch geschickte Anordnung von
DIV-Elementen visuell dargestellt.
• Über die DOM-Schnittstelle ist ein ständiger Zugriff zwischen dem
dargestellten, und dem in Javascript gehaltenen Baum möglich.
• Ein Nachladen von Bäumen wird über AJAX realisiert, wobei diese
als JSON-Objekte übertragen werden.
• Für eine benutzerfreundliche Realisierung werden HTML- und CSSPatterns eingesetzt.
Die einzelnen Begriffe sind im Glossar (siehe 5, Seite 30) mit kurzer
Beschreibung aufgelistet.
4.2
Ausarbeitung
Es gibt genug Hilfsmittel wie Code-Snippets, Bibliotheken, Frameworks,
auch ganze Tools, die es einem einfacher machen, eine Web-App zu
erstellen, oder diese sogar großteils generieren zu lassen. Bei Frameworks und generierten Anwendungen leidet darunter jedoch meistens
die Qualität des Programms, und äußert sich in langen, und oft sinnlosen Ladezeiten für den User, sowie für den Programmierer in schwieriger
Änderbarkeit durch Abhängigkeiten, und erschwerter Portabilität durch
mögliche weitere Anforderungen an das System. Für Verbesserungen
müsste man den Code ständig anpassen. Um von Anfang an ein leichtgewichtiges, qualitatives Tool zu erstellen, wurde von einem Überladen
durch Hilfsmittel abgesehen, und das Programm “from scratch“ aufgebaut. Eine Übersicht der Systemarchitekur mit den verwendeten Komponenten ist in Abb. ... dargestellt.
16
KAPITEL 4. B-BAUM-TOOL
4.2.1
Server und Verzeichnisbaum
Es wird ein gewöhnlicher HTTP-Server mit PHP aufgesetzt. Ein langjährig
bewährter, und zugleich der meistgenutzte Webserver ist der frei erhältliche
“Apache“ [Net16]. Hervorragende Tutorials zum Einrichten eines eigenen Servers sind auf der offiziellen Webseite 1 zu finden. Als serverseitige Programmiersprache wird PHP installiert, wodurch sich zwei sehr
vorteilhafte Möglichkeiten ergeben. Zum einen können globale Einstellungen definiert werden, die alle Komponenten erhalten, welche an den
Client geschickt werden. Und zum anderen können Daten, wie beispielhafte B-Bäume per AJAX nach Belieben nachgeladen werden, ohne den
aktuellen Seitenstatus zu verändern. Details dazu sind in Abschnitt 4.3.1
ausführlich beschrieben. Der Verzeichnisbaum des B-Baum-Tools, und
ein erstmaliger Aufruf ist in folgender Abbildung dargestellt:
Dabei befinden sich in der config.php globale Einstellungsmöglichkeiten
für den Administrator. Dieser kann in der Datei durch Werteveränderung
das Aussehen und Verhalten des B-Baum-Tools nach Belieben anpassen.
Beispielsweise kann er Limits für den Grad des Baumes, oder Schlüsselgröße
angeben. Die grafische Darstellung wird durch Schriftart, Textgröße,
Breite eines Schlüsseleintrags, uvm. verändert. Diese Variablen werden
vor dem Versand zum Client durch PHP in den Quellcode von HTML,
JavaScript, und CSS geschrieben. Die inhaltliche Gestaltung wird nach
CSS-Standard in style.php definiert. Und das eigentliche Programm wird
mit JavaScript realisiert, welches als jscript.php in das HTML-Dokument
eingefügt ist. Für weitere Aufrufe während des Programmablaufs ist die
Datei ajax.php zuständig, die, wie der Name bereits erahnen lässt, angefragte Daten an den Client retour schickt.
1
http://httpd.apache.org/
17
KAPITEL 4. B-BAUM-TOOL
4.2.2
Der B-Baum in JavaScript
Ursprünglich war JavaScript als Skriptsprache angedacht, mit deren Hilfe man schnell und einfach kleinere Programme erstellen konnte, die
Browserinhalte manipulieren, und Benutzereingaben auswerten sollten.
Es stellten sich aber bald weitreichendere Möglichkeiten wie beispielsweise objektorientierte Einsätze heraus. Dabei wird gänzlich auf Definitionen von Klassen verzichtet, stattdessen existieren in JavaScript Eigenschaften und Funktionen als Objekte. Diese können wiederum selbst Eigenschaften und Funktion beinhalten. Eigene Objekte können demnach
als Funktionen definiert werden, wobei eine Instanz durch das key-word
“new“ erzeugt wird. Auf Eigenschaften eines Objekt kann anschließend
mit der Punkt-Notation zugegriffen werden. Nach diesem Prinzip wird
nun ein Schlüsselelement des B-Baum erstellt:
function key(value){
this.value = value;
this.parent = null;
this.left_key = null;
this.right_key = null;
this.left_child = null;
this.right_child = null;
}
Mit Hilfe des Key-words this können Eigenschaften der eigenen Objektreferenz zugeordnet werden. Wird aus key eine neue Instanz erzeugt,
behält diese den übergebenen Wert value. Alle weiteren Variablen stehen
anfangs als Platzhalter für spätere Referenzen auf andere keys. Will man
ein Schlüsselelement wie die Wurzel des B-Baums dauerhaft im Speicher
halten, wird es einer Variable zugeordnet:
var key_root = null;
key_root = new key(1);
console.log(key_root.value); // schreibt 1 zum Konsolen-Output
Dabei erhält key root obige Eigenschaften und für value den Wert 1.
Da für dieses Tool nicht mehrere B-Bäume gleichzeitig existieren, wird
key root in globalem Scope angelegt, und bildet zugleich den Startpunkt
für den B-Baum als mehrfach-verkettete Liste. So werden durch die
insert-Funktion nach und nach seine Nachbarelemente und Kindsknoten aufgebaut.
4.2.3
Die grafische Darstellung
Sobald ein B-Baum in JavaScript existiert, gibt es mehrere Möglichkeiten
diesen im Browser grafisch auszugeben. Einerseits können mit dem HTMLElement “Canvas“ Pixelgrafiken erstellt werden. Allerdings müssen die18
KAPITEL 4. B-BAUM-TOOL
se von JavaScript Bild für Bild neu gemalt werden. Am Beispiel des
B-Baums wäre es folglich notwendig, Koordinaten und jegliche visuelle Veränderungen in JavaScript zusätzlich zu speichern. Dennoch ist
diese Variante sehr schnell, da keine ständigen Zugriffe auf grafische
HTML-Elemente wie bei SVG notwendig sind. Mit SVG können dem
DOM vektorbasierende Grafiken hinzugefügt werden. Dabei wird das
HTML-Dokument um XML-tags erweitert. Der Vorteil liegt hier in der
Möglichkeit auf jedes Objekt direkt zugreifen zu können. Folgende kleine
Gegenüberstellung vergleicht beide Varianten:
Canvas
- zeichnet eine Pixelgrafik
- schnell bei komplexen Bildern
- behält kein Wissen über Inhalt
- Änderung erfordert neues Bild
SVG
- erstellt einzelne grafische Objekte
- Zeit je nach Objektanzahl
- Elemente bleiben erhalten
- Manipulation in Element angeben
An letztem Punkt ist erkennbar, dass Animationen und Transformationen in Canvas selbst in JavaScript umgesetzt werden müssen, wobei
SVG-Elemente durch eine Zusatzangabe innerhalb des Objekts einfach
manipuliert werden können. Aber den relevanten Unterschied, weshalb
SVG für das B-Baum-Tool geeigneter erscheint, ist die Möglichkeit für
jedes Element einen Event-Handler definieren zu können, wodurch beispielsweise ein Schlüsseleintrag per Mausklick für weitere Funktionalität
direkt ausgewählt werden kann.
Bei zunehmender Objektanzahl (bereits bei Ordnung 2, und Höhe 3)
erweist sich ein ständiger Zugriff auf SVG-Objekte als nicht sehr praktikabel und langsam. Denn will man nach strukturellen Verschiebungen
innerhalb des B-Baumes die aktuelle Position eines Objekts erhalten,
muss man für alle darauf ausgeführte Transformationen dessen Koordinatenänderungen selbst berechnen. Um diesem Umstand entgegenzuwirken, gibt es in JavaScript Libraries, welche Objektpositionen behalten
und updaten.
Als einfacher erwies sich der Einsatz von DIV-Elementen, welche in
einem Container innerhalb des HTML-Dokuments absolut positioniert
werden. Dabei kann bei Zugriff die genaue Position abgefragt, und gesetzt werden kann. Eine kleine Hürde stellt allerdings die fehlende
Möglichkeit dar, einfache grafische Elemente wie schräge Linien darzustellen, die beispielsweise Eltern- und Kindknoten miteinander verbinden. Mit folgender Funktion kann dieser Mangel behoben werden:
function draw_line(x1,y1,x2,y2){
var length = Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
var angle = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
var transform = ’rotate(’+angle+’deg)’;
19
KAPITEL 4. B-BAUM-TOOL
var top = 0;
var left = 0;
if (y2 < y1){
top = y2;
left = x1;
}
else{
top = y1;
left = x1;
}
...
var line = document.createElement("div");
line.style = "position: absolute; transform: "+transform+";
width: "+length+"px; left: "+left+"px; top: "+top+"px;";
document.getElementById("drawing").appendChild(line);
}
Dabei werden die Start-, und Ziel-Koordinaten der zu zeichnenden Linie
benötigt, wodurch sich daraus die Länge, sowie der Neigungswinkel berechnen lassen. Zur gezielten absoluten Positionierung werden dann, der
Linienorientierung entsprechend, die Offsets vom Container-Nullpunkt
top und left bestimmt. So kann die Linie als neues DIV-Element erzeugt,
und mit den berechneten Werten in den Container (hier als “drawing“
benannt) eingefügt werden. Wird nun eine Möglichkeit gefunden, einfache Transformationen und Animationen auf diese Elemente darzustellen,
kann auch auf den Einsatz von SVG gänzlich verzichtet werden.
4.2.4
Transformationen und Animationen
Die grafische Umsetzung der einzelnen Schlüssel könnte, wie folgt, aufgebaut werden: Dabei steht der Parameter id für den Schlüsseleintrag
selbst, und x sowie y für dessen Koordinaten. Damit wird ein Rechteck
kreiert, und dem bereits bekannten Container “drawing“ hinzugefügt.
function create_rectangle(id,x,y){
var rect = document.createElement("div");
rect.id = id+"_rectangle";
rect.className = "rectangle";
rect.style = "position: absolute; left: "+x+"px; top:
"+y+"px;";
rect.innerHTML = id;
rect.onclick = function(){show_tooltip(this);};
document.getElementById("drawing").appendChild(rect);
}
Transformationen darauf wie Translationen (Objektverschiebungen) gestalten sich noch relativ einfach. Dazu werden die Offsets top und left
20
KAPITEL 4. B-BAUM-TOOL
von einem Objekt abgefragt, und mit angepassten Werten wieder zugefügt:
function move_object(id, x_offset, y_offset){
var element = document.getElementById(id);
var x = element.offsetLeft;
var y = element.offsetTop;
element.style.left = (x + x_offset) + "px";
element.style.top = (y + y_offset) + "px";
}
Schwieriger gestaltet es sich, solch eine Translation zu animieren. Von anderen Programmiersprachen ist bereits die sleep-Funktion bekannt. Damit ließe sich eine Verschiebung einfach durch eine Schleife durchführen,
wo pro Schritt die Position verändert, und anschließend bis zum Folgeschritt eine Zeit lang “geschlafen“ wird. Genauer gesagt, wird dadurch
die Programmausführung für eine bestimmte Zeit an andere Threads
bzw. Prozesse abgegeben. In JavaScript gibt es eine solche Funktion
nicht. Eine ähnliche Möglichkeit wäre der Einsatz des busy-waitingPatterns, wodurch der Prozess für eine bestimmte Zeit beschäftigt wird,
bevor im Programmablauf (nächster Translationsschritt) weitergemacht
wird. Das wäre aber nicht sehr benutzerfreundlich, da der Anwender
während laufender Animationen keine Interaktionsmöglichkeit mehr hat.
Ein weiterer Ansatz ist das Setzen von Timeouts (setTimeout und setInterval ), die nach Ablauf gewählter Zeitspannen eine bestimmte Funktion aufrufen. Solch eine Funktion könnte je einen Teilschritt für eine
Objektverschiebung umsetzen. Man teilt dabei die Translation durch
die gewünschte Dauer in Einzelschritte, und setzt diese dann in einer
Schleife als Timeouts ab. Bis eine Timeout-Funktion aktiv wird, setzt
das Programm seinen Ablauf fort. Problematisch wird diese Variante, sobald Objekte verschoben werden sollen, die voneinander abhängig
sind. Beispielsweise ist bei Knotenüberläufen, und Knotenunterläufen eine rekursive Umstrukturierung von Teilbäumen möglich. Nur kann man
bei deren Behandlungen nicht davon ausgehen, dass vorhergehende Verschiebungen bereits abgeschlossen sind. Man denke an einen Schlüssel,
der in einen Knoten eingefügt werden soll, obwohl dieser möglicherweise
noch verschoben wird. Hinzu kommt noch, dass populäre Browser eigene
Rendering-Engines haben, welche Manipulationen auf HTML-Elemente
in unvorhersehbaren zeitlichen Abständen behandeln. So kann es vorkommen, dass eine Schlüsselposition für eine Translation bestimmt wird,
obwohl die Rendering-Engine die vorhergehende Verschiebung noch nicht
durchgeführt hat.
21
KAPITEL 4. B-BAUM-TOOL
Browserkompatibilität
Web-Browser können auf grafische Inhalte sehr unterschiedlich reagieren. Alleine bei der Umsetzung von Transformationen zeigten sich große
Unterschiede. Um diese Anwendung für gängige Browser kompatibel zu
machen mussten ein paar Anpassungen vorgenommen werden. Für eine
Rotation wurden beispielsweise diese Befehle zum CSS hinzugefügt.
-moz-transform: rotate(30deg);
-ms-transform: rotate(30deg);
-o-transform: rotate(30deg);
-webkit-transform: rotate(30deg);
transform: rotate(30deg);
Der eingesetzte Browser führt dabei den zuletzt erkannten Befehl aus,
weshalb spezielle Befehle zuerst genannt werden.
4.3
Benutzerschnittstelle (GUI)
Neben den Hauptoperationen für Bäume search, insert, und delete, denen bereits ein ausführliches eigenes Kapitel gewidmet wurde, werden
hier noch weitere hilfreiche Funktionen beschrieben, welche den User
in der Anwendung unterstützen. Generell wird großer Wert auf Benutzerfreundlichkeit, und im speziellen auf einfache und intuitive Bedienung gelegt. Dafür erhält auch jeder Schlüssel ein onclick-Event, welches direkt daneben ein kleines Popup öffnet, wo beispielsweise ein direktes Löschen dieses Schlüssels möglich ist (siehe 4.2.4, Seite 20). Hier
ein kurzes, vereinfachtes Beispiel, wie solch ein Popup bzw. Tooltip erstellt werden kann: Der Übergabeparameter rect stellt das zugehörige
Schlüsselelement dar.
function show_tooltip(rect){
var x = rect.offsetLeft +rect_width;
var y = rect.offsetTop - 20;
var tooltip = document.createElement("div");
tooltip.className = "tooltip";
tooltip.style = "position: absolute; left: "+x+"px; top:
"+y+"px;";
document.getElementById("drawing").appendChild(tooltip);
// add div for closing on click
var close = document.createElement("div");
close.className = "close";
close.style = "position: relative;";
close.innerHTML = "X";
close.onclick =
function(){document.getElementById("drawing").removeChild(tooltip);};
22
KAPITEL 4. B-BAUM-TOOL
tooltip.appendChild(close);
// add div for deletion
var del = document.createElement("div");
del.className = "del";
del.style = "position: relative;";
del.innerHTML = "<img src=’./img/delete.png’
onclick=’delete(rect.innerHTML);’
style=’width:30px;padding:5px;’> Löschen !";
tooltip.appendChild(del);
}
Der Tooltip als Popup bekommt in diesem Beispiel zwei Kindelemente zu
seinem Strukturbaum dazu. Das Div-Element close erhält die Referenz
des gerade erstellten Tooltips, wodurch dieses bei Klick entfernt werden
kann. Das Div-Element del hingegen, führt bei Klick die Löschoperation
für diesen Schlüssel aus.
Als weiteres Beispiel werden Hover-Effekte eingesetzt, sobald sich der Fokus auf einem Element des B-Baums befindet, und zudem auch HighlightEffekte bei Animationen verwendet. Diese werden von verschiedenen
Abschnitten der Baumoperationen aufgerufen, und setzen dabei einen
Timeout ab:
function highlight_rectangle(k){
var rectangle = document.getElementById(k.value+"_rectangle");
setTimeout(function(){rectangle.style.backgroundColor =
"snow";}, 200);
}
4.3.1
Laden von Beispielbäumen
Mit PHP als serverseitige Programmiersprache ist es für den Client
möglich, zum aktuellen Seitenstatus gewisse Daten nachzufordern, und
per JavaScript einzubinden. Damit können beispielhafte B-Bäume nach
Belieben in das Tool geladen werden. Es wird dabei von der AJAXTechnologie Gebrauch gemacht, wobei die Datenübertragung vereinfacht
mit JSON-Objekte realisiert wird. Über eine Schleife in index.php werden alle Beispielbäume aus dem Verzeichnis tree examples ausgelesen,
und einem Auswahlmenü als Optionen hinzugefügt.
<?php
$tree_array = scandir("./tree_examples/");
$tree_array = array_diff($tree_array,array("..","."));
?>
<div id="div_example_tree">
Beispielbaum laden
<select id="tree_examples" onchange="tree_example_load();">
23
KAPITEL 4. B-BAUM-TOOL
<option disabled selected>Beispielb&aumlume</option>
<?php
foreach($tree_array as $tree){
echo "<option>".$tree."</option>";
}
?>
</select>
</div>
Wählt man eine Option aus, wird tree example load() ausgeführt. Die
Abarbeitung kann in drei Teile zusammengefasst werden. Zuerst wird
der ausgewählte Baum per AJAX ins Programm geladen. Das dadurch
erhaltene serialisierte JSON-Objekt, wird dann in ein mehrdimensionales Array gespeichert. Mit einer verschachtelten Schleife kann dann jedes Element als neuer key dem B-Baum in JavaScript zugeführt werden.
Zur grafischen Ausgabe wird anschließend jede Höhe, beginnend von den
Blättern, zentriert, und mittig übereinander angeordnet. Zur vereinfachten Darstellung werden hier manche Abschnitte im Code-Auszug in sehr
reduziertem Pseudocode angeführt:
function tree_example_load(){
...
var select = document.getElementById("tree_examples");
var option = select.options[select.selectedIndex].value;
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST","ajax.php",false);
xmlhttp.send("tree_example="+option);
var tree = JSON.parse(xmlhttp.responseText);
...
...
for(i=0; i< tree.length ;i++){
for(x=0; x< tree[i].length ;x++){
for(y=0; y< tree[i][x].length ;y++){
insert_key(tree[i][x][y]);
draw_key(tree[i][x][y]);
}
}
}
...
...
var leaf_left = leftest_key();
var leaf_right = rightest_key();
var center_point =
(document.getElementById(leaf_left.value+"_rectangle").offsetLeft
+
document.getElementById(leaf_right.value+"_rectangle").offsetLeft)
/2;
for(i=0; i< tree.length;i++){
24
KAPITEL 4. B-BAUM-TOOL
var last_x_index = tree[i].length-1;
var last_y_index = tree[i][last_x_index].length-1;
var parent_center_point =
(document.getElementById(tree[i][0][0]+"_rectangle").offsetLeft
+
document.getElementById(tree[i][last_x_index][last_y_index]+
"_rectangle").offsetLeft) /2
var offset_x = center_point - parent_center_point;
for(x=0; x< tree[i].length ;x++){
for(y=0; y< tree[i][x].length ;y++){
var element_offset = offset_x +
document.getElementById(tree[i][x][y]+"_rectangle").offsetLeft;
rectangle_move(parseInt(tree[i][x][y]),
element_offset);
}
}
}
...
}
Die Indizes im B-Baum-Array tree[i ][x ][y] stehen für:
i als jeweilige Höhe, x als Knoten einer Höhe, und y als einzelne keys.
Damit die Beispielbäume vom Programm fehlerfrei geladen werden können,
müssen sie gewisse Kriterien erfüllen. Genauer gesagt, wird ein spezielles
Format vereinbart, indem einzelne Bäume als Dateien vorliegen sollen.
Dazu gibt folgender Eintrag in der Datei README.txt auskunft:
every file in the directory "tree_examples" holds an b-tree.
the file needs to be built with following rules:
first line has number n (minimum number of elements in node).
every other line contains keys of same tree-height.
lines have order from root to leafs.
separator in node is ",".
separator between nodes is "+".
an example: n=1 (binary-tree)
1
8,16
4+12+19,33
1,2+6+10+14+18+20+44
4.3.2
Erstellen eines neuen Baumes
Hier hat ein User die Möglichkeit die Ordnung des gewünschten Baumes
in einem Auswahlfeld zu wählen. Daraufhin wird er zur Eingabe des ersten Schlüssels (Wurzel) aufgefordert, mit dem der Baum in JavaScript
25
KAPITEL 4. B-BAUM-TOOL
initialisiert wird. Die Datei index.php stellt die möglichen Ordnungszahlen nach der Limitation des Administrators als Optionen dar:
<div id="div_new_tree">
Neuen B-Baum der Ordnung
<select id="select_min_keys" onchange="tree_build()">
<option disabled selected>n</option>
<?php
for($i=1; $i<=$n_limit; $i++){
echo "<option>".$i."</option>";
}
?>
</select>
erstellen
</div>
Bei Auswahl einer Option wird tree build() ausgeführt. Diese Funktion
fragt den Benutzer nach dem ersten Schlüssel, mit dem der B-Baum begonnen werden soll. Mit diesem Wurzelelement wird die verkettete Liste
des B-Baumes begonnen, und anschließend grafisch erstellt.
function tree_build(){
var value = prompt("Mit welchem Schlüssel wollen Sie den
B-Baum beginnen?");
if(!check_input_number(value)){
return 0;
}
var select = document.getElementById("select_min_keys");
n = select.options[select.selectedIndex].value;
select.selectedIndex = 0;
document.getElementById("drawing_title").innerHTML = "B-Baum
der Ordnung "+n;
document.getElementById("drawing").innerHTML="";
key_root = new key(value);
create_rectangle(value,svg_width/2,rect_width*2);
}
Durch check input number() wird der einzufügende Schlüssel dahingehend überprüft, ob er einem gültigen Wert entspricht. Ist dies nicht der
Fall, wird dem Anwender eine entsprechende Meldung angezeigt, und
die fehlerhafte Eingabe entfernt.
function check_input_number(value){
if(value > max_input_number){
status_write("Es sind nur Zahlen bis "+max_input_number+"
erlaubt. ");
26
KAPITEL 4. B-BAUM-TOOL
document.getElementById("input_key").value = "";
return false;
}
else if(isNaN(value)){
status_write(value+" ist keine Zahl. ");
document.getElementById("input_key").value = "";
return false;
}
else if(value < 0){
status_write("Bitte einen positiven Wert eingeben!");
document.getElementById("input_key").value = "";
return false;
}
return true;
}
27
Kapitel 5
Auswertung und Ausblick
Im direkten Vergleich mit Canvas und SVG wurden bereits einige Vorteile für den bevorzugten Einsatz mit SVG hervorgehoben. In weiterer Gegenüberstellung zeigte sich, dass alle benötigten Grafiken, Transformationen, und Animationen auch mit Hilfe von Div-Elementen umgesetzt
werden können. Dazu benötigte es nur ein paar kleine Tricks, und Anpassungen. Und in Folge ergaben sich sogar weitere Vorteile. Bei SVG ist
der Schlüsseleintrag zwingend ein eigenständiges Textelement. Wird der
umschließende Container (grafische Darstellung des Schlüssels als Rechteck) bewegt, muss zusätzlich die selbe Operation auf das Textelement
ausgeführt werden. Mit Div-Containern hingegen kann der Schlüsselwert
als darin stehender Text (innerHTML) eingebunden werden, wodurch
keine weitere Verschiebung notwendig wird.
In dieser Arbeit wurde besonders Wert darauf gelegt, dass ein qualitatives Tool entsteht, ohne es mit fremden Code überladen zu müssen.
Es seien aber durchaus Bibliotheken und Frameworks zu erwähnen, die
einem Programmierer die Arbeit sehr erleichtern können, und zudem
auch visuell ansprechend sind. Als Hilfe könnte man beispielsweise das
bekannte Framework “Bootstrap“ einsetzen, welches hauptsächlich Gestaltungsvorlagen für die Benutzeroberfläche liefert. Speziell für grafische Strukturen eignet sich die JavaScipt-Bibliothek “D3.js“, welches
die Schnittstelle zum DOM stellt. So lassen sich Daten in JavaScript
eindrucksvoll in grafische Bäume verwandeln.
Als Erweiterung zum B-Baum-Tool könnte man die Funktionalität hinzufügen, einen neu erstellten Baum speichern zu können. Dieser würde
nach den Vorgaben , wie in 4.3.1 beschrieben, zu den Beispielbäumen
hinzugefügt werden. Sollte dies nur für einen Administrator möglich sein,
wäre auch eine zusätzliche Authentifizierung notwendig.
29
Glossar
Technologien
Beschreibung
AJAX
Asynchronous JavaScript and XML
Datenübertragung zwischen Browser und Server ohne Page-Reload.
Canvas
Englisch für “Leinwand“. Ein HTML-Element.
Aus JavaScript erstellte Pixelgrafik.
CSS
Cascading Style Sheets
Gestaltung der Elemente des HTML-Dokuments.
DOM
Document Object Model
Schnittstelle für Zugriff auf Knoten des HTML-Strukturbaumes.
HTML
Hypertext Markup Language
Textbasierte Auszeichnungssprache zur Strukturierung.
JavaScript
Ursprünglich LiveScript bei Netscape Navigator
Clientbasierte (hauptsächlich) Skriptsprache.
Behandelt DOM-Manipulationen, AJAX, User-Interaktionen, etc.
JSON
JavaScript Object Notation
Textbasiertes Format zur Übertragung von Daten.
Serialisierung von Objekten möglich.
PHP
PHP Hypertext Preprocessor
Serverseitige Programmiersprache.
SVG
Scalable Vector Graphics
Grafiken, die sich aus primitiven geometrischen Formen aufbaut.
30
Literaturverzeichnis
[Bay72] R. Bayer: Symmetric binary B-Trees: Data structure and
maintenance algorithms, Acta Informatica, volume 1(4),
(1972), pages 290–306, URL http://dx.doi.org/10.1007/
BF00289509.
[BZ13]
K. Bauknecht and C. Zehnder: Grundlagen für den
Informatikeinsatz, XLeitfäden der Informatik, Vieweg+Teubner Verlag, 2013, URL https://books.google.
at/books?id=ICPwBgAAQBAJ.
[Com79] D. Comer: Ubiquitous B-Tree, ACM Comput. Surv., volume 11(2), (1979), pages 121–137, URL http://doi.acm.org/
10.1145/356770.356776.
[KE09]
A. Kemper and A. Eickler: Datenbanksysteme: eine
Einführung, Oldenbourg, 2009, URL https://books.
google.at/books?id=\_lgBQAAACAAJ.
[Net16] Netcraft: Marktanteile Webserver, Abgerufen am 10.05.2016,
URL
https://news.netcraft.com/archives/category/
web-server-survey/.
[SA16]
Statistik-Austria: Einwohnerzahl Österreichs, Abgerufen am
21.09.2016, URL http://www.statistik-austria.at/.
[Sch13]
M.
Schneider:
Implementierungskonzepte
für
Datenbanksysteme, Springer Berlin Heidelberg, 2013, URL
https://books.google.at/books?id=DYLyBQAAQBAJ.
31
Herunterladen