diff --git a/AuD/src/UEB06/Baum.java b/AuD/src/UEB06/Baum.java new file mode 100644 index 0000000..330572b --- /dev/null +++ b/AuD/src/UEB06/Baum.java @@ -0,0 +1,409 @@ +package UEB06; + +public class Baum> +{ + private Knoten wurzel; + + // Wird nur f�r grafische Oberfl�che ben�tigt, ohne + // diese Methode k�nnte die gesamte Implementierung + // des Baumes geheim gehalten werden. Alle �ffentlichen + // Methoden sind parameterlos oder besitzen als + // einzigen Parameter einen Schl�sselwert + public Knoten getWurzel() + { + return wurzel; + } + + public boolean istLeer() + { + return (wurzel == null); + } + + public void attach(Knoten einKnoten) + { + wurzel = einKnoten; + } + + +// Methoden zum Suchen + + public boolean suchen(final T daten) + { + return istLeer() ? false : suchenKnoten(daten, wurzel); + // Effiziente Kurzform f�r: + // if (istLeer()) { return false; } else { return suchenKnoten(daten, wurzel); } + } + + private boolean suchenKnoten(final T daten, Knoten teilbaum) + { + if (teilbaum == null) + return false; + + // Vergleichs-Ergebnis zwischenspeichern, da compareTo() + // aufw�ndig sein kann, und das Ergebnis mehrfach ben�tigt + // wird + final int cmp = daten.compareTo(teilbaum.getDaten()); + + return (cmp == 0) ? true : suchenKnoten(daten, (cmp < 0) ? teilbaum.getKnotenLinks() : teilbaum.getKnotenRechts()); + // Effiziente Kurzform f�r: + // if (cmp == 0) { return true; } + // else if (cmp < 0) { return suchenKnoten(daten, teilbaum.getKnotenLinks()); } + // else { return suchenKnoten(daten, teilbaum.getKnotenRechts()); } + } + + +// Methoden zum Einf�gen + + public void einfuegen(final T daten) + { + if (istLeer()) + { + // Sonderfall, analog zu verketteten Listen + wurzel = new Knoten(daten, null, null); + } + else + { + einfuegenKnoten(daten, wurzel); + } + } + + // Generiert einen neuen Knoten mit �bergebenen Daten und f�gt + // ihn (die Suchbaumeigenschaft erhaltend) als Blatt in den + // Baum ein, sofern die Daten noch nicht vorhanden sind. + private void einfuegenKnoten(final T daten, Knoten teilbaum) + { + // Vergleichs-Ergebnis zwischenspeichern, da compareTo() + // aufw�ndig sein kann, und das Ergebnis mehrfach ben�tigt + // wird + final int cmp = daten.compareTo(teilbaum.getDaten()); + + // Daten schon vorhanden? + // Falls ja: alles erledigt! + if (cmp == 0) + return; + + if (cmp < 0) + { + // Einzuf�gende Daten sind KLEINER als Daten im aktuellen Knoten + // und m�ssen daher im LINKEN Teilbaum eingef�gt werden + if (teilbaum.getKnotenLinks() == null) + { + // Es gibt keinen linken Teilbaum -> neuen Knoten erzeugen + teilbaum.setKnotenLinks(new Knoten(daten, null, null)); + } + else + { + // Es existiert ein linker Teilbaum -> rekursiv weiter + einfuegenKnoten(daten, teilbaum.getKnotenLinks()); + } + } + else + { + // Einzuf�gende Daten sind GROESSER als Daten im aktuellen Knoten + // und m�ssen daher im RECHTEN Teilbaum eingef�gt werden + if (teilbaum.getKnotenRechts() == null) + { + // Es gibt keinen rechten Teilbaum -> neuen Knoten erzeugen + teilbaum.setKnotenRechts(new Knoten(daten, null, null)); + } + else + { + // Es existiert ein rechter Teilbaum -> rekursiv weiter + einfuegenKnoten(daten, teilbaum.getKnotenRechts()); + } + } + } + + +// Methoden zum Entfernen + + public void entfernen(final T daten) + { + // Leerer Baum? + // Falls ja, gibt es nicht zu entfernen! + if (istLeer()) + return; + + // Vergleichs-Ergebnis zwischenspeichern, da compareTo() + // aufw�ndig sein kann, und das Ergebnis mehrfach ben�tigt + // wird + final int cmp = daten.compareTo(wurzel.getDaten()); + + if (cmp == 0) + { + // Der Wurzel-Knoten muss entfernt werden! + // Sonderfall, analog zu verketteten Listen + entfernenWurzel(); + } + else + if (cmp < 0) + { + // Zu l�schende Daten kleiner als Daten in Wurzel; + // im linken Teilbaum weitersuchen falls existent + if (wurzel.getKnotenLinks() != null) + entfernenKnoten(daten, wurzel, wurzel.getKnotenLinks(), true); + } + else + { + // Zu l�schende Daten gr��er als Daten in Wurzel; + // im rechten Teilbaum weitersuchen falls existent + if (wurzel.getKnotenRechts() != null) + entfernenKnoten(daten, wurzel, wurzel.getKnotenRechts(), false); + } + } + + private void entfernenWurzel() + { + if (wurzel.getKnotenLinks() == null) + { + // Wurzel hat h�chstens einen rechten Nachfolger. + // Der wird zur neuen Wurzel! + wurzel = wurzel.getKnotenRechts(); + } + else + if (wurzel.getKnotenRechts() == null) + { + // Wurzel hat h�chstens einen linken Nachfolger. + // Der wird zur neuen Wurzel! + wurzel = wurzel.getKnotenLinks(); + } + else + { + // Rechter und linker Teilbaum nicht leer; zwei Nachfolger. + // Wurzel durch gr��ten Knoten im linken Teilbaum ersetzen! + ersetzeKnoten(wurzel); + } + } + + // Sofern �bergebene Daten im Teilbaum vorhanden sind, werden sie gel�scht. + // Elternknoten wird ben�tigt, da dessen rechter bzw. linker Nachfolger ggf. auf + // den rechten bzw. linken Nachfolger des zu l�schenden Knotens umgesetzt werden muss + // Ist linkerTeilbaum == true, wurde der linke Nachfolger des Elternknotens �bergeben, + // sonst der rechte. Wird ben�tigt, um zu entscheiden, ob der linke oder rechte + // Nachfolger des Elternknotens ge�ndert werden muss. + private void entfernenKnoten(final T daten, Knoten elternknoten, Knoten teilbaum, final boolean linkerTeilbaum) + { + // Vergleichs-Ergebnis zwischenspeichern, da compareTo() + // aufw�ndig sein kann, und das Ergebnis mehrfach ben�tigt + // wird + final int cmp = daten.compareTo(teilbaum.getDaten()); + + if (cmp == 0) + { + // Der Knoten mit den zu l�schenden Daten wurde gefunden + if (teilbaum.getKnotenLinks() == null) + { + // Zu l�schender Knoten hat h�chstens einen rechten Nachfolger. + // Auf diesen vom Elternknoten aus verweisen! + if (linkerTeilbaum) + { + elternknoten.setKnotenLinks(teilbaum.getKnotenRechts()); + } + else + { + elternknoten.setKnotenRechts(teilbaum.getKnotenRechts()); + } + } + else + if (teilbaum.getKnotenRechts() == null) + { + // Zu l�schender Knoten hat h�chstens einen linken Nachfolger. + // Auf diesen vom Elternknoten aus verweisen! + if (linkerTeilbaum) + { + elternknoten.setKnotenLinks(teilbaum.getKnotenLinks()); + } + else + { + elternknoten.setKnotenRechts(teilbaum.getKnotenLinks()); + } + } + else + { + // Rechter und linker Teilbaum nicht leer; zwei Nachfolger! + // Zu l�schenden Knoten durch gr��ten Knoten im linken Teilbaum ersetzten + ersetzeKnoten(teilbaum); + } + } + else + if (cmp < 0) + { + // Zu l�schende Daten kleiner als Daten im aktuellen Knoten; + // im linken Teilbaum weitersuchen falls existent + if (teilbaum.getKnotenLinks() != null) + entfernenKnoten(daten, teilbaum, teilbaum.getKnotenLinks(), true); + } + else + { + // Zu l�schende Daten gr��er als Daten im aktuellen Knoten; + // im rechten Teilbaum weitersuchen falls existent + if (teilbaum.getKnotenRechts() != null) + entfernenKnoten(daten, teilbaum, teilbaum.getKnotenRechts(), false); + } + } + + // Ersetzt zu l�schenden Knoten durch gr��ten Knoten im linken Teilbaum, + // indem Daten des gr��ten Knotens in zu l�schenden Knoten kopiert werden. + // Vom Elternknoten des gr��ten Knotens aus muss auf den linken Teilbaum + // des gr��ten Knotens verwiesen werden. Der rechten Teilbaum des gr��ten + // Knotens ist immer leer (Def. gr��ter Knoten) + private void ersetzeKnoten(Knoten zuLoeschenderKnoten) + { + // Gr��ten Knoten suchen; dessen rechter Nachfolger ist null. + // Daher kann rechter Nachfolger des zu l�schenden Knotens �bernommen werden. + Knoten elternknoten = zuLoeschenderKnoten; + Knoten teilbaum = zuLoeschenderKnoten.getKnotenLinks(); + Knoten groessterKnoten = teilbaum; + + while (teilbaum.getKnotenRechts() != null) + { + elternknoten = teilbaum; + teilbaum = teilbaum.getKnotenRechts(); + groessterKnoten = teilbaum; + } + + // Daten des gr��ten Knotens werden in zu l�schenden Knoten kopiert + zuLoeschenderKnoten.setDaten(groessterKnoten.getDaten()); + + if (elternknoten == zuLoeschenderKnoten) // Gr��ter Knoten ist Wurzel des linken Teilbaums des zu L�schenden + { + // Zu l�schender Knoten ist gleichzeitig Elternknoten des gr��ten Knotens + // Rechter Teilbaum des zu l�schenden Knotens muss erhalten bleiben + // Linken Teilbaum des zu loeschenden Knotens auf linken Teilbaum des gr��ten Knotens setzen + // Das sind die einzigen Nachfolger des gr��ten Knotens, da dessen rechter Teilbaum ja + // immer leer ist. + zuLoeschenderKnoten.setKnotenLinks(groessterKnoten.getKnotenLinks()); + } + else + { + // Rechten, freiwerdenden Teilbaum des Elternknotens des gr��ten Knotens + // auf linken Teilbaum des gr��ten Knotens setzen + // Das sind die einzigen Nachfolger des gr��ten Knotens, da dessen rechter Teilbaum ja + // immer leer ist. + elternknoten.setKnotenRechts(groessterKnoten.getKnotenLinks()); + } + } + + +// Methoden zum Traversieren + + // Pre-Order + public String traversierePreOrder() + { + return (wurzel != null) ? traversierePreOrder(wurzel) : "Der Baum ist leer."; + } + + private String traversierePreOrder(final Knoten einKnoten) + { + assert(einKnoten != null); + + String nodes = ""; + nodes += einKnoten.getDaten(); + + if(einKnoten.getKnotenLinks() != null){ + nodes += traversierePreOrder(einKnoten.getKnotenLinks()); + } + + + if(einKnoten.getKnotenRechts() != null){ + nodes += traversierePreOrder(einKnoten.getKnotenRechts()); + } + + + return nodes; + } + + + // In-Order + public String traversiereInOrder() + { + return (wurzel != null) ? traversiereInOrder(wurzel) : "Der Baum ist leer."; + } + + private String traversiereInOrder(final Knoten einKnoten) + { + String nodes = ""; + assert(einKnoten != null); + + + if(einKnoten.getKnotenLinks() != null){ + nodes += traversiereInOrder(einKnoten.getKnotenLinks()); + } + + nodes += einKnoten.getDaten(); + + if(einKnoten.getKnotenRechts() != null){ + nodes += traversiereInOrder(einKnoten.getKnotenRechts()); + } + + return nodes; + } + + + + +// public String traversiereInOrder() +// { +// return (wurzel != null) ? traversiereInOrder(wurzel,"") : "Der Baum ist leer."; +// } +// +// private String traversiereInOrder(final Knoten einKnoten, String nodes) +// { +// assert(einKnoten != null); +// +// +// if(einKnoten.getKnotenLinks() != null){ +// nodes = traversiereInOrder(einKnoten.getKnotenLinks(),nodes); +// } +// +// nodes += einKnoten.getDaten(); +// +// if(einKnoten.getKnotenRechts() != null){ +// nodes = traversiereInOrder(einKnoten.getKnotenRechts(),nodes); +// } +// +// return nodes; +// } + + + // Post-Order + public String traversierePostOrder() + { + return (wurzel != null) ? traversierePostOrder(wurzel) : "Der Baum ist leer."; + } + + private String traversierePostOrder(final Knoten einKnoten) + { + assert(einKnoten != null); + String nodes = ""; + if(einKnoten.getKnotenLinks() != null){ + nodes += traversierePostOrder(einKnoten.getKnotenLinks()); + } + + + if(einKnoten.getKnotenRechts() != null){ + nodes += traversierePostOrder(einKnoten.getKnotenRechts()); + } + + nodes += einKnoten.getDaten(); + + + return nodes; + } + + +// Methoden zur Bestimmung der H�he + + public int hoehe() + { + return hoeheRek(wurzel); + } + + private int hoeheRek(final Knoten einKnoten) + { + + + + return -1; + } +} \ No newline at end of file diff --git a/AuD/src/UEB06/BaumAnsicht.java b/AuD/src/UEB06/BaumAnsicht.java new file mode 100644 index 0000000..b75e3f5 --- /dev/null +++ b/AuD/src/UEB06/BaumAnsicht.java @@ -0,0 +1,41 @@ +package UEB06; + +import java.awt.*; + +public class BaumAnsicht +{ + private Baum einBaum; + + public BaumAnsicht(Baum einBaum) + { + this.einBaum = einBaum; + } + + public void ausgeben(int xLinks, int xRechts, int y, Graphics g) + { + g.setColor(new Color(240, 240, 240)); + g.fillRect(xLinks, 100, xRechts, 190); + + ausgebenTeilbaum(einBaum.getWurzel(), -1, -1, xLinks, xRechts, y, g); + } + + public void ausgebenTeilbaum(Knoten teilbaum, int xParent, int yParent, int xLinks, int xRechts, int y, Graphics g) + { + if (teilbaum != null) + { + final int mitte = (xLinks + xRechts) / 2; + + g.setColor(Color.black); + g.drawString(teilbaum.toString(), mitte - 2, y); + + if ((xParent != -1) && (yParent != -1)) + { + g.setColor(new Color(192, 192, 192)); + g.drawLine(xParent, yParent, mitte, y-12); + } + + ausgebenTeilbaum(teilbaum.getKnotenLinks(), mitte, y + 4, xLinks + 4, mitte - 4, y + 30, g); + ausgebenTeilbaum(teilbaum.getKnotenRechts(), mitte, y + 4, mitte + 4, xRechts + 4, y + 30, g); + } + } +} \ No newline at end of file diff --git a/AuD/src/UEB06/BaumGUI.java b/AuD/src/UEB06/BaumGUI.java new file mode 100644 index 0000000..702ef66 --- /dev/null +++ b/AuD/src/UEB06/BaumGUI.java @@ -0,0 +1,200 @@ +package UEB06; + +import java.awt.*; +import java.applet.*; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + + +public class BaumGUI extends Frame +{ + private Baum einBaum; + private BaumAnsicht eineBaumAnsicht; + + private java.awt.Label zeichenFuehrungstext = new java.awt.Label(); + private java.awt.TextField zeichenTextfeld = new java.awt.TextField(); + private java.awt.Button suchenDruckknopf = new java.awt.Button(); + private java.awt.Button einfuegenDruckknopf = new java.awt.Button(); + private java.awt.Button entfernenDruckknopf = new java.awt.Button(); + private java.awt.Button demoDruckknopf = new java.awt.Button(); + private java.awt.Checkbox enthaltenKontrollkaestchen = new java.awt.Checkbox(); + private java.awt.Label infoLabel = new java.awt.Label(); + private java.awt.Button traversierenDruckknopf = new java.awt.Button(); + private java.awt.TextArea ausgabeTextfeld = new java.awt.TextArea("",0,0,TextArea.SCROLLBARS_NONE); + + public BaumGUI() + { + setLayout(null); + setSize(530,505); + zeichenFuehrungstext.setText("Zeichen:"); + zeichenFuehrungstext.setAlignment(java.awt.Label.RIGHT); + add(zeichenFuehrungstext); + zeichenFuehrungstext.setBounds(12,32,48,24); + add(zeichenTextfeld); + zeichenTextfeld.setBounds(72,32,48,24); + suchenDruckknopf.setLabel("Suchen"); + add(suchenDruckknopf); + suchenDruckknopf.setBackground(java.awt.Color.lightGray); + suchenDruckknopf.setBounds(132,32,84,24); + einfuegenDruckknopf.setLabel("Einf�gen"); + add(einfuegenDruckknopf); + einfuegenDruckknopf.setBackground(java.awt.Color.lightGray); + einfuegenDruckknopf.setBounds(228,32,84,24); + entfernenDruckknopf.setLabel("Entfernen"); + add(entfernenDruckknopf); + entfernenDruckknopf.setBackground(java.awt.Color.lightGray); + entfernenDruckknopf.setBounds(324,32,84,24); + demoDruckknopf.setLabel("Demo-Baum"); + add(demoDruckknopf); + demoDruckknopf.setBackground(java.awt.Color.lightGray); + demoDruckknopf.setBounds(418,32,84,24); + enthaltenKontrollkaestchen.setLabel("Im Baum enthalten"); + enthaltenKontrollkaestchen.setEnabled(false); + add(enthaltenKontrollkaestchen); + enthaltenKontrollkaestchen.setBounds(132,68,132,24); + add(infoLabel); + infoLabel.setBounds(14,292,500,20); + traversierenDruckknopf.setLabel("Traversieren"); + add(traversierenDruckknopf); + traversierenDruckknopf.setBackground(java.awt.Color.lightGray); + traversierenDruckknopf.setBounds(14,320,127,26); + add(ausgabeTextfeld); + ausgabeTextfeld.setBounds(14,350,500,144); + + AktionsAbhoerer einAktionsAbhoerer = new AktionsAbhoerer(); + suchenDruckknopf.addActionListener(einAktionsAbhoerer); + einfuegenDruckknopf.addActionListener(einAktionsAbhoerer); + entfernenDruckknopf.addActionListener(einAktionsAbhoerer); + demoDruckknopf.addActionListener(einAktionsAbhoerer); + TastaturAbhoerer einTastaturAbhoerer = new TastaturAbhoerer(); + zeichenTextfeld.addKeyListener(einTastaturAbhoerer); + traversierenDruckknopf.addActionListener(einAktionsAbhoerer); + + addWindowListener( + new WindowAdapter() + { + public void windowClosing(WindowEvent event) + { + setVisible(false); + dispose(); + System.exit(0); + } + } + ); + + einBaum = new Baum(); + eineBaumAnsicht = new BaumAnsicht(einBaum); + + updateBaumInfo(); + } + + public void paint(Graphics g) + { + eineBaumAnsicht.ausgeben(15, 500, 120, g); + } + + public void updateBaumInfo() + { + final int h = einBaum.hoehe(); + + infoLabel.setText("Der Baum hat eine H�he von " + h + "."); + } + + // Innere Klassen + class AktionsAbhoerer implements java.awt.event.ActionListener + { + public void actionPerformed(java.awt.event.ActionEvent event) + { + Object object = event.getSource(); + if ((object == einfuegenDruckknopf) || (object == entfernenDruckknopf) || (object == suchenDruckknopf)) + { + String text = zeichenTextfeld.getText(); + if ((text != null) && (text.length() > 0)) + { + char zeichen = text.charAt(0); + + if (object == einfuegenDruckknopf) + { + einBaum.einfuegen(zeichen); + zeichenTextfeld.setText(""); + repaint(); + updateBaumInfo(); + } + else + if (object == entfernenDruckknopf) + { + einBaum.entfernen(zeichen); + repaint(); + updateBaumInfo(); + } + else + if (object == suchenDruckknopf) + { + enthaltenKontrollkaestchen.setState(einBaum.suchen(zeichen)); + } + } + } + else + if (object == traversierenDruckknopf) + { + ausgabeTextfeld.setText("Pre-Order:\n"); + ausgabeTextfeld.append(einBaum.traversierePreOrder()); + ausgabeTextfeld.append("\n\nIn-Order:\n"); + ausgabeTextfeld.append(einBaum.traversiereInOrder()); + ausgabeTextfeld.append("\n\nPost-Order:\n"); + ausgabeTextfeld.append(einBaum.traversierePostOrder()); + } + else + if (object == demoDruckknopf) + { + System.out.println("XXX"); + einBaum.attach( + new Knoten('E', + new Knoten('D', + new Knoten('A', + null, + null), + null), + new Knoten('S', + new Knoten('O', + null, + new Knoten('P', + null, + new Knoten('R', + new Knoten('Q', + null, + null), + null))), + new Knoten('Z', + null, + null)))); + + repaint(); + updateBaumInfo(); + } + } + } + + class TastaturAbhoerer extends java.awt.event.KeyAdapter + { + public void keyReleased(java.awt.event.KeyEvent event) + { + if (event.getSource() == zeichenTextfeld) + { + String text = zeichenTextfeld.getText(); + if ((text != null) && (text.length() > 0)) + { + char zeichen = text.charAt(0); + + if (event.getKeyCode() == java.awt.event.KeyEvent.VK_ENTER) + { + einBaum.einfuegen(zeichen); + zeichenTextfeld.setText(""); + repaint(); + } + } + } + } + } +} + diff --git a/AuD/src/UEB06/BaumTest.java b/AuD/src/UEB06/BaumTest.java new file mode 100644 index 0000000..d400bfa --- /dev/null +++ b/AuD/src/UEB06/BaumTest.java @@ -0,0 +1,9 @@ +package UEB06; + +public class BaumTest +{ + public static void main(String[] args) + { + new BaumGUI().setVisible(true); + } +} \ No newline at end of file diff --git a/AuD/src/UEB06/Knoten.java b/AuD/src/UEB06/Knoten.java new file mode 100644 index 0000000..2c6ea15 --- /dev/null +++ b/AuD/src/UEB06/Knoten.java @@ -0,0 +1,50 @@ +package UEB06; + +public class Knoten +{ + private T daten; + private Knoten teilbaumLinks; + private Knoten teilbaumRechts; + + public Knoten(T daten, Knoten teilbaumLinks, Knoten teilbaumRechts) + { + this.daten = daten; + this.teilbaumLinks = teilbaumLinks; + this.teilbaumRechts = teilbaumRechts; + } + + public T getDaten() + { + return daten; + } + + public Knoten getKnotenLinks() + { + return teilbaumLinks; + } + + public Knoten getKnotenRechts() + { + return teilbaumRechts; + } + + public void setDaten(T daten) + { + this.daten = daten; + } + + public void setKnotenLinks(Knoten teilbaumLinks) + { + this.teilbaumLinks = teilbaumLinks; + } + + public void setKnotenRechts(Knoten teilbaumRechts) + { + this.teilbaumRechts = teilbaumRechts; + } + + public String toString() + { + return this.daten.toString(); + } +} \ No newline at end of file