Übung 3: Die generische Klasse „BinärerSuchbaum“ in Java 1

Werbung
Algorithmen und Datenstrukturen
Übung 3: Die generische Klasse „BinärerSuchbaum“ in Java 1
Datenelemente der Klasse BinaererSuchbaum
Das einzige Datenelelement in dieser Klasse ist die Wurzel vom Typ
BinaerBaumknoten. Die Klasse „BinaerBaumknoten“ ist allgemein sichtbar.
Der binäre Suc hbaum setzt voraus, daß alle Datenelemente der Baumknoten in eine
Ordnungsbeziehung gebracht werden können. Eine generische Klasse für einen
binären Suchbaum erfordert daher ein Interface, das Ordnungsbeziehungen
zwischen Daten eines Datenbestands festlegt. Diese Eigenschaft besitzt das
Interface Comparable
public interface Comparable
{
int compareTo(Comparable rs)
}
Durch die Definition eines Interface wird der zugehörige Referenztyp erzeugt, der wie
andere Datentypen eingesetzt werden kann.
Methoden der Klasse BinaererSuchbaum
Die öffentlich zugänglichen, sichtbaren Methoden rufen private, rekursive Methoden
auf:
Die private Methode „elementAt“ gibt eine Referenz zurück, die auf den Baumknoten verweist, in
dem ein bestimmtes Datenelement gespeichert ist.
Das Auffinden eines Datenelements im binären Suchbaum besorgt: private BinaerBaumknoten
find(Comparable x, BinaerBaumknoten b);
Das Auffinden des größten bzw. kleinsten Datenelements im binären Suchbaum übernehmen:
private BinaerBaumknoten findMax(BinaerBaumknoten b);
private BinaerBaumknoten findMin(BinaerBaumknoten b);
Das Einfügen eines Knoten in den binären Suchbaum übernimmt: private BinaerBaumknoten
insert(Comparable x, BinaerBaumknoten b);
Duplikate können beim Einfügen durch ein spezielles Feld im Baumknoten behandelt werden, das die
doppelten Vorkommen zählt.
Das Löschen eines Baumkoten übernimmt private BinaerBaumknoten remove(Comparable
x, BinaerBaumknoten b);
Beim Entfernen sind 3 Fälle zu unterscheiden:
1. Der zu entfernende Knoten ist ein Blattknoten. Das Entfernen dieses Knoten kann direkt erfolgen.
2. Der zu entfernende Knoten hat einen Nachfolger. Hier wird vom Elternknoten des zu entfernenden
Knoten ein Link auf den Nachfolger des zu entfernenden Knoten gesetzt.
1 Vgl. PR42000
1
Algorithmen und Datenstrukturen
6
2
6
8
1
4
2
8
1
4
3
3
3. Der zu entfernende Knoten hat 2 Nachfolger. Hier könnte eine allgemeine Strategie für das
Entfernen des Knoten so lauten:
- Ersetze den Inhalt des Datenelements durch den Inhalt des kleinsten Datenelements des rechten
Teilbaums. Dieser Baumknoten kann leicht gefunden werden.
- Das Datenelement mit dem kleinsten Inhalt vom rechten Teilbaum des zu entfernenden Baumknoten
ist dann leer, der zugehörige Baumknoten kann deshalb rekursiv entfernt werden. Da der Knoten mit
dem kleinsten Inhalt des Datenelements keine linken Nachfolger besitzt, ist diese Art des Entfernens
einfach
Bsp.: Entfernen des Knotens mit dem Datenelement 2
6
2
6
8
1
5
3
3
8
1
5
3
4
4
Test: Klasse BinaerSuchbaumTest
Aufgaben: Ersetze die rekursiven Methoden durch Methoden, die Iterationen anstatt Rekursionen
verwenden.
2
Algorithmen und Datenstrukturen
Lösungen
// Elementarer Knoten eines binaeren Baums, der nicht ausgeglichen ist
// Der Zugriff auf diese Klasse ist nur innerhalb eines Verzeichnisses
// bzw. Pakets moeglich
class BinaerBaumknoten
{
// Instanzvariable
protected BinaerBaumknoten links;
protected BinaerBaumknoten rechts;
public Comparable daten;
// linker Teilbaum
// rechter Teilbaum
// Dateninhalt der Knoten
// Konstruktor
public BinaerBaumknoten(Comparable datenElement)
{
this(datenElement, null, null );
}
public BinaerBaumknoten(Comparable datenElement,
BinaerBaumknoten l,
BinaerBaumknoten r)
{
daten
= datenElement;
links
= l;
rechts
= r;
}
public BinaerBaumknoten getLinks()
{
return links;
}
public BinaerBaumknoten getRechts()
{
return rechts;
}
}
// Freier binaerer Intervallbaum
// Generische Klasse fuer einen unausgeglichenen binaeren Suchbaum
//
// Konstruktor: Initialisierung der Wurzel mit dem Wert null
//
// **********oeffentlich zugaengliche
Methoden*************************************
// void insert( x )
--> Fuege x ein
// void remove( x )
--> Entferne x
// Comparable find( x )
--> Gib das Element zurueck, das zu x passt
// Comparable findMin( ) --> Rueckgabe des kleinsten Elements
// Comparable findMax( ) --> Rueckgabe des groessten Elements
// boolean isEmpty( )
--> Return true if empty; else false
// void makeEmpty( )
--> Entferne alles
// void printTree( )
--> Ausgabe der Binaerbaum-Elemente in sortierter
Folge
// void ausgBinaerBaum() --> Ausgabe der Binaerbaum-Elemente um 90 Grad
vers.
/*
* Implementiert einen unausgeglichenen binaeren Suchbaum.
* Das Einordnen in den Suchbaum basiert auf der Methode compareTo
*/
public class BinaererSuchbaum
{
3
Algorithmen und Datenstrukturen
// Private Datenelemente
/* Die Wurzel des Baums */
private BinaerBaumknoten root;
// Oeffentlich zugaengliche Methoden
/*
* Konstruktor.
*/
public BinaererSuchbaum()
{
root = null;
}
/*
* Einfuegen eines Elements in den binaeren Suchbaum
* Duplikate werden ignoriert
*/
public void insert( Comparable x )
{
root = insert(x, root);
}
/*
* Entfernen aus dem Baum. Falls x nicht da ist, geschieht nichts
*/
public void remove( Comparable x )
{
root = remove(x, root);
}
/*
* finde das kleinste Element im Baum
*/
public Comparable findMin()
{
return elementAt(findMin(root));
}
/*
* finde das groesste Element im Baum
*/
public Comparable findMax()
{
return elementAt(findMax(root));
}
/*
* finde ein Datenelement im Baum
*/
public Comparable find(Comparable x)
{
return elementAt(find(x, root));
}
/*
* Mache den Baum leer
*/
public void makeEmpty()
{
root = null;
}
/*
* Test, ob der Baum leer ist
*/
public boolean isEmpty()
{
return root == null;
}
/*
* Ausgabe der Datenelemente in sortierter Reihenfolge
4
Algorithmen und Datenstrukturen
*/
public void printTree()
{
if( isEmpty( ) )
System.out.println( "Baum ist leer" );
else printTree( root );
}
/*
* Ausgabe der Elemente des binaeren Baums um 90 Grad versetzt
*/
public void ausgBinaerBaum()
{
if( isEmpty() )
System.out.println( "Leerer baum" );
else
ausgBinaerBaum( root,0 );
}
// Private Methoden
/*
* Methode fuer den Zugriff auf ein Datenelement
*/
private Comparable elementAt( BinaerBaumknoten b )
{
return b == null ? null : b.daten;
}
/*
* Interne Methode fuer das Einfuegen in einen Teilbaum
*/
private BinaerBaumknoten insert(Comparable x, BinaerBaumknoten b)
{
/* 1*/
if( b == null )
/* 2*/
b = new BinaerBaumknoten( x, null, null );
/* 3*/
else if( x.compareTo( b.daten ) < 0 )
/* 4*/
b.links = insert( x, b.links );
/* 5*/
else if( x.compareTo( b.daten ) > 0 )
/* 6*/
b.rechts = insert( x, b.rechts );
/* 7*/
else
/* 8*/
; // Duplikat; tue nichts
/* 9*/
return b;
}
/*
* Interne Methode fuer das Entfernen eines Knoten in einem Teilbaum
*/
private BinaerBaumknoten remove(Comparable x, BinaerBaumknoten b)
{
if( b == null )
return b;
// nichts gefunden; tue nichts
if( x.compareTo(b.daten) < 0 )
b.links = remove(x, b.links );
else if( x.compareTo(b.daten) > 0 )
b.rechts = remove( x, b.rechts );
else if( b.links != null && b.rechts != null ) // Zwei Kinder
{
b.daten = findMin(b.rechts).daten;
b.rechts = remove(b.daten, b.rechts);
}
else
b = ( b.links != null ) ? b.links : b.rechts;
return b;
}
/*
* Interne Methode zum Bestimmen des kleinsten Datenelements im Teilbaum
*/
5
Algorithmen und Datenstrukturen
private BinaerBaumknoten findMin(BinaerBaumknoten b)
{
if (b == null)
return null;
else if( b.links == null)
return b;
return findMin(b.links );
}
/*
* Interne Methode zum Bestimmen des groessten Datenelements im Teilbaum
*/
private BinaerBaumknoten findMax( BinaerBaumknoten b)
{
if( b != null )
while( b.rechts != null )
b = b.rechts;
return b;
}
/*
* Interne Methode zum Bestimmen eines Datenelements im Teilbaum.
*/
private BinaerBaumknoten find(Comparable x, BinaerBaumknoten b)
{
if(b == null)
return null;
if( x.compareTo(b.daten ) < 0)
return find(x, b.links);
else if( x.compareTo(b.daten) > 0)
return find(x, b.rechts);
else
return b;
// Gefunden!
}
/*
* Internae Methode zur Ausgabe eines Teilbaums in sortierter Reihenfolge
*/
private void printTree(BinaerBaumknoten b)
{
if(b != null)
{
printTree(b.links);
System.out.print(b.daten);
System.out.print(' ');
printTree( b.rechts );
}
}
/*
* Ausgabe des Binaerbaums um 90 G rad versetzt
*/
private void ausgBinaerBaum(BinaerBaumknoten b, int stufe)
{
if (b != null)
{
ausgBinaerBaum(b.links, stufe + 1);
for (int i = 0; i < stufe; i++)
{
System.out.print(' ');
}
System.out.println(b.daten);
ausgBinaerBaum(b.rechts, stufe + 1);
}
}
}
6
Algorithmen und Datenstrukturen
public class BinaererSuchbaumTest
{
// Test program
public static void main( String [] args )
{
// Test Nr. 1
BinaererSuchbaum b = new BinaererSuchbaum();
final int ZAHLEN = 4000;
final int LUECKE = 37;
System.out.println(
"Pruefung... (keine weiteren Ausgaben bedeutet Erfolg)");
for( int i = LUECKE; i != 0; i = (i + LUECKE) % ZAHLEN)
b.insert( new Integer( i ) );
for(int i = 1; i < ZAHLEN; i+= 2 )
b.remove( new Integer( i ) );
if (ZAHLEN < 40)
b.printTree( );
if( ((Integer)(b.findMin( ))).intValue( ) != 2 ||
((Integer)(b.findMax( ))).intValue( ) != ZAHLEN - 2 )
System.out.println( "FindMin oder FindMax -Fehler!" );
for( int i = 2; i < ZAHLEN; i+=2 )
if( ((Integer)(b.find( new Integer( i ) ))).intValue( ) != i )
System.out.println( "Find Fehler Nr.1!" );
for( int i = 1; i < ZAHLEN; i+=2 )
{
if( b.find( new Integer( i ) ) != null )
System.out.println( "Find error2!" );
}
// Test Nr.2
BinaererSuchbaum b1 = new BinaererSuchbaum();
for (int i = 0; i < 10; i++)
{
// Erzeuge eine Zahl zwischen 0 und 100
Integer r = new Integer((int)(Math.random()*100));
b1.insert(r);
}
System.out.println("Inorder-Durchlauf");
b1.printTree();
System.out.println();
System.out.println("Baumdarstellung um 90 Grad versetzt");
b1.ausgBinaerBaum();
System.out.print("Kleinster Wert: ");
System.out.print(((Integer)(b1.findMin())).intValue());
System.out.println();
System.out.print("Groesster Wert: ");
System.out.print(((Integer)(b1.findMax())).intValue());
System.out.println();
for (int i = 0; i < 10; i++)
{
// Erzeuge eine Zahl zwischen 0 und 100
Integer r = new Integer((int)(Math.random()*100));
if ( b1.find(r) != null )
{
b1.remove( r );
}
// else System.out.println(r.intValue() + " nicht gefunden");
}
b1.ausgBinaerBaum();
// Test Nr. 3
BinaererSuchbaum b2 = new BinaererSuchbaum();
for (int i = 0; i < 20; i++) // 20 Zusfallsstrings speichern
{
String s = "Zufallszahl " + (int)(Math.random() * 100);
7
Algorithmen und Datenstrukturen
b2.insert(s);
}
b2.printTree(); // Sortiert wieder ausdrucken
}
}
8
Herunterladen