7.3


Ein bisschen unglücklich bin ich noch mit:

public Binaerbaum(BinaerbaumInterface<Type> left,
				Type value, BinaerbaumInterface<Type> right)
public BinaerbaumInterface<Type> left();
public BinaerbaumInterface<Type> right();

Das heißt ja, das mischen von Typen in einem Binärbaum ist unmöglich, obwohl die Axiome meiner Meinung nach darüber ja keine Aussage treffen.

BinaerbaumInterface<String> eins = new Binaerbaum<String>(null, "eins", null);
BinaerbaumInterface<Integer> zwei = new Binaerbaum<Integer>(eins, 2, null);

Ergibt den Fehler:

The constructor Binaerbaum<Integer>(BinaerbaumInterface<String>, int, null) is undefined

Soll der Baum also wirklich an einen Typ gebunden sein?


Wer sagt das? :wink:


Das sag ich, mit der Begründung, dass es das am einfachsten zu verwirklichende aufgabenstellungskonforme Verhalten ist (ein Dreizeiler: if (v!=null) println(…v.toString()…); if (left!=null) left.traverse(n+1); if (right!=null) right.traverse(n+1); ) und jedes speziellere Verhalten in der Aufgabenstellung weiter hätte spezifiziert werden müssen.


Anscheinend wollte man in der Aufgabe unbedingt ein neues feature von Java1.5 verwenden, welches man übrigens in C++ bereits seit 16 Jahren unter dem Begriff „template“ kennt. :wink:
Eine Möglichkeit, beliebige Typen in einem Baum/Liste zu speichern ist, die Tatsache auszunutzen, dass sämtliche Objekte von der Klasse „Object“ erben; also Type=Object. Für einen späteren Zugriff (welcher über toString() hinausgeht) muss man sie dann aber richtig casten, was einen verwaltungstechnischen Mehraufwand bedeutet. In der Realität ist es wohl sehr unüblich, Objekte völlig verschiedenen Typs in einem Baum speichern zu wollen.
Wenn man z.B. Hunde, Katzen und Mäuse in einem Baum speichern will, dann würde man wohl wählen: Type=Tier. Bei Bäumen und Listen geht es ja letztendlich darum, Dinge zu speichern, welche gemeinsame Eigenschaften haben (um sie z.B. zu sortieren), welche üblicherweise durch eine gemeinsame Oberklasse oder ein gemeinsames Interface gegeben sind.


Jap, unter Java ist es aber typsicher ;D


Also, Marc Wöhrlein, was soll denn nun passieren bei traverse(2536536)…


Wörlein bitte


Eine prinzipielle Eigenschaft der generischen Programmierung ist Typsicherheit - egal ob C++ oder Java.


Nur ist C++ eben nicht streng getypt.


Was meinst du mit streng getypt?


mit “streng getypt” meine ich:

wenn das Programm erfolgreich uebersetzt wurde, werde alle Typfehler zur Laufzeit bemerkt


a) “null” ist kein Binärbaum, von daher ist in der Aufgabe
BinaerbaumInterface eins = new Binaerbaum(null, “eins”, null);
nicht unbedingt gewollt.
b) traverse(2536536) geht davon aus, das der Teilbaum auf der Tiefe 2536536 beginnt.
c) ja, das mit der private traverse(int); und public traverse(); Methode wäre vielleicht eine besserer Modelierung gewesen, aber dann hätte ich bestimmt wieder tonnen von nachfragen bekommen, was denn der Unterschied ziwschen diesen beiden Methoden ist. Deswegen diesmal nur eine :wink:


das ist doch dann eh sache des testcase oder nicht?


Marc hat übrigens vor zwei Stunden klammheimlich in BinaerbaumInterface.java folgendes von

/*public BinaerbaumInterface(SimpleBinaerbaumInterface<Type> left,
 *             Type value, SimpleBinaerbaumInterface<Type> right);*/

in

/*public BinaerbaumInterface(BinaerbaumInterface<Type> left,
 *             Type value, BinaerbaumInterface<Type> right);*/

geändert.

Vielleicht schafft er es ja noch, dass es auf dem Übungsblatt auch noch in einer konsistenten Form auftaucht. Momentan heißt es noch:


Es spricht übrigens nichts dagegen, dass ihr eine [m]public traverse()[/m] implementiert, auch wenn sie nicht explizit gefordert ist. Schöner ist es damit auf jeden Fall, man kann dann halt einfach [m]irgendeinBaum.traverse()[/m] aufrufen.


Meinst du reinzufällig vielleicht eher (oder auch), dass new Binaerbaum(foo, null, bar); nicht gewollt ist?
Ohne null-Verweise (auf nichtexistente Kinder) wäre doch jeder Baum unendlich groß.

Selbst die Alternative new Binaerbaum(new Binaerbaum(), „eins“, new Binaerbaum()) heißt ja nix anderes als zwei Kinder deren Attribute alle null sind, also wieder das was „nicht unbedingt gewollt“ ist.


Ich wollte halt keine Binärbäume, die nur “einen” Nachfogler haben, so wie das halt in der Signatur geschreiben ist.
Es gibt den Leeren baum (create) und dann Bäume die aus zwei Bäumen aufgebaut sind.
“null” ist kein Baum, da man an ihm keine Methoden Aufrufen kann.Wie die Interne Struktur des leeren Baumes aussieht ist egal, da jeder ja nur auf seine nach Signatur erlaubten Methoden zugreifen kann. left(create), right(create), value(create) sind nicht spezifiziert von daher werden sie nicht aufgerufen, aber empty und traverse muss richtig funktionieren.


Das bedeutet wohl, dass man eine boolean-Variable z.B. „empty“ anlegen muss, die beim Constructor Binaerbaum(void) auf true gesetzt wird, ansonsten auf false, welche dann von der Funktion empty() benutzt wird.

Bei so einem Beispiel muss es also klappen:

BinaerbaumInterface<Object> leererBaum = new Binaerbaum<Object>(); BinaerbaumInterface<Object> eins = new Binaerbaum<Object>(leererBaum, 1, leererBaum); BinaerbaumInterface<Object> neun = new Binaerbaum<Object>(leererBaum, 9, leererBaum); BinaerbaumInterface<Object> zwei = new Binaerbaum<Object>(leererBaum, "zwei", leererBaum); BinaerbaumInterface<Object> vier = new Binaerbaum<Object>(zwei, 4.0, leererBaum); BinaerbaumInterface<Object> sieben = new Binaerbaum<Object>(eins, "sieben", neun); BinaerbaumInterface<Object> fuenf = new Binaerbaum<Object>(leererBaum, 5, vier); BinaerbaumInterface<Object> drei = new Binaerbaum<Object>(sieben, 3, fuenf); drei.traverse(0);


bei mir gibt empty true zurück wenns auf dem leeren Baum ausgeführt wird?! Das ist doch wohl gemeint denk ich


Ja du hast Recht, das mit der boolean-Variable ist unnötig.