Informatik/Jahrgangsstufe Q/Klausuren/Themensortiert/03 Baeume.pdf
Informatik/Jahrgangsstufe Q/Klausuren/Themensortiert/03 Baeume.pdf
Informatik/Jahrgangsstufe Q/Klausuren/Themensortiert/03 Baeume.pdf
Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.
YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.
Aufgabe 1: Begründen oder widerlegen Sie die folgenden Aussagen:<br />
(1) Jeder Knoten eines Binärbaums hat zwei nichtleere Teilbäume<br />
(2) Beim Löschen eines Elements aus einem Binärbaum ändert sich die Höhe<br />
dieses Baumes.<br />
(3) Beim Einfügen eines Elements in einen Binärbaum kann die Höhe dieses<br />
Baumes unverändert bleiben.<br />
(4) Die Inorder-Ausgabe eines Suchbaums ist immer Sortiert.<br />
(5) Ein Binärbaum der Höhe 4 besitzt höchstens 15 Knoten.<br />
(6) Ein Binärbaum mit der Höhe 5 besitzt mindestens 7 Knoten.
Aufgabe 1: Bäume − Binärbaume – Suchbäume<br />
Im Unterricht haben wir drei verschiedene Gruppen von Bäumen kennen<br />
gelernt: Gruppe A: Suchbäume<br />
Gruppe B: Binärbäume<br />
Gruppe C: Bäume<br />
Gruppe D: keine Bäume (Graphen)<br />
Diese stehen in einem rechts veranschaulichten Hierarchieverhältnis.<br />
(D) Graphen<br />
(C) Bäume<br />
(B) Binärbäume<br />
(A) Suchbäume<br />
a) Ordnen Sie jede der nachfolgenden Strukturen einer dieser Gruppen zu und begründen Sie<br />
kurz, warum die Struktur zur angegebenen Hierarchie gehört.<br />
(1) (2) C<br />
(3)<br />
B<br />
F<br />
E<br />
P<br />
(4)<br />
10<br />
(5) 04.<strong>03</strong>.2002<br />
6<br />
9<br />
19.09.2001<br />
25.05.2002<br />
4<br />
5 7 8<br />
08.07.2001<br />
24.12.2001<br />
01.10.20<strong>03</strong><br />
b) Zeichnen Sie den Graphen eines zu Anfang leeren Suchbaumes, in den nacheinander die<br />
folgenden Elemente eingefügt werden (Eine Zeichnung reicht aus!):<br />
3, 1, 7, 2, 12, 6, 4, 10, 8, 5, 11, 9<br />
c) Geben Sie zum nachfolgenden Binärbaum die Preorder-, Inorder- und Postorder-<br />
Traversierung an.<br />
oder<br />
Binärbäumen<br />
Spass<br />
Traversieren<br />
von<br />
riesen<br />
das<br />
macht<br />
d) Löschen Sie nacheinander die folgenden Elemente aus dem rechts<br />
abgebildeten Suchbaum.<br />
9, 8, 7, 3, 6,<br />
Halten Sie sich dabei exakt an das im Unterricht entwickelte<br />
Verfahren SuchLöschen (Anlage I). Zeichnen Sie nach jeder<br />
Löschaktion den Graphen des daraus resultierenden Baumes.<br />
(Insgesamt sind also 5 Bäume zu zeichnen!)<br />
einen<br />
e) Entwickeln Sie eine Funktion, welche die Anzahl der Blätter eines Baumes berechnet.<br />
Verwenden Sie wann immer möglich die Binbaum-Methoden (Anlage II).<br />
function TBinBaum.Blattanzahl: integer;<br />
1<br />
2<br />
3<br />
5<br />
6<br />
8<br />
7 10<br />
4 9 11
Aufgabe 3: Zeichnen Sie den Graphen eines zu Anfang leeren Suchbaumes, in den<br />
nacheinander die folgenden Elemente eingefügt werden (Eine Zeichnung reicht<br />
aus!):<br />
3, 1, 7, 2, 12, 6, 4, 10, 8, 5, 11, 9<br />
Aufgabe 4: Geben Sie zum nachfolgenden Binärbaum die Preorder-, Inorder- und Postorder-<br />
Traversierung an.<br />
der<br />
Freitag<br />
ist<br />
ein<br />
guter<br />
Tag<br />
zum<br />
Klausur<br />
schreiben<br />
Aufgabe 5: Löschen Sie nacheinander die folgenden Elemente aus dem rechts abgebildeten<br />
Suchbaum.<br />
9, 8, 7, 3, 6,<br />
6<br />
Halten Sie sich dabei exakt an das im Unterricht<br />
3<br />
entwickelte Verfahren SuchLöschen (Anlage I). Zeichnen<br />
Sie nach jeder Löschaktion den Graphen des daraus<br />
2 5<br />
resultierenden Baumes. (Insgesamt sind also 5 Bäume zu<br />
zeichnen!)<br />
1<br />
8<br />
7 10<br />
4 9 11<br />
Aufgabe 6: Entwickeln Sie eine Funktion, welche die Anzahl der Knoten eines Baumes<br />
zählt, die genau einen nichtleeren Teilbaum besitzen. Die Funktion angewendet<br />
auf den Baum aus Aufgabe 5 würde als Ergebnis die Zahl 2 liefern, da nur die<br />
Knoten 2 und 5 genau einen nichtleeren Teilbaum besitzen.<br />
Verwenden Sie wann immer möglich die Binbaum-Methoden (Anlage II).<br />
function TBinBaum.HalbbaumAnzahl: integer;<br />
Aufgabe 7: Die Inhalte eines Suchbaums sollen in einen File geschrieben werden.<br />
a) Begründen Sie, warum eine Methode SaveToFile, welche in der Klasse<br />
TSuchbaum deklariert würde, nur Textdateien erzeugen könnte.<br />
b) Begründen Sie, warum eine Methode LoadFromFile in der Klasse<br />
TSuchbaum sogar unsinnig wäre.
Aufgabe 1:<br />
Binärbäume − Suchbäume<br />
Hinweis: Sämtliche Abbildungen finden Sie im Anhang I.<br />
a) Begründen oder widerlegen Sie:<br />
(1) Der Baum aus ABBILDUNG 1 gehört zur Gruppe der Suchbäume.<br />
(2) Der Baum aus ABBILDUNG 2 ist kein Suchbaum.<br />
(3) Ein Binärbaum der Höhe 3 hat höchstens sechs Elemente.<br />
(4) Das Suchen in einem Suchbaum mit 7 Elementen benötigt höchstens drei<br />
Vergleiche.<br />
(5) Die InOrder Ausgabe des Baums aus ABBILDUNG 2 lautet:<br />
Karl, Emil, Otto, Bert, Fritz, Josef, Paul, Doris, Gerd, Moritz<br />
(6) Der Baum aus ABBILDUNG 3 könnte eine Datenstruktur für das Expertensystem<br />
„Tiereraten“ sein.<br />
(7) Beim Expertensystem „Tiereraten“ müssen die Baumelemente in PreOrder-<br />
Notation in einem File abgelegt werden, damit die Rekonstruktion der<br />
Wissensstruktur möglich ist.<br />
b) Im Unterricht haben Sie Algorithmen kennen gelernt, mit Hilfe derer Elemente in<br />
Suchbäume eingefügt und Elemente aus Suchbäumen gelöscht werden können.<br />
(1) Fügen Sie in einen anfangs leeren Suchbaum nacheinander folgende Elemente ein.<br />
30, 10, 20, 40, 50, 45, 35, 25, 15, 5<br />
Eine Zeichnung genügt.<br />
(2) Löschen Sie in dem so entstandenen Baum nacheinander die folgenden Elemente.<br />
25, 50, 30<br />
Zeichnen Sie nach jeder Löschoperation den resultierenden Suchbaum.<br />
(3) Geben Sie zu Ihrem Suchbaum aus Teilaufgabe (1) die zugehörige PostOrder-<br />
Ausgabe an.<br />
(4) Die PreOrderAusgabe eines Suchbaums lautet:<br />
8, 4, 0, 2, 6, 14, 10, 12, 18, 16, 20<br />
Zeichnen Sie den zugehörigen Suchbaum.<br />
c) Gegeben sei die folgende Datenstruktur eines Binärbaums über dem Inhalt integer.<br />
type TIntBinBaum = class(TBinBaum)<br />
public<br />
Wurzelinhalt: integer;<br />
constructor Create(w: Integer);<br />
function WurzelinhaltToString: string; override;<br />
end;<br />
(1) Implementieren Sie die Methode WurzelinhaltToString.<br />
(2) Erweitern Sie die Klasse TIntBinBaum um eine Methode, welche das größte<br />
Element des Baums bestimmt.<br />
Achtung: Es handelt sich hier nicht um einen Suchbaum!<br />
(3) Erweitern Sie nun die Klasse TIntBinBaum um eine Methode<br />
procedure StrukturierteAusgabe(Memo: TMemo);<br />
die den Baum „strukturiert“ auf einem Memofeld ausgibt. ABBILDUNG 4 zeigt, wie<br />
dies gemeint ist.
Anlage I:<br />
6<br />
3<br />
9<br />
1<br />
4<br />
7<br />
1 0<br />
0<br />
2<br />
5<br />
8<br />
ABBILDUNG 1: SUCHBAUM ?<br />
Karl<br />
Emil<br />
Otto<br />
Bert<br />
Fritz<br />
Josef<br />
Paul<br />
Doris<br />
Gerd<br />
Moritz<br />
ABBILDUNG 2: SUCHBAUM ?<br />
Kann<br />
sprechen?<br />
Lebt im<br />
Käfig?<br />
Kann<br />
miauen?<br />
Papagei<br />
Katze<br />
Kann<br />
bellen?<br />
Hund<br />
ABBILDUNG 3: WISSENSSTRUKTUR BEIM „TIERERATEN“ ?<br />
ABBILDUNG 4: STRUKTURIERTE AUSGABE IM MEMO (UM 90° LINKS GEDREHT)
Aufgabe 1:<br />
Binärbäume<br />
Im Morsealphabet ist jeder Buchstabe durch eine Aneinanderreihung von Punkten (·) und<br />
Strichen (-) codiert. Die Codierung der Buchstaben lautet wie folgt:<br />
Morsealphabet<br />
A ·- B -·· C -·-· D -··· E · F ··-· G --· H ···· I ·· J ·--- K -·- L ·-·· M –-<br />
N -· O --- P ·--· Q --·- R ·-· S ··· T - U ··- V ···- W ·-- X -··- Y -·-- Z --··<br />
Eine Möglichkeit, den Morse-Code zu verwalten, ist die Speicherung der Codes in einem<br />
Binärbaum. Der Morsepunkt bewirkt dabei eine Verzweigung nach<br />
links, der Morsestrich eine Verzweigung nach rechts. In jedem<br />
Knoten des Baumes steht der Buchstabe, der durch den im Baum<br />
vorausgegangenen Punkt-Strich-Code repräsentiert wird.<br />
a) Stelle den Morsecode wie oben beschrieben als Baum dar. Der<br />
Pfad zum Buchstaben R müsste in deinem Baum wie rechts<br />
abgebildet aussehen.<br />
Solltest du keinen Baum erstellen können, so erhältst du diese<br />
Lösung von dem Aufsicht führenden Lehrer.<br />
b) Übersetze mit Hilfe des in a) entwickelten Baumes den folgenden<br />
Morsetext. Die |-Zeichen trennen die einzelnen Buchstaben.<br />
-|---|·-··|·-··|·|-·-|·-··|·-|··-|···|··-|·-·<br />
...<br />
R<br />
−<br />
•<br />
•<br />
...<br />
...<br />
c) Beschreibe, wie man algorithmisch vorgeht, wenn man einen Text mit Hilfe des Baumes<br />
übersetzen möchte. Es ist kein exakter Algorithmus gefordert!<br />
d) Wieso ist eine Trennung der einzelnen Buchstaben (hier durch ein |-Zeichen)<br />
erforderlich? Begründe mit Hilfe des Baums aus Aufgabenteil a).<br />
Für die Umsetzung dieser Speichermöglichkeit in DELPHI bietet sich das folgende<br />
interface an:<br />
uses BinBaum;<br />
type TMorsebaum = class(TBinBaum)<br />
public<br />
Inhalt: char;<br />
constructor Create(c: char);<br />
function WurzelinhaltToString: string; override;<br />
function Einlesen: TMorsebaum;<br />
function MorsetextToKlartext(Morse: string): char;<br />
function KlartextToMorsetext(Klar: char): string;<br />
end;<br />
e) Implementiere die folgenden Methoden dieses Datentyps:<br />
(i) constructor Create(c: char);<br />
Erzeugt ein Blatt dessen Knoteninhalt der Buchstabe c ist.<br />
(ii) function WurzelinhaltToString: string; override;<br />
Liefert den Knoteninhalt als string.<br />
(iii) function MorsetextToKlartext(Morse: string): char;<br />
Gibt zu einem Zeichen in Morsecode (Morse) den entsprechenden Buchstaben<br />
im Klartext zurück.<br />
MorsetextToKlartext(´··-·´) liefert den Buchstaben ´F´.<br />
(iv) ... siehe nächste Seite ...
(iv) function KlartextToMorsetext(Klar: char): string;<br />
Sucht im Baum den Buchstaben Klar und gibt den entsprechenden Morsetext<br />
zurück.<br />
KlartextToMorsetext(´V´) liefert den Morsecode ´···−´.<br />
Hinweis: Am besten ist diese Aufgabe zu lösen, wenn du dir eine<br />
Hilfsfunktion/-prozedur schreibst, welche rekursiv alle möglichen<br />
Morsecodes durchläuft.<br />
f) Eine andere Möglichkeit der Verwaltung der Morsecodes wäre durch ein Array gegeben:<br />
const CodeTabelle: array['A'..'Z'] of string[4]=<br />
('·-','-··','-·-·','-···','·','··-·',<br />
'--·','····','··','·---','-·-','·-··',<br />
'--','-·','---','·--·','--·-','·-·',<br />
'···','-','··-','···-','·--','-··-','-·--','--··');<br />
Welche Nachteile hat diese Art der Verwaltung gegenüber der Verwaltung in Form eines<br />
Baums? Welche Vorteile ergeben sich aus dieser Art der Speicherung?
ellt?<br />
Aufgabe 3: Aus dem Unterricht kennen Sie den Datentyp des Binärbaums (Anlage I).<br />
beißt?<br />
miaut?<br />
Hund Löwe Katze Fisch<br />
a) Beschreiben Sie die wesentlichen Merkmale dieser Datenstruktur.<br />
b) Der Datentyp wird um folgende Methode erweitert:<br />
function TBinBaum.wasBerechneIch: string;<br />
begin<br />
if leer<br />
then result:= ´´<br />
else result:= LinkerTeilbaum.wasBerechneIch +<br />
WurzelinhaltToString +<br />
RechterTeilbaum.wasBerechneIch;<br />
end;<br />
Welches Funktionsergebnis wird für den links abgebildeten Baum<br />
zurückgegeben?<br />
c) Schreiben Sie eine Methode für den Datentyp TBinBaum, welche die Anzahl<br />
der Tiere in einer Wissensstruktur berechnet. Hinweis: In den Blättern eines<br />
Wissensbaums standen stets Tiernamen.<br />
d) Erläutern und formulieren Sie einen Algorithmus, welcher die Inhalte eines<br />
Binärbaums zeilenweise ausgibt. Eine exakte Implementierung ist hier nicht<br />
gefordert. Hinweis: Sie dürfen auf bereits bekannte Datenstrukturen (Lineare<br />
Liste, Stapel, Schlange, etc.) zurückgreifen.
Aufgabe 1: Binärbäume − hier: Termbäume<br />
In der fünften Klasse lernt man, nach welchen Rechengesetzen Terme berechnet werden:<br />
Klammer- vor Punkt- und Punkt- vor Strichrechnung. Zur Veranschaulichung werden<br />
sogenannte Rechenbäume oder Termbäume benutzt, welche die Reihenfolge der Berechnung<br />
veranschaulichen. Zwei Beispiele:<br />
Beispiel 1: 2 + 3 * 6 − 4 / 1<br />
Beispiel 2: 5 * (6 + 2) − 7 / 4 + 2 * 5<br />
–<br />
+<br />
+<br />
/<br />
−<br />
*<br />
2<br />
* 4<br />
1<br />
*<br />
/<br />
2 5<br />
3 6<br />
5<br />
+<br />
7 4<br />
6 2<br />
a) Stelle die zugehörigen Terme auf:<br />
*<br />
/<br />
2<br />
+<br />
–<br />
+<br />
7<br />
/<br />
*<br />
+<br />
2<br />
1<br />
5 5<br />
5 4<br />
3 2<br />
b) Stelle die zugehörigen Termbäume zu den Termen (I) 7 * 6 − (3 * 5 − 2 + 1) und<br />
(II) 3 − 8 / 4 * 3 + 5 auf.<br />
c) Durchläuft man einen Termbaum in Preorder, so erhält man den sogenannten Präfix-<br />
Term, durchläuft man ihn in Postorder, so erhält man den Postfix-Term.<br />
Gib sowohl den Präfix-Term als auch den Postfix-Term der Beispiel-Termbäume an<br />
(Beispiel 1 und 2).<br />
d) Gegeben ist nun der Präfix-Term (I) – * 2 + 2 3 + 6 1. Stelle den zugehörigen Termbaum<br />
auf. Versuche das gleiche mit den Präfix-Termen (II) * + 8 7 − 7 / 4 2 und<br />
(III) + + + 1 1 1 + + 1 1 + 1 . Begründe bei (III) dein Ergebnis.<br />
e) Gegeben ist nun der Postfix-Term (I) 1 3 5 * + 6 − 8 3 * −. Stelle den zugehörigen<br />
Termbaum auf. Versuche das gleiche mit den Postfix-Termen (II) 8 7 7 * + 4 2 / − und<br />
(III) 1 * + 3 4 – *. Begründe bei (III) dein Ergebnis.<br />
In der Anlage (Anlage I) findest du eine mögliche Klassendefinition TTermbaum für einen<br />
Termbaum. Dieser ist abgeleitet vom Datentyp Binärbaum und erbt somit alle in TBinbaum<br />
definierten Methoden.<br />
f) Schreibe die Methode ToPostorder der Klasse TTermbaum, welche den Termbaum<br />
als Postfix-Term zurückgibt.<br />
g) Beschreibe algorithmisch, wie die Funktion FromPreorder aus einem Präfix-Term<br />
den zugehörigen Termbaum erstellen kann. „Befehle“ wie „Lies nächstes Zeichen“,<br />
„Prüfe, ob Zeichen ein Operator ist“, etc. sind dabei in Ordnung.
unit TermBaum;<br />
interface<br />
uses BinBaum<br />
const Operatoren: set of char= ['+','-','*','/','^']; { Menge der Operatoren }<br />
Operanden: set of char= ['0'..'9']; { Menge der Operanden }<br />
type TTermbaum = class(TBinBaum)<br />
Inhalt: char; { nur Ziffern als Operanden erlaubt }<br />
constructor create(z: char); { Konstruktor mit Übergabe des Wurzelinhalts }<br />
function WurzelinhaltToString: string; override; { Aus TBinbaum geerbt }<br />
function ToPreOrder: string; { Gibt den Termbaum als PreOrder-String aus }<br />
function ToInOrder: string; { Gibt den Termbaum als InOrder-String aus }<br />
function ToPostOrder: string; { Gibt den Termbaum als PostOrder-String aus }<br />
function Auswertung: Integer; { Wertet den Termbaum arithmetisch aus }<br />
end;<br />
function FromPreOrder(var Zeichenkette: string): TTermBaum; { Erzeugung eines Termbaums aus PreOrder-String }<br />
function FromInOrder(var Zeichenkette: string): TTermbaum; { Erzeugung eines Termbaums aus InOrder-String }<br />
function FromPostOrder(var Zeichenkette: string): TTermbaum; { Erzeugung eines Termbaums aus PostOrder-String }<br />
Eine mögliche Oberfläche zur Darstellung von Termbäumen ist die folgende:
Aufgabe 1:<br />
Binärbäume<br />
In der fünften Klasse lernt man, nach welchen Rechengesetzen Terme berechnet werden:<br />
Klammer- vor Punkt- und Punkt- vor Strichrechnung. Zur Veranschaulichung werden<br />
sogenannte Rechenbäume oder Termbäume benutzt, welche die Reihenfolge der Berechnung<br />
veranschaulichen. Zwei Beispiele:<br />
Beispiel 1: 2 + 3 * 6 − 4 / 1<br />
Beispiel 2: 5 * (6 + 2) − 7 / 4 + 2 * 5<br />
–<br />
+<br />
+<br />
/<br />
−<br />
*<br />
2<br />
* 4<br />
1<br />
*<br />
/<br />
2 5<br />
3 6<br />
5<br />
+<br />
7 4<br />
6 2<br />
a) Gib für folgende Termbäume den zugehörigen Term an.<br />
*<br />
/<br />
2<br />
+<br />
–<br />
+<br />
7<br />
/<br />
*<br />
+<br />
2<br />
1<br />
5 5<br />
5 4<br />
3 2<br />
b) Zeichne die Termbäume zu den Termen<br />
(I) 7 * 6 − (3 * 5 − 2 + 1) und<br />
(II) 3 − 8 / 4 * 3 + 5.<br />
c) Durchläuft man einen Termbaum in Preorder, so erhält man den sogenannten Präfix-<br />
Term, durchläuft man ihn in Postorder, so erhält man den Postfix-Term.<br />
Gib sowohl den Präfix-Term als auch den Postfix-Term der Beispiel-Termbäume an<br />
(Beispiel 1 und 2).<br />
d) Gegeben sind nun der Präfix-Terme<br />
(I) – * 2 + 2 3 + 6 1<br />
(II) * + 8 7 − 7 / 4 2 und<br />
(III) + + + 1 1 1 + + 1 1 + 1 1<br />
Stelle die Terme als Termbaum dar.<br />
e) Gegeben sind nun die Postfix-Terme<br />
(I) 1 3 5 * + 6 − 8 3 * −<br />
(II) 8 7 7 * + 4 2 / − und<br />
(III) 1 1 + 1 + 1 1 + 1 + +<br />
Stelle die Terme als Termbaum dar.
f) Die Datenstruktur eines Termbaums ist durch folgendes UML-Diagramm gegeben.<br />
I) Erläutere die Beziehungen dieser Datenstruktur.<br />
II) Begründe, warum eine Vererbung der Klasse TTermbaum von der Klasse TBinTree<br />
nicht sinnvoll ist.<br />
g) Implementiere die private Methode BinTreeToPostOrder, welche die zu dem<br />
übergebenen Binärbaum zugehörige Postfixterm-Darstellung zurückliefert.<br />
h) Vervollständige das folgende Raster der privaten Methode PreOrderToBinTree, welche<br />
aus einem Präfixterm einen Binärbaum erstellt und zurückgibt.<br />
Hinweise: Eine Fehlerprüfung, ob tatsächlich ein Präfixterm vorliegt, ist nicht erforderlich.<br />
Alle Operanden sind Ziffern. Leerzeichen wurden zuvor aus der Zeichenkette entfernt.<br />
const Operatoren: set of char= ['+','-','*','/','^'];<br />
Operanden: set of char= ['0'..'9'];<br />
function NaechstesZeichen(var Zeichenkette: string): char;<br />
begin<br />
result:= Zeichenkette[1];<br />
Delete(Zeichenkette,1,1);<br />
end;<br />
function TTermbaum.PreOrderToBinTree(var Zeichenkette: string): TBinTree;<br />
var ltb, rtb: TBinTree;<br />
Zeichen: char;<br />
begin<br />
Zeichen:= NaechstesZeichen(Zeichenkette);<br />
if Zeichen in Operatoren // prüfe, ob das Zeichen ein Operator ist.<br />
then begin<br />
// hier bitte den richtigen Code ergänzen.<br />
end<br />
else result:= TBinTree.Create(TOperandObjekt.create(StrToInt(Zeichen)));<br />
end;
Materialien<br />
Die Klasse TBinTree<br />
In einem Objekt der Klasse TBinTree werden beliebige Objekte in einem Binärbaum verwaltet. Ein<br />
Binärbaum ist entweder leer oder besteht aus einem Knoten, dem ein Element und zwei binäre<br />
Teilbäume, die so genannten linken und rechten Teilbäume, zugeordnet sind.<br />
Dokumentation der Methoden der Klasse TBinTree<br />
Konstruktor create<br />
nachher Ein leerer Baum existiert<br />
Konstruktor create (pObject: TObject)<br />
nachher Der Binärbaum existiert und hat einen Wurzelknoten mit dem Inhalt pObject und<br />
zwei leeren Teilbäumen.<br />
Konstruktor create (pObject: TObject; pLeftTree, pRightTree: TBinTree)<br />
nachher Der Binärbaum existiert hat einen Wurzelknoten mit dem Inhalt pObject, dem<br />
linken Teilbaum pLeftTree und dem rechten Teilbaum pRightTree.<br />
Anfrage<br />
nachher<br />
Auftrag<br />
nachher<br />
Auftrag<br />
nachher<br />
Anfrage<br />
vorher<br />
nachher<br />
Auftrag<br />
vorher<br />
nachher<br />
Auftrag<br />
vorher<br />
nachher<br />
Anfrage<br />
vorher<br />
nachher<br />
Anfrage<br />
vorher<br />
nachher<br />
Auftrag<br />
nachher<br />
isEmpty: boolean<br />
Diese Anfrage liefert den Wahrheitswert true, wenn der Binärbaum leer ist, sonst<br />
liefert sie den Wert false.<br />
clear<br />
Der Binärbaum ist leer. Auch die Inhaltsobjekte der Knoten wurden freigegeben<br />
und stehen nicht mehr zur Verfügung.<br />
setRootItem (pObject: TObject)<br />
Die Wurzel hat – unabhängig davon, ob der Binärbaum leer ist oder schon eine<br />
Wurzel hat – pObject als Inhalt. Eventuell vorhandene Teilbäume werden nicht<br />
geändert.<br />
getRootItem: TObject<br />
Der Binärbaum ist nicht leer.<br />
Diese Anfrage liefert den Inhalt des Wurzelknotens des Binärbaums.<br />
setLeftTree (pTree: TBinTree)<br />
Der Binärbaum ist nicht leer.<br />
Die Wurzel hat den übergebenen Baum als linken Teilbaum.<br />
setRightTree (pTree: TBinTree)<br />
Der Binärbaum ist nicht leer.<br />
Die Wurzel hat den übergebenen Baum als rechten Teilbaum.<br />
getLeftTree: TBinTree<br />
Der Binärbaum ist nicht leer<br />
Diese Anfrage liefert den linken Teilbaum der Wurzel des Binärbaums. Der<br />
Binärbaum ist unverändert.<br />
getRightTree: TBinTree<br />
Der Binärbaum ist nicht leer<br />
Diese Anfrage liefert den rechten Teilbaum der Wurzel des Binärbaums. Der<br />
Binärbaum ist unverändert.<br />
destroy<br />
Der Binärbaum existiert nicht mehr.
Aufgabe 1:<br />
Bäume<br />
Im Unterricht haben Sie Datenstrukturen für Binärbäume (BinTree) und geordnete<br />
Binärbäume (OrderedTree) kennen gelernt. Beide Datenstrukturen hatten den Nachteil,<br />
dass jeder Knoten lediglich zwei Sohnknoten besaß. Es gibt allerdings Anwendungsbeispiele,<br />
bei denen es hilfreich wäre, dass jeder Knoten beliebig viele Sohnknoten speichert. Beispiele<br />
hierfür sind Entscheidungsbäume bei Strategiespielen (eine Spielsituation hat eine<br />
unterschiedliche Anzahl von Folge-Situationen) oder Ahnenbäume (ein Mensch hat nicht<br />
immer genau zwei Nachkommen).<br />
Im Folgenden sollen Sie Teile einer hierfür geeigneten Datenstruktur Tree modellieren und<br />
implementieren.<br />
a) Die Speicherung der Sohnknoten eines Trees soll mittels einer List (siehe Anlage)<br />
realisiert werden. Folgende Konstruktoren, Aufträge und Anfragen sollen in der Klasse<br />
Tree Berücksichtigung finden:<br />
(1) zwei Konstruktoren zur Erzeugung eines leeren Trees oder eines Trees mit einem<br />
Inhalt vom Typ Object.<br />
(2) eine Anfrage, ob der Tree leer ist<br />
(3) einen Auftrag zum Leeren des Trees, d. h. alle Inhalte werden gelöscht<br />
(4) eine Anfrage nach dem Inhalt der Wurzel des Trees<br />
(5) einen Auftrag zum Setzen des Inhalts der Wurzel des Trees<br />
(6) eine Anfrage nach einem Teilbaum des Trees, wobei durch eine Nummer bestimmt<br />
wird, der wievielte Teilbaum angefragt wird.<br />
(7) Auftrag zum Anhängen eines neuen Teilbaums an den Tree. Die Teilbäume<br />
benötigen keine spezielle Ordnung.<br />
Zeichnen Sie ein UML-Klassendiagramm der Klasse Tree mit allen Attributen und<br />
Methoden.<br />
Ergänzen Sie das Diagramm um ein Klassendiagramm der Klasse List (ohne Methoden<br />
und Attribute) und setzen Sie beide Klassen sinnvoll in Beziehung zueinander.<br />
b) Dokumentieren Sie die Anfrage nach einem Teilbaum (6) sowie den Auftrag zum Setzen<br />
des Inhalts der Wurzel eines Trees (5) ausführlich mit vorher/nachher-Bedingung. Gehen<br />
Sie auch auf Spezialfälle ein.<br />
c) Implementieren Sie beide Konstruktoren der Klasse Tree (1) sowie die Methode für die<br />
Anfrage nach einem Teilbaum (6). Achten Sie auf die in b) dokumentierten Spezialfälle.<br />
d) Implementieren Sie die Methode<br />
String preOrder(Tree pTree)<br />
welche die Wurzelinhalte des Baums pTree in preorder-Traversierung<br />
semikolongetrennt in einem String ausgibt.<br />
Hinweis: Die Klasse Object verfügt über eine Methode toString(), welche zur<br />
Konvertierung in einen String genutzt werden kann.
Aufgabe 1: AVL-Bäume<br />
Aus dem Unterricht kennen Sie die Datenstruktur TAVLBaum. (siehe Interface in Anlage I)<br />
a) Geben Sie die Definition für einen AVL-Baum an. Erläutern Sie den wesentlichen Vorteil<br />
im Gegensatz zu den ihnen bekannten Baumstrukturen. Erläutern Sie wenigstens zwei<br />
weitere Möglichkeiten der Baumoptimierung.<br />
b) Fügen Sie nacheinander die folgenden Elemente in einen anfangs leeren AVL-Baum ein.<br />
Zeichnen Sie nach jeder AVL-Korrekturoperation (Links-/Rechtsrotation) den Baum neu.<br />
3, 4, 7, 1, 2, 6 und 5<br />
8<br />
c) Löschen Sie im rechts abgebildeten AVL-Baum das<br />
Element mit der Nr. 8. Stellen Sie anschließend die<br />
AVL-Eigenschaft wieder her.<br />
2<br />
5<br />
11<br />
7 9<br />
14<br />
1<br />
3<br />
6 10 13 15<br />
4<br />
d) Das Einfügen und Löschen in AVL-Bäumen kann zur<br />
Störungen der AVL-Balance führen. Skizzieren Sie die um Unterricht entwickelte<br />
Fallunterscheidung, welche alle möglichen Situationen vor und nach den<br />
Korrekturoperationen enthält.<br />
12<br />
e) Implementieren Sie den Teil der Methode<br />
function TAVLBaum.AVLKorrektur: TAVLBaum.<br />
der für einen Baum in rechts abgebildeter Situation die AVL-<br />
Eigenschaft wieder herstellt.<br />
if (Balance = −2) and (LinkerTeilbaum.Balance = −1) then ...<br />
h−1<br />
Y<br />
h<br />
h−2<br />
X<br />
h+1<br />
h−2<br />
f) Die von TAVLBaum abgeleitete Klasse TIntAVLBaum soll<br />
Integer-Werte aufnehmen können. Implementieren Sie für diese Klasse eine Methode<br />
function TIntAVLBaum.AVL_PerfekterAusgleich: TAVLBaum.<br />
Die Funktion soll den Baum InOrder auf einen File abgelegen und den dann per<br />
Halbteilungsmethode eingelesen Baum zurückgeben.<br />
Verwenden Sie wann immer möglich die Methoden des AVL-Baumes bzw. die des ihnen<br />
bekannten Binärbaumes.<br />
5<br />
3<br />
7<br />
1<br />
4 6<br />
2<br />
File:<br />
1 2 3 4 5 6 7<br />
EOF<br />
4<br />
2<br />
6<br />
1<br />
3<br />
5<br />
7
Aufgabe 2:<br />
AVL-Bäume<br />
a) Bauen Sie schrittweise einen AVL-Baum auf. Zeichnen Sie den Baum nach jeder<br />
Korrekturoperation:<br />
10, 20, 30, 110, 100, 90, 80, 70, 60, 50, 40<br />
b) Löschen Sie nun nacheinander die folgenden Elemente. Zeichne Sie nach jedem<br />
Löschvorgang den aktuellen Baum:<br />
50, 40, 30, 20<br />
c) Geben Sie die Prorder- und Postorder-Ausgabe des Baums aus Teilaufgabe a) an.<br />
d) Schreiben Sie eine Funktion, welche einen vorhandenen Baum in PROLOG-<br />
Notation ausgibt.<br />
function TAVLBaum.PrologAusgabe: string;<br />
begin<br />
{ hier kommt der Programmtext hin... }<br />
end;<br />
z. B. sollte der rechts abgebildete Baum die folgende Rückgabe bewirken:<br />
baum(30,baum(10,nil,baum(20,nil,nil)),baum(50,baum(40,nil,nil),baum(60,nil,nil)))<br />
30<br />
10 50<br />
20<br />
40<br />
60<br />
e) Begründen Sie mit Hilfe eines geeigneten Beispiels: Das Löschen eines Elements in einem<br />
AVL-Baum kann auf mehreren Ebenen Korrekturoperationen nach sich ziehen.<br />
f) Ist es möglich, dass nach dem Einfügen eines neuen Elements in einen AVL-Baum die<br />
AVL-Balance eines Knotens −3 beträgt? Begründen Sie!<br />
g) Die Ausgewogenheit eines nichtleeren AVL-Baumes ist definiert durch das Verhältnis<br />
Summe der absoluten Balancen<br />
a = . Dabei meint man mit absoluten Balancen die<br />
Anzahl der Knoten<br />
jeweiligen Beträge der Balancen.<br />
Begründen Sie die untere Schranke: a ≥ 0. Zeigen Sie durch ein Beispiel, dass a = 0<br />
möglich ist.<br />
Geben Sie eine möglichst kleine obere Schranke für diese Maßzahl a an. Begründen Sie<br />
Ihre Wahl anhand geeigneter Beispiele.<br />
Lösung:<br />
Aufgabe 2:<br />
a)<br />
b)<br />
c)<br />
d)<br />
function TAVLBaum.PrologAusgabe: string;<br />
begin<br />
if BaumLeer<br />
then Result:= ´nil´<br />
else Result:= ´baum(´+WurzelinhaltToString+´,´+<br />
+(linkerTeilbaum as TAVLBaum).PrologAusgabe<br />
+´,´<br />
+(rechterTeilbaum as TAVLBaum).PrologAusgabe<br />
+´)´;<br />
end;
Aufgabe 2:<br />
Bäume – Binärbäume – Suchbäume<br />
a) Im Unterricht haben wir verschiedene Gruppen von Bäumen kennen<br />
gelernt: Gruppe A: AVL-Bäume<br />
Gruppe B: Suchbäume<br />
Gruppe C: Binärbäume<br />
Gruppe D: Bäume<br />
Gruppe E: keine Bäume (Graphen)<br />
Diese stehen in einem rechts veranschaulichten Hierarchieverhältnis.<br />
(E) Graphen<br />
(D) Bäume<br />
(C) Binärbäume<br />
(B) Suchbäume<br />
Ordnen Sie jede der nachfolgenden Strukturen in die Gruppenhierarchie ein. Begründen<br />
Sie kurz, warum die Struktur zur angegebenen Hierarchiestufe gehört.<br />
(1) (2)<br />
–6<br />
0<br />
6<br />
3 9<br />
(3)<br />
(A) AVL-Bäume<br />
(4)<br />
100<br />
1<br />
(5) (6)<br />
K<br />
010<br />
110<br />
F<br />
T<br />
001<br />
011<br />
101 111<br />
L<br />
N<br />
b) Das Einfügen und Löschen in AVL-Bäumen kann dazu führen, dass die AVL-Eigenschaft<br />
verloren geht, welche dann durch Rotationen wieder hergestellt werden muss.<br />
Stellen Sie dar, wie die folgenden Elemente nacheinander in einen<br />
anfangs leeren AVL-Baum eingefügt werden. Ihre Darstellung muss<br />
auch die AVL-Korrekturoperationen beinhalten.<br />
7, 6, 1, 4, 2, 5, 3<br />
Stellen Sie das schrittweise Löschen der Elemente 7, 10, 3, 6 im rechts<br />
abgebildeten AVL-Baum dar.<br />
1<br />
2<br />
3<br />
4<br />
6<br />
8<br />
7 10<br />
5 9 11<br />
c) Implementieren Sie eine Methode für den allgemeinen Binärbaum, welche überprüft, ob<br />
die AVL-Eigenschaft erfüllt ist. Verwenden Sie wann immer möglich die Methoden der<br />
Klasse TBinTree (Anlage I). Eventuelle Hilfsmethoden sind ebenfalls zu implementieren.<br />
function TBinTree.AVL_ok: boolean;<br />
d) Die Daten eines Integer-Suchbaumes sollen in einem File abgelegt werden. Die<br />
gespeicherten Daten sollen so gespeichert sein, dass eine identische Rekonstruktion der<br />
alten Baumstruktur möglich ist.<br />
Erläutern Sie eine Idee, wie die Daten gespeichert werden müssten. Begründen Sie dabei,<br />
dass über die eigentlichen Daten hinaus keine weitere Informationen abgespeichert<br />
werden müssen, um eine identische Rekonstruktion zu ermöglichen.<br />
Entwickeln Sie einen Grobalgorithmus, der die Rekonstruktion des Baumes erzeugt.<br />
Die Klasse TBinTree<br />
In einem Objekt der Klasse TBinTree werden beliebige Objekte in einem Binärbaum<br />
verwaltet. Ein Binärbaum ist entweder leer oder besteht aus einem Knoten, dem ein<br />
Element und zwei binäre Teilbäume, die so genannten linken und rechten<br />
Teilbäume,
zugeordnet sind.<br />
Dokumentation der Methoden der Klasse TBinTree<br />
Konstruktor create<br />
nachher Ein leerer Baum existiert<br />
Konstruktor create (pObject: TObject)<br />
nachher Der Binärbaum existiert und hat einen Wurzelknoten mit dem Inhalt pObject und<br />
zwei leeren Teilbäumen.<br />
Konstruktor create (pObject: TObject; pLeftTree, pRightTree: TBinTree)<br />
nachher Der Binärbaum existiert hat einen Wurzelknoten mit dem Inhalt pObject, dem<br />
linken Teilbaum pLeftTree und dem rechten Teilbaum pRightTree.<br />
Anfrage<br />
nachher<br />
Auftrag<br />
nachher<br />
Auftrag<br />
nachher<br />
Anfrage<br />
vorher<br />
nachher<br />
Auftrag<br />
vorher<br />
nachher<br />
Auftrag<br />
vorher<br />
nachher<br />
Anfrage<br />
vorher<br />
nachher<br />
Anfrage<br />
vorher<br />
nachher<br />
Auftrag<br />
nachher<br />
isEmpty: boolean<br />
Diese Anfrage liefert den Wahrheitswert true, wenn der Binärbaum leer ist, sonst<br />
liefert sie den Wert false.<br />
clear<br />
Der Binärbaum ist leer. Auch die Inhaltsobjekte der Knoten wurden freigegeben<br />
und stehen nicht mehr zur Verfügung.<br />
setRootItem (pObject: TObject)<br />
Die Wurzel hat – unabhängig davon, ob der Binärbaum leer ist oder schon eine<br />
Wurzel hat – pObject als Inhalt. Eventuell vorhandene Teilbäume werden nicht<br />
geändert.<br />
getRootItem: TObject<br />
Der Binärbaum ist nicht leer.<br />
Diese Anfrage liefert den Inhalt des Wurzelknotens des Binärbaums.<br />
addTreeLeft (pTree: TBinTree)<br />
Der Binärbaum ist nicht leer.<br />
Die Wurzel hat den übergebenen Baum als linken Teilbaum.<br />
addTreeRight (pTree: TBinTree)<br />
Der Binärbaum ist nicht leer.<br />
Die Wurzel hat den übergebenen Baum als rechten Teilbaum.<br />
getLeftTree: TBinTree<br />
Der Binärbaum ist nicht leer<br />
Diese Anfrage liefert den linken Teilbaum der Wurzel des Binärbaums. Der<br />
Binärbaum ist unverändert.<br />
getRightTree: TBinTree<br />
Der Binärbaum ist nicht leer<br />
Diese Anfrage liefert den rechten Teilbaum der Wurzel des Binärbaums. Der<br />
Binärbaum ist unverändert.<br />
destroy<br />
Der Binärbaum existiert nicht mehr.<br />
Lösung:<br />
Aufgabe 2:<br />
a) Die Zuordnung sieht wie folgt aus:
(1): Gruppe E. Nicht D, da es zu einem Element unterschiedliche Wege gibt.<br />
(2): Gruppe B. Nicht A, da die AVL-Eigenschaft in oberster Wurzel verletzt ist (−2).<br />
(3): Gruppe C. Nicht D, da keine Inhalte vorhanden sind.<br />
(4): Gruppe A. AVL-Eigenschaft überall ok und Inhalte (Binärzahlen) aufsteigend sortiert.<br />
(5): Gruppe D. Nicht C, da es vom obersten Knoten drei Nachfolger gibt.<br />
(6): Gruppe C. Nicht B, da die alphabetische Reihenfolge gestört ist ( L nicht kleiner K).<br />
b) Die Lösungen der Teilaufgaben lauten wie folgt:<br />
b.1) Das Einfügen gestaltet sich wie folgt:<br />
7,6,1 7 R(7) 6 4,2 6 R(4), L(1)<br />
6<br />
5<br />
6<br />
6<br />
1<br />
7<br />
1<br />
7<br />
2<br />
7<br />
2<br />
7<br />
1<br />
4<br />
1<br />
4<br />
1<br />
4<br />
L(2)<br />
6<br />
2<br />
R(6)<br />
4<br />
3<br />
4<br />
5<br />
4<br />
7<br />
2<br />
6<br />
2<br />
6<br />
2<br />
5<br />
1 5<br />
7<br />
1 3 5<br />
7<br />
1<br />
b.1) Das Löschen gestaltet sich wie folgt:<br />
7<br />
6<br />
L(8)<br />
6<br />
10<br />
6<br />
3<br />
8<br />
3<br />
10<br />
3<br />
9<br />
2<br />
4<br />
10<br />
2<br />
4<br />
8<br />
11<br />
2<br />
4<br />
8<br />
11<br />
1<br />
3<br />
5 9 11<br />
6<br />
1<br />
6<br />
5<br />
5<br />
9<br />
1<br />
5<br />
2<br />
9<br />
2<br />
9<br />
1<br />
4<br />
8<br />
11<br />
1<br />
4<br />
8<br />
11<br />
5<br />
c) Eine Funktion, welche die AVL-Eigenschaft überprüft lautet wie folgt:<br />
function TBinBaum.AVL_ok: boolean;<br />
var l,r: integer;<br />
begin<br />
if leer then AVL_ok:= true<br />
else begin<br />
l:= LinkerTeilbaum.Baumhoehe;<br />
r:= rechterTeilbaum.Baumhoehe;<br />
AVL_ok:= LinkerTeilbaum.AVL_ok and<br />
RechterTeilbaum.AVL_ok and<br />
(abs(l-r)
function TBinBaum.Baumhoehe: integer;<br />
var l,r: integer;<br />
begin<br />
if leer then Baumhoehe:= 0<br />
else begin<br />
l:= LinkerTeilbaum.Baumhoehe;<br />
r:= RechterTeilbaum.Baumhoehe;<br />
if l>r then Baumhoehe:= l+1<br />
else Baumhoehe:= r+1;<br />
end;<br />
end;<br />
d) Die Speicherung geschieht PreOrder, d. h. in dem File wird beim Beispielbaum aus<br />
Teilaufgabe c) die Zahlenreihenfolge 6, 3, 2, 1, 4, 5, 8, 7, 10, 9, 11 gespeichert.<br />
Baut man nun mit dieser Zahlenreihenfolge wieder einen neuen Suchbaum auf, so ergibt<br />
sich exakt der gleiche Suchbaum wie zuvor.<br />
Ein Grobalgorithmus wäre wie folgt:<br />
Solange Datei nicht am Ende<br />
Tue: Lies nächste Zahl<br />
Baum.Insert(Zahl)
Aufgabe 3:<br />
Bäume - Quadtrees<br />
Quadratische Schwarz-Weiß-Grafiken, deren Seitenlänge (in Pixeln) eine Zweierpotenz ist,<br />
können mit Hilfe der Datenstruktur QuadTree gespeichert werden. Ein QuadTree ist dabei<br />
ein Baum, der entweder vier Teilbäume hat oder ein Blatt ist.<br />
Der Inhalt eines Bildes wird nach folgendem Algorithmus in der Datenstruktur abgelegt:<br />
• Jedem Teilquadrat der Grafik entspricht ein QuadTree.<br />
• Ist die Farbe eines Teilquadrates einheitlich, so wird in den Knoten des zugehörigen<br />
QuadTree der Farbwert (1 = schwarz, 0 = weiß) eingetragen. Der QuadTree besitzt in<br />
diesem Fall leere Teilbäume und ist somit ein Blatt.<br />
• Ist die Farbe nicht einheitlich, so wird dies im Knoten des zugehörigen QuadTree<br />
durch den Wert −1 kenntlich gemacht. Anschließend wird das Quadrat in vier<br />
Teilquadrate zerlegt. Deren Bildinhalte werden im Uhrzeigersinn (links oben, rechts<br />
oben, rechts unten, links unten) in Teilbäume abgelegt und an den aktuellen Knoten<br />
angehängt.<br />
Beispiel: Folgendes 8x8-Schwarz-Weiß-Bild soll in einem QuadTree gespeichert werden:<br />
Der zugehörige QuadTree sieht demnach wie folgt aus:<br />
−1<br />
1<br />
−1 −1 −1<br />
−1 0 0 0<br />
0 0 1 0 0 1 0 −1<br />
1 0 0 0<br />
0 1 0 0<br />
Durchläuft man den Baum in der Reihenfolge Wurzel-Linksaußen-Linksinnen-Rechtsinnen-<br />
Rechtsaußen (WLaLiRiRa), so erhält man die untenstehende Folge von Knoteninhalten, die<br />
als Bilddatei gespeichert werden kann:<br />
−1, −1, −1, 1, 0, 0, 0, 0, 0, 0, 1, −1, 0, 0, 1, 0, −1, 0, 1, 0, −1, 0, 1, 0, 0<br />
a) Stellen Sie den QuadTree zur rechts abgebildeten 8x8-<br />
Schwarz-Weiß-Grafik dar. Geben Sie anschließend die Folge<br />
von Knoteninhalten an, die als Bilddatei gespeichert werden<br />
könnte.
) Eine 8x8-Grafik ist in Form einer Bilddatei (nach der oben genannten<br />
Durchlaufstrategie WLaLiRiRa) abgelegt:<br />
−1, −1, 0, −1, 0, 1, 1, 0, −1, 0, 1, 1, 0, 0, −1, −1, 1, 0, 0, 1, 0, 0, −1, 1, 0, 0, 1,<br />
−1, 1, 1, 0, 0, −1, 0, 0, 1, 1<br />
Stellen Sie den zugehörigen QuadTree grafisch dar.<br />
Stellen Sie die zugehörige 8x8 Grafik dar.<br />
Analysieren Sie, was passieren würde, wenn Sie mit dieser Datei statt einer 8x8-Grafik<br />
eine 16x16-Grafik aufbauen würden?<br />
Stellen Sie die zugehörige 16x16-Grafik dar und beschreiben Sie die Veränderungen<br />
bzgl. der 8x8-Grafik.<br />
Begründen Sie, ob es möglich ist, aus dieser Datei eine 4x4-Grafik aufzubauen und<br />
erläutern Sie eventuelle Einschränkungen.<br />
c) Nebenstehend sehen Sie eine Modellierung der<br />
Klasse TQuadTree.<br />
Dokumentieren Sie die Klasse.<br />
d) Implementieren Sie die Methode<br />
LoadFromFile(...) , welche den Aufbau<br />
eines QuadTrees aus einer Datei mit dem angegebenen Dateinamen übernimmt.<br />
Hinweis 1: Damit die Methode aufgerufen werden kann, muss die Wurzel des<br />
QuadTrees bereits erzeugt sein (siehe Oberflächenprozedur). Berücksichtigen Sie dies<br />
in Ihrer Implementierung.<br />
Hinweis 2: Falls Sie die Methode LadeRekursiv_WLaLiRiRa in Ihrer<br />
Implementierung benötigen, so implementieren Sie diese bitte ebenfalls.<br />
Lösung:<br />
type TQuadTreeFile = file of shortint;<br />
procedure TQuadTree.LoadFromFile(dateiname: string);<br />
var ...<br />
begin<br />
...<br />
end;<br />
procedure MI_OeffnenClick(Sender: TObject);<br />
var QT: TQuadTree;<br />
begin<br />
QT:= TQuadTree.Create;<br />
QT.LoadFromFile(´Baum.dat´);<br />
end;<br />
Aufgabe 3:<br />
a) Zur angegebenen Grafik gehört der folgende QuadTree
−1<br />
−1<br />
0<br />
−1 –1<br />
−1 0 0<br />
–1<br />
0 1 0 1 1 0 1 0<br />
0 1 0 1<br />
0 1 0 1<br />
Das Bild entspricht somit der Datei<br />
−1, −1, −1, 0, 1, 0, 1, 0, 0, −1, 0, 1, 0, 1, 0, −1, 0, 1, 0, 1, −1, 1, 0, 1, 0<br />
b.1) Der zugehörige QuadTree sieht wie folgt aus:<br />
−1<br />
−1<br />
–1<br />
−1<br />
–1<br />
0 –1 –1<br />
0<br />
–1 0 0<br />
–1<br />
1 1 0 0 0 0<br />
1 1<br />
0 1 1 0<br />
0<br />
1 1 0<br />
1 0 0 1<br />
1 0 0 1<br />
b.2) Und das zugehörige 8x8-Bild hat folgendes Aussehen:<br />
b.3) Würde man aus der Datei ein 16x16-Bild aufbauen, so wäre es um den Faktor 2<br />
„gezoomt“:<br />
b.4) Aus dieser Datei ist es nicht so ohne weiteres möglich, da der Baum eine Tiefe von 4<br />
Ebenen hat. Die dritte Ebene entspricht aber bereits dem Farbwert eines Pixels, so dass<br />
für die vierte Ebene ein Pixel aufgeteilt werden müsste. Dies ist jedoch nicht möglich.
Eine Möglichkeit bestände darin, die Farbwerte der Teilbäume aus der vierten Ebene zu<br />
einem Farbwert für ein Pixel zusammenzufassen („Rendering“ durch<br />
Mittelwertbildung). Diese Möglichkeit muss jedoch vom Prüfling nicht erkannt werden.<br />
c) Die Dokumentation der Klasse könnte wie folgt aussehen:<br />
Anfrage LoadFromFile:<br />
vorher: Baum mit einem Wurzelelement<br />
nachher: Baum, welcher aus einer Datei ausgelesen wurde<br />
Auftrag SaveToFile:<br />
vorher: Baum exisitert und ist nicht leer<br />
nachher: Der Baum wurde in der Traversierung WLaLiRiRa in die Datei gespeichert.<br />
Auftrag Zeichnen:<br />
vorher: Der Baum ist nicht leer<br />
nachher: Der Baum wurde in der Paintbox ausgegeben<br />
Anfrage Leer:<br />
vorher: Der Baum exisitiert<br />
nachher: Ist der Baum leer, so wird true zurück gegeben, andernfalls false<br />
Auftrag LadeRekursiv_WLaLiRiRa<br />
vorher: Die Datei ist geöffnet<br />
nachher: Der Baum wurde aus der Datei eingelesen.<br />
d) Lediglich der Dateiname wird übergeben, so dass eine Rahmenprozedur die Datei öffnen<br />
muss und eine innere rekursive Prozedur die Inhalte PreOrder einlesen muss.<br />
procedure TQuadTree.LadeRekursiv_WLaLiRiRa(var f:<br />
TQuadTreeFile);<br />
var i: integer;<br />
begin<br />
Readln(f,Farbwert);<br />
if Farbwert=-1<br />
then begin<br />
for i:= 1 to 4<br />
do begin<br />
Teilbaeume[i]:= TQuadTree.Create;<br />
Teilbaeume[i].LadeRekursiv_WLaLiRiRa(f);<br />
end;<br />
end;<br />
end;<br />
procedure TQuadTree.LoadFromFile(dateiname: string);<br />
var datei : TQuadTreeFile;<br />
begin<br />
AssignFile(datei, dateiname);<br />
ReSet(datei);<br />
LadeRekursiv_WLaLiRiRa(datei);<br />
CloseFile(datei);<br />
end;<br />
procedure MI_OeffnenClick(Sender: TObject);
var QT: TQuadTree;<br />
begin<br />
QT:= TQuadTree.Create;<br />
QT.LoadFromFile(´Baum.dat´);<br />
end;
Aufgabe 4:<br />
Baumstrukturen – Suchbäume − AVL-Bäume<br />
a) In einen anfangs leeren Suchbaum werden nacheinander die Elemente<br />
10, 20, 30, 50, 40, 60, 70 eingefügt.<br />
Zeichnen Sie den resultierenden Suchbaum.<br />
b) Erläutern Sie an diesem Beispiel die Nachteile, die sich bei der Verwendung von<br />
Suchbäumen ergeben können.<br />
c) Die Elemente aus Aufgabenteil a) werden nun in einen anfangs leeren AVL-Baum<br />
eingefügt.<br />
Stellen Sie schrittweise die Entwicklung des AVL-Baums dar.<br />
d) Die Elemente 10, 60, 50, 70 werden nacheinander aus dem AVL-Baum aus Teilaufgabe c)<br />
gelöscht.<br />
Stellen Sie schrittweise die Entwicklung des AVL-Baums dar.<br />
e) Rechts abgebildet sehen Sie das UML-Diagramm der Klasse<br />
TAVLTree.<br />
Implementieren Sie die Methode getTreeHeight<br />
Hinweis: Die Dokumentation der Klasse TBinTree finden<br />
Sie in der ANLAGE IV<br />
Lösung:<br />
Aufgabe 4: a)<br />
10<br />
20<br />
30<br />
50<br />
40 60<br />
70<br />
b) Man erkennt direkt, dass der Baum annähernd zu einer linearen Liste entartet. Die Vorteile<br />
der geringen Suchtiefe von O(log n) in einem ausgeglichenen Suchbaum mit n Elementen<br />
gehen verloren.<br />
c)
20<br />
10<br />
10<br />
30<br />
20<br />
20<br />
30 LR(10)<br />
50<br />
40 RR(50), LR(30)<br />
40<br />
10<br />
40<br />
20<br />
50<br />
30<br />
50<br />
10<br />
30 60<br />
40<br />
60 LR(20)<br />
70 LR(50)<br />
20<br />
60<br />
10<br />
30<br />
50<br />
70<br />
d)<br />
40<br />
40<br />
20<br />
60<br />
20<br />
50<br />
30<br />
50<br />
40<br />
70<br />
30<br />
40<br />
70<br />
20<br />
70 20<br />
30<br />
30<br />
30 LR(20) RR(40) 20<br />
40<br />
e) function TAVLTree.getTreeHeight: integer;<br />
function hoehe(tree: TBinTree): integer;<br />
var l, r: integer;<br />
begin<br />
if isEmpty()<br />
then result:= 0<br />
else begin<br />
l:= hoehe(getLeftTree as TBinTree);<br />
r:= hoehe(getRightTree as TBinTree);<br />
if l>r then result:= l + 1<br />
else result:= r + 1;<br />
end;<br />
end;<br />
begin<br />
result:= hoehe(pTree);<br />
end;
Aufgabe 5:<br />
AVL-Bäume<br />
a) Die nachfolgend aufgeführten Knoteninhalte sollen in einen anfangs leeren AVL-<br />
Baum eingefügt werden. Stellen Sie den schrittweisen Aufbau des AVL-Baums grafisch<br />
dar. Zeichnen Sie auch nach jeder Korrekturoperation den neu entstandenen AVL-Baum.<br />
45; 25; 15; 13; 12; 11; 8; 7; 50; 53; 35; 63<br />
b) Löschen Sie aus dem nachfolgend angegebenen AVL-Baum sukzessive die<br />
Knoteninhalte 16, 30, 40, 11. Geben Sie nach jedem Löschvorgang den entstandenen<br />
Baum an.<br />
30<br />
18<br />
10 23<br />
37<br />
33 40<br />
7<br />
11<br />
20 25<br />
32<br />
5<br />
16<br />
21<br />
c) Implementieren Sie eine Funktion TreeHeight(tree: TBinTree), welche die Höhe eines<br />
Baumes berechnet und zurückgibt. Verwenden Sie wann immer möglich die Methoden<br />
der Klasse TBinTree (Anlage I).<br />
d) Implementieren Sie eine Funktion IsAVLTree(tree: TBinTree), welche überprüft, ob ein<br />
Binärbaum bezüglich seiner Balancierung ein AVL-Baum ist (die Sortierung der<br />
Knoteninhalte soll keine Rolle spielen). Verwenden Sie wann immer möglich die<br />
Methoden der Klasse TBinTree (Anlage I).<br />
Lösung:<br />
Aufgabe 5:<br />
a)
)<br />
c) function TreeHeight(tree: TBinTree): integer;<br />
var l, r: integer;<br />
begin<br />
if tree.isEmpty()<br />
then result := 0<br />
else begin<br />
l:= TreeHeight(tree.getLeftTree);<br />
r:= TreeHeight(tree.getRightTree);<br />
if l> r<br />
then result := l + 1<br />
else result := r + 1;<br />
end;<br />
end;<br />
d) function IsAVLTree(tree: TBinTree): boolean;<br />
var l, r: boolean;
alance: integer;<br />
begin<br />
if tree.isEmpty<br />
then result:= true<br />
else begin<br />
l:= IsAVLTree(tree.getLeftTree);<br />
r:= IsAVLTree(tree.getRightTree);<br />
balance:= TreeHeight(tree.getRightTree) -<br />
TreeHeight(tree.getLeftTree);<br />
result := l and r and (balance in [-1,0,1];<br />
end;<br />
end;
Aufgabe 2:<br />
Bäume<br />
Ein Mobile besteht in der Regel aus Stangen, die untereinander mit Fäden verbunden sind und<br />
an denen an beiden Enden je ein Anhänger befestigt ist. Im einfachsten Fall wollen wir jedoch<br />
auch einen einzelnen Anhänger schon als Mobile auffassen. Folgende Fälle könne also für ein<br />
Mobile unterschieden werden:<br />
Extremfall: Mobile besteht aus einem<br />
Anhänger:<br />
Normalfall: Mobile besteht aus mehreren Stangen,<br />
an deren Ende entweder eine weitere Stange oder<br />
ein Anhänger hängt:<br />
links<br />
10mm<br />
rechts<br />
40mm<br />
links<br />
20mm<br />
rechts<br />
10mm<br />
5000 g<br />
1200 g<br />
100 g<br />
200 g<br />
Bereits an diesem Beispiel erkennt man, dass der Normalfall eines Mobiles auf vielen<br />
einzelnen kleinen Mobiles besteht. Als <strong>Informatik</strong>er können wir dies rekursiv formulieren:<br />
Ein Mobile besteht aus<br />
a) einem Anhänger (Rekursionsanker)<br />
b) aus einer Stange, an denen sich zwei Teilmobiles befinden.<br />
Im Fall a) interessiert uns lediglich die Masse (m) des Anhängers in Gramm.<br />
Die Kraft (F), mit der ein solcher Anhänger an der Stange zieht berechnet sic nach der<br />
physikalischen Vorschrift:F = m⋅g, wobei für die Erdbeschleunigung g = 9,81 m/s 2<br />
angenommen werden kann.<br />
Im Fall b) interessiert uns nur der Aufhängepunkt, also die Werte für die Abstände rechts und<br />
links in Millimetern, wie in der Skizze gezeigt. Wir gehen der Einfachheit halber davon aus,<br />
dass sowohl die Fäden als auch die Stangen gegenüber den Anhängergewichten ein<br />
vernachlässigbares Gewicht haben.<br />
Ein Mobile ist im Gleichgewicht, wenn das Hebelgesetz der Physik erfüllt ist:<br />
F l ⋅ links = F r ⋅ rechts<br />
a) Weisen Sie nach, dass sich das oben dargestellte Mobile überall im Gleichgewicht<br />
befindet.<br />
b) Zeichnen Sie ein Mobile mit mindestens 4 Stangen, welches sich überall im<br />
Gleichgewicht befindet.<br />
c) Zeichnen Sie jeweils ein UML-Klassendiagramm für die Klassen Anhaenger, Stange<br />
und Mobile. Geben Sie im Klassendiagramm alle Datenfelder und Methoden an.
d) Zeichnen Sie nun ein neues Klassendiagramm ohne Methoden und Datenfelder für die<br />
Klassen BinTree und die drei oben genannten Klassen. Veranschaulichen Sie in Ihrem<br />
Diagramm die Beziehungen und begründen Sie Ihre Wahl.<br />
e) Implementieren Sie eine Methode void beispiel(), welches das oben angegebene<br />
Beispiel-Mobile erzeugt.<br />
f) Implementieren Sie für die Klasse Mobile eine Methode int gesamtmasse(),<br />
welche die Gesamtmasse des gespeicherten Mobiles berechnet.<br />
g) Analysieren Sie die folgende Methode und geben Sie an, zu welchem Zweck diese<br />
implementiert wurde.<br />
private boolean rekursiveFunktion(BinTree b) {<br />
if (b.isEmpty()) {<br />
return true;<br />
} else {<br />
if (b.getRootItem() instanceof Anhaenger) {<br />
return true;<br />
} else {<br />
if (b.getRootItem() instanceof Stange) {<br />
return gesamtmasse(b.getLeftTree()) *<br />
((Stange)b.getRootItem()).getLinks() ==<br />
gesamtmasse(b.getRightTree()) *<br />
((Stange)b.getRootItem()).getRechts()<br />
&& rekursiveFunktion(b.getLeftTree())<br />
&& rekursiveFunktion(b.getRightTree());<br />
}<br />
}<br />
}<br />
h) Implementieren Sie die folgenden drei Konstruktoren:<br />
Mobile()<br />
// leeres Mobile<br />
Mobile(int gewicht)<br />
// Mobile mit einem Anhänger<br />
Mobile(Mobile m1, Mobile m1, int l1, int l2) // Mobile mit zwei Teilmobiles (m1<br />
und m2), die an einer Stange in<br />
den Entfernungen l1 bzw. l2<br />
angebracht sind.<br />
Die Klasse BinTree<br />
In einem Objekt der Klasse BinTree werden beliebige Objekte nach dem Binärbaumprinzip<br />
verwaltet. Ein Binärbaum ist entweder leer oder besteht aus einem Knoten, dem ein Element<br />
und zwei binäre Teilbäume, die so genannten linken und rechten Teilbäume, zugeordnet<br />
sind.<br />
Dokumentation der Methoden der Klasse BinTree<br />
Konstruktor BinTree()<br />
nachher Ein leerer Baum existiert<br />
Konstruktor BinTree (Object pObject)<br />
nachher Der Binärbaum existiert und hat einen Wurzelknoten mit dem Inhalt pObject und<br />
zwei leeren Teilbäumen.<br />
Konstruktor BinTree (Object pObject, BinTree pLeftTree, BinTree<br />
pRighttree)<br />
nachher Der Binärbaum existiert, hat einen Wurzelknoten mit dem Inhalt pObject sowie<br />
dem linken Teilbaum pLeftTree und dem rechten Teilbaum pRightTree.<br />
Anfrage isEmpty(): boolean
nachher Diese Anfrage liefert den Wahrheitswert true, wenn der Binärbaum leer ist, sonst<br />
liefert sie den Wert false.<br />
Auftrag clear()<br />
nachher Der Binärbaum ist leer.<br />
Auftrag setRootItem (Object pObject)<br />
nachher Die Wurzel hat – unabhängig davon, ob der Binärbaum leer ist oder schon eine<br />
Wurzel hat – pObject als Inhalt. Eventuell vorhandene Teilbäume werden nicht<br />
geändert.<br />
Anfrage getRootItem(): Object<br />
vorher Der Binärbaum ist nicht leer.<br />
nachher Diese Anfrage liefert den Inhalt des Wurzelknotens des Binärbaums.<br />
Auftrag setLeftTree (BinTree pTree)<br />
vorher Der Binärbaum ist nicht leer.<br />
nachher Die Wurzel hat den übergebenen Baum als linken Teilbaum.<br />
Auftrag setRightTree (BinTree pTree)<br />
vorher Der Binärbaum ist nicht leer.<br />
nachher Die Wurzel hat den übergebenen Baum als rechten Teilbaum.<br />
Anfrage getLeftTree(): BinTree<br />
vorher Der Binärbaum ist nicht leer.<br />
nachher Diese Anfrage liefert den linken Teilbaum der Wurzel des Binärbaums. Der<br />
Binärbaum ist unverändert.<br />
Anfrage getRightTree(): BinTree<br />
vorher Der Binärbaum ist nicht leer.<br />
nachher Diese Anfrage liefert den rechten Teilbaum der Wurzel des Binärbaums. Der<br />
Binärbaum ist unverändert.<br />
Lösung:<br />
Aufgabe 2:<br />
Baumstrukturen<br />
a) 100g⋅20mm⋅9,81m/s 2 = 200g⋅100mm⋅9,81m/s 2 und<br />
1200g⋅10mm⋅9,81m/s 2 = 300g⋅40mm⋅9,81m/s 2<br />
b) verschiedene Lösungen sind denkbar…<br />
c) und d)
e) public void beispiel() {<br />
Anhaenger a1 = new Anhaenger(1200);<br />
Anhaenger a2 = new Anhaenger(100);<br />
Anhaenger a3 = new Anhaenger(200);<br />
Stange s1 = new Stange(10,40);<br />
Stange s2 = new Stange(20,10);<br />
tree = new BinTree(s1,<br />
new BinTree(a1),<br />
new BinTree(s2,<br />
new BinTree(a2),<br />
new BinTree(a3)<br />
)<br />
);<br />
}<br />
f) private int gesamtmasse(BinTree b) {<br />
if (b.isEmpty()) {<br />
return 0;<br />
} else {<br />
if (b.getRootItem() instanceof Anhaenger) {<br />
return ((Anhaenger)b.getRootItem()).getGewicht();<br />
} else {<br />
if (b.getRootItem() instanceof Stange) {<br />
return gesamtmasse(b.getLeftTree()) +<br />
gesamtmasse(b.getRightTree());<br />
} else {<br />
throw new RuntimeException("Kein Mobilebaum!");<br />
}<br />
}<br />
}<br />
}<br />
public int gesamtmasse() {<br />
try {<br />
return gesamtmasse(tree);<br />
} catch (Exception e) {<br />
System.err.println(e.toString());<br />
return -1;<br />
}<br />
}
g) Die Methode überprüft, ob sich das gesamte Mobile im Gleichgewicht befindet. Dazu<br />
werden zwei Fälle unterschieden:<br />
1. Besteht das Mobile nur aus einem Anhänger, so befindet sich das Mobile natürlich im<br />
Gleichgewicht.<br />
2. Ist das Mobile eine Stange, so wird zunächst geprüft, ob sich das Mobile am aktuellen<br />
Knoten im Gleichgewicht befindet (gesamtmasse*laenge auf beiden Seiten gleich).<br />
Anschließend wird noch geprüft, ob sich die beiden Teilmobiles, die links und rechts an<br />
der Stange hängen, ebenfalls im Gleichgewicht befinden. Ist dies der Fall, so befindet<br />
sich das gesamte Mobile im Gleichgewicht, andernfalls nicht.<br />
h) public Mobile() {<br />
tree = new BinTree();<br />
}<br />
public Mobile(int gewicht) {<br />
tree = new BinTree(new Anhaenger(gewicht));<br />
}<br />
public Mobile(Mobile m1, Mobile m2, int l1, int l2) {<br />
Stange stange = new Stange(l1, l2);<br />
tree = new BinTree(stange, m1.getTree(), m2.getTree());<br />
}
Aufgabe 2:<br />
Binärbäume<br />
Im Morsealphabet ist jeder Buchstabe durch eine Aneinanderreihung von Punkten (·) und<br />
Strichen (-) codiert. Die Codierung der Buchstaben lautet wie folgt:<br />
Morsealphabet<br />
A ·- B -·· C -·-· D -··· E · F ··-· G --· H ···· I ·· J ·--- K -·- L ·-·· M –-<br />
N -· O --- P ·--· Q --·- R ·-· S ··· T - U ··- V ···- W ·-- X -··- Y -·-- Z --··<br />
Eine Möglichkeit, den Morse-Code zu verwalten, ist die Speicherung der Codes in einem<br />
Binärbaum. Der Morsepunkt bewirkt dabei eine Verzweigung nach<br />
links, der Morsestrich eine Verzweigung nach rechts. In jedem<br />
Knoten des Baumes steht der Buchstabe, der durch den im Baum<br />
vorausgegangenen Punkt-Strich-Code repräsentiert wird.<br />
a) Stellen Sie den Morsecode wie oben beschrieben als Baum dar.<br />
Der Pfad zum Buchstaben R müsste in Ihrem Baum wie rechts<br />
abgebildet aussehen.<br />
b) Übersetzen Sie den folgenden Morsetext. Die |-Zeichen trennen die<br />
einzelnen Buchstaben.<br />
-|---|·-··|·-··|·|-·-|·-··|·-|··-|···|··-|·-·<br />
...<br />
R<br />
−<br />
•<br />
•<br />
...<br />
...<br />
c) Beschreiben Sie, wie man algorithmisch vorgeht, wenn man einen Text mit Hilfe des<br />
Baumes übersetzen möchte.<br />
d) Begründen Sie, warum eine Trennung der einzelnen Buchstaben (hier durch das<br />
Zeichen | ) erforderlich ist.<br />
Folgende Datenstruktur soll im folgenden für die Speicherung des Morsebaumes verwendet<br />
werden:<br />
Die Morsecodes der Buchstaben 'A' bis 'Z' sind dabei im Datenfeld codeTabelle wie folgt<br />
gespeichert:<br />
private static String[] codeTabelle = {<br />
".-","-..","-.-.","-...",".","..-.","--.","....","..",".---","-.-",".-..","--",<br />
"-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."<br />
};<br />
e) Analysieren Sie die folgende Methode, d. h., erläutern Sie ihre Arbeitsweise, indem Sie die<br />
wesentlichen Zeilen bzw. Abschnitte kommentieren, und erläutern Sie kurz die zentrale<br />
Funktionalität der Methode.
Hinweis: Objekte der Klasse Character enthalten lediglich ein Datenfeld vom Typ char,<br />
welches mithilfe der Methode char charValue() geholt werden kann.<br />
1<br />
2<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
9<br />
10<br />
11<br />
12<br />
13<br />
14<br />
15<br />
16<br />
17<br />
18<br />
19<br />
private void xxx() {<br />
this.baum = new BinTree();<br />
BinTree hilf;<br />
for (char buchstabe = 'A'; buchstabe
Anfrage isEmpty(): boolean<br />
nachher Diese Anfrage liefert den Wahrheitswert true, wenn der Binärbaum leer ist, sonst<br />
liefert sie den Wert false.<br />
Auftrag clear()<br />
nachher Der Binärbaum ist leer.<br />
Auftrag setRootItem (Object pObject)<br />
nachher Die Wurzel hat – unabhängig davon, ob der Binärbaum leer ist oder schon eine<br />
Wurzel hat – pObject als Inhalt. Eventuell vorhandene Teilbäume werden nicht<br />
geändert.<br />
Anfrage getRootItem(): Object<br />
vorher Der Binärbaum ist nicht leer.<br />
nachher Diese Anfrage liefert den Inhalt des Wurzelknotens des Binärbaums.<br />
Auftrag setLeftTree (BinTree pTree)<br />
vorher Der Binärbaum ist nicht leer.<br />
nachher Die Wurzel hat den übergebenen Baum als linken Teilbaum.<br />
Auftrag setRightTree (BinTree pTree)<br />
vorher Der Binärbaum ist nicht leer.<br />
nachher Die Wurzel hat den übergebenen Baum als rechten Teilbaum.<br />
Anfrage getLeftTree(): BinTree<br />
vorher Der Binärbaum ist nicht leer.<br />
nachher Diese Anfrage liefert den linken Teilbaum der Wurzel des Binärbaums. Der<br />
Binärbaum ist unverändert.<br />
Anfrage getRightTree(): BinTree<br />
vorher Der Binärbaum ist nicht leer.<br />
nachher Diese Anfrage liefert den rechten Teilbaum der Wurzel des Binärbaums. Der<br />
Binärbaum ist unverändert.<br />
Lösung:<br />
Aufgabe 2:<br />
Binärbäume<br />
a) Der Morsebaum hat folgende Struktur:<br />
b) Der Text lautet: TOLLEKLAUSUR<br />
c) Initialisiere den Klartext mit einer leeren Zeichenkette<br />
Lies den Morsetext Zeichen für Zeichen.<br />
Liest man das Zeichen | so<br />
Erweitere den Klartext um das Zeichen im aktuellen Knoten des Baums
Starte wieder an der obersten Wurzel Morsebaums.<br />
Liest man das Zeichen . so<br />
Gehe im Morsebaum nach links runter<br />
Liest man das Zeichen – so<br />
Gehe im Morsebaum nach rechts runter<br />
d) Die Trennungszeichen sind nötig, da man sonst z. B. den Morsecode "---" als den<br />
Buchstaben O aber auch als dreimal den Buchstaben T interpretieren könnte.<br />
e) Die Methode xxx erstellt zunächst einen leeren Binärbaum.<br />
Für alle Buchstaben von A bis Z wird jedes mal am Anfang des (zu Anfang leeren)<br />
Binärbaums gestartet. In der Variablen morsecode steht der zum Zeichen zugehörige<br />
Morsecode.<br />
Ist der Baum noch leer, so wird zunächst eine Wurzel mit unbekanntem Zeichen angelegt.<br />
Danach wird je nach aktuellem Zeichen des zum Buchstaben zugehörigen Morsecodes im<br />
Binärbaum nach links oder rechts verzweigt.<br />
Hat man den ganzen Morsecode abgearbeitet (Ende der for-Schleife), so kann in die<br />
Wurzel des aktuellen Knotens der aktuelle Buchstabe geschrieben werden. Evtl. wird<br />
dabei ein unbekanntes Zeichen aus einem vorherigen Schleifendurchlauf überschrieben.<br />
Die Methode baut den Morsecode für alle Buchstaben von A bis Z auf.<br />
f) public String klarToMorse(char klar) {<br />
klar = Character.toUpperCase(klar);<br />
if (klar >= 'A' && klar