ueb5 - oth-regensburg.de

Werbung
Algorithmen und Datenstrukturen
Übung 5. Perfekt ausgeglichene binäre Bäume, statisch optimierte Bäume1
Perfekt ausgeglichener, binärer Suchbaum
Hier geht es darum, entartete Bäume (schiefe Bäume, Äste werden zu linearen Listen, etc.) zu
vermeiden. Statische Optimierung heißt: Der ganze Baum wird neu (bzw. wieder neu) aufgebaut.
Bei der dynamischen Optimierung wird der Baum während des Betriebs (bei jedem Ein- und
Ausfügen) optimiert.
Ein binärer Suchbaum sollte immer ausgeglichen sein. Der folgende Baum
1
2
3
4
5
ist zu einer linearen Liste degeneriert und läßt sich daher auch nicht viel schneller als eine lineare
Liste durchsuchen. Ein derartiger binärer Suchbaum entsteht zwangsläufig, wenn die bei der Eingabe
angegebene Schlüsselfolge in aufsteigend sortierter Reihenfolge vorliegt. Der vorliegende binäre
Suchbaum ist selbstverständlich nicht ausgeglichen. Es gibt allerdings auch Unterschiede bei der
Beurteilung der Ausgeglichenheit, z.B.:
Die vorliegenden Bäume sind beide ausgeglichen. Der linke Baum ist perfekt ausbalanciert. Jeder
Binärbaum ist perfekt ausbalanciert, falls jeder Knoten über einen linken und rechten Teilbaum
verfügt, dessen Knotenzahl sich höchstens um den Wert 1 unterscheidet.
Der rechte Teilbaum ist ein in der Höhe ausgeglichener (AVL 2-)Baum. Die Höhe der Knoten
zusammengehöriger linker und rechter Teilbäume unterscheiden sich höchstens um den Wert 1.
Jeder perfekt ausgeglichene Baum ist gleichzeitig auch ein in der Höhe ausgeglichener Binärbaum.
Der umgekhrte Fall trifft allerdings nicht zu.
Es gibt einen einfachen Algorithmus zum Erstellen eines pefekt ausgeglichenen Binärbaums, falls
(1) die einzulesenden Schlüsselwerte sortiert in aufsteigender Reihenfolge angegeben werden
(2) bekannt ist, wieviel Objekte (Schlüssel) werden müssen.
import java.io.*;
class PBBknoten
{
// Instanzvariable
protected PBBknoten links;
protected PBBknoten rechts;
1
2
// linker Teilbaum
// rechter Teilbaum
Vgl. PBB.java, PR43205
nach den Anfangsbuchstaben der Namen seiner Entdecker: Adelson-Velski u. Landes
1
Algorithmen und Datenstrukturen
public int daten;
// Dateninhalt der Knoten
// Konstruktoren
public PBBknoten()
{
this(0,null,null);
}
public PBBknoten(int datenElement)
{
this(datenElement, null, null );
}
public PBBknoten(int datenElement,
PBBknoten l,
PBBknoten r)
{
daten
= datenElement;
links
= l;
rechts
= r;
}
public PBBknoten getLinks()
{
return links;
}
public PBBknoten getRechts()
{
return rechts;
}
}
public class PBB
{
static BufferedReader ein = new BufferedReader(new InputStreamReader(
System.in));
// Instanzvariable
PBBknoten wurzel;
// Konstruktor
public PBB(int n) throws IOException
{
if (n == 0) wurzel = null;
else
{
int nLinks = (n - 1) / 2;
int nRechts = n - nLinks - 1;
wurzel = new PBBknoten();
wurzel.links = new PBB(nLinks).wurzel;
wurzel.daten = Integer.parseInt(ein.readLine());
wurzel.rechts = new PBB(nRechts).wurzel;
}
}
public void ausgPBB()
{
ausg(wurzel,0);
}
private void ausg(PBBknoten b, int nSpace)
{
if (b != null)
{
ausg(b.rechts,nSpace += 6);
for (int i = 0; i < nSpace; i++)
System.out.print(" ");
System.out.println(b.daten);
ausg(b.links, nSpace);
2
Algorithmen und Datenstrukturen
}
}
// Test
public static void main(String args[]) throws IOException
{
int n;
System.out.print("Gib eine ganze Zahl n an, ");
System.out.print("gefolgt von n ganzen Zahlen in ");
System.out.println("aufsteigender Folge");
n = Integer.parseInt(ein.readLine());
PBB b = new PBB(n);
System.out.print(
"Hier ist das Resultat: ein perfekt balancierter Baum, ");
System.out.println("die Darstellung erfogt um 90 Grad versetzt");
b.ausgPBB();
}
}
Schreibtischtest: Wird mit n = 10 aufgerufen, dann wird anschließend die Anzahl der Knoten
berechnet, die sowohl in den linken als auch in den rechten Teilbaum eingefügt werden. Da der
Wurzelknoten keinem Teilbaum zugeordnet werden kann, ergeben sich für die beiden Teilbäume (10
– 1) Knoten. Das ergibt nLinks = 4, nRechts = 5. Anschließend wird der Wurzelknoten erzeugt.
Es folgt der rekursive Aufruf wurzel.links = new PBB(nLinks).wurzel; mit nLinks = 4.
Die Folge davon ist: Einlesen von 4 Zahlen und Ablage dieser Zahlen im linken Teilbaum. Die danach
folgende Zahl wird im Wurzelknoten abgelegt. Der rekursive Aufruf wurzel.rechts = new
PBB(nRechts).wurzel; mit nRechts = 5 verarbeitet die restlichen 5 Zahlen und erstellt damit
den rechten Teilbaum.
Durch jedem rekursiven Aufruf wird ein Baum mit zwei ungefähr gleich großen Teilbäumen erzeugt.
Da die im Wurzelknoten enthaltene Zahl direkt nach dem erstellen des linken Teilbaum gelesen wird,
ergibt sich bei aufsteigender Reihenfolge der Eingabedaten ein binärer Suchbaum, der außerdem
noch perfekt balanciert ist.
Statische Optimierung
Der Algorithmus zum Erstellen eines perfekt ausgeglichenen Baums kann zur statischen
Optimierung binärer Suchbäume verwendet werden. Das Erstellen des binären Suchbaums erfolgt
dabei nach der bekannten Verfahrensweise. Wird ein solcher Baum in Inorder-Folge durchlaufen, so
werden die Informationen in den Baumknoten aufsteigend sortiert. Diese sortierte Folge ist
Eingangsgröße für die statische Optimierung. Es wird mit der sortiert vorliegende Folge der Schlüssel
ein perfekt ausgeglichener Baum erstellt.
3
Herunterladen