Binomialqueue - oth

Werbung
Algorithmen und Datenstrukturen
Übung 13: Binomial Queue
Binomialbaum
Definition: Ein Baum mit einem Knoten ist der Binomialbaum B0. Ein Baum mit zwei Knoten ist der
Binomialbaum B1. Man erhält den Binomialbaum Bk, indem man die Wurzel der zwei Binomialbäume
Bk-1 mit einer Kante verbindet.
B0
B1
B2
B3
B4
Abb.: Binomialbäume B0, B1, B2, B3 und B4
Für einen Binomialbaum Bk gilt: Bk hat 2k Knoten. Die Wurzel von Bk hat den Grad k. Die Anzahl der
Knoten in Tiefe t von einem Bk ist
k
 
t
Binomialqueue
Definition: Eine Menge von „Heap“ geordneten Binomialbäumen , von denen keine den gleichen Grad
haben, heißt Binomialqueue, z.B.:
1. Eine Binomialqueue für 7 Elemente besteht aus B2 + B1 + B0
2. Eine Binomialqueue der Größe 13 kann durch B3 + B2 + B0 präsentiert werden.
3. Eine Binomialqueue mit 6 Elementen kann bspw. so aussehen
H1
16
12
18
21
24
65
1
Algorithmen und Datenstrukturen
Operationen
Bestimmen des kleinsten Elements: Das kleinste Element kann nach Durchlaufen aller Baumwurzeln
gefunden werden. Falls es N unterschiedliche Bäume gibt, kann das Minimum in O(logN) [ ZE]
gefunden werden.
Mischen 2er Binomialqeueues:
H1
16
12
18
21
24
65
H2
13
14
23
26
51
24
65
B0 von H2 hat kein Gegenstück und kann daher nach H3 übernommen werden. H1 und H2 haben
Binomialbäume der Höhe 1. Sie werden zusammengemischt. Der Baum mit der größeren Wurzel wird
Teilbaum der kleineren.
14
26
16
18
Es entsteht in H3 ein Binomiallbaum der Höhe 2, in H3 gibt es keinen Baum der Höhe 1.
H3
13
23
12
51
24
21
24
65
14
65
26
16
18
Einfügen. Das Einfügen von Knoten ist ein Spezialfall des Mischens. Es wird ein aus einem Knoten
bestehender Baum erzeugt und ein Mischvorgang ausgeführt.
Bsp.: Einfügen der Zahlen 1 bis 7
1
1
3
1
2
4
3
2
1
3
2
1
4
1
2
2
3
4
2
Algorithmen und Datenstrukturen
Das Einfügen der 4 erfordert drei Schritte (2 Mischvorgänge und einen Stop-Vorgang.
5
1
2
3
4
5
1
6
2
3
4
7
5
1
6
2
3
4
Löschen des kleinsten Elements
Zuerst wird der Baum mit der kleinsten Wurzel gesucht. Sie befindet sich bspw. im Baum Bk der
Binomialqueue. Bk wird aus dem Wald der Binomialbaeume entfernt, dies führt zu H’. Aus B k wird die
Wurzel entfernt, daraus resultieren B0, B1, Bk-1, die zusammen die Binomialqueue H’’ bilden.
Abgeschlossen wird die Operation durch Mischen von H’ und H’’.
Bsp.:
H3
13
23
12
51
24
21
65
24
14
65
26
16
18
H’
13
23
51
24
65
3
Algorithmen und Datenstrukturen
H’’
21
24
14
24
16
18
Implementierung
Die Binomialqueue
H3
13
23
12
51
24
21
24
65
14
65
26
16
18
wird folgendermaßen implementiert:
12
14
16
24
23
21
65
24
13
51
65
18
Die Binomialqueue ist durch einen Array von Binomialbäumen repräsentiert.
Jeder Knoten von einem Binomialbaum in einer Binomialqueue umfasst Daten, das erste (linke) Kind
und den rechten Nachbarn.
// Knoten fuer Binomialbaeume in Binomial Queues
class BinomialKnoten
{
// Freundliche Daten mit Zugriffsmoeglichkeit vom
// gleichen Verzeichnis bzw. Paket
Comparable
element;
// Daten im Knoten
BinomialKnoten linkesKind;
// Linkes Kind
BinomialKnoten naechsterNachbar; // Rechtes Kind
// Konstructor
BinomialKnoten( Comparable dasElement )
{
this( dasElement, null, null );
}
BinomialKnoten( Comparable dasElement,
BinomialKnoten lb, BinomialKnoten nb )
4
Algorithmen und Datenstrukturen
{
element
= dasElement;
linkesKind
= lb;
naechsterNachbar = nb;
}
}
Schnittstellen der Klasse Binomialqueue
//
//
//
//
//
//
//
//
//
//
//
//
//
//
Die Klasse BinomialQueue
CONSTRUCTION: with a negative infinity sentinel
******************OEFFENTLICHE OPERATIONEN*********************
void insert( x )
--> Einfuegen x
Comparable loescheMin( )--> Return und Rueckgabe des kleinsten Elements
Comparable findeMin( ) --> Return und Rueckgabe des kleinsten Elements
boolean istLeer( )
--> Return true, falls; sonst false
boolean istVoll( )
--> Return true, falls voll; sonst false
void macheLeer( )
--> Entferne alle Elemente
vod mische( rhs )
--> Absorbiere rhs in den vorliegenden heap
****************** Fehler ********************************
Overflow, falls die Kapazitaet erschoepft ist
5
Algorithmen und Datenstrukturen
Lösungen
//
//
//
//
//
//
//
//
//
//
//
//
//
//
Die Klasse BinomialQueue
CONSTRUCTION: with a negative infinity sentinel
******************OEFFENTLICHE OPERATIONEN*********************
void insert( x )
--> Einfuegen x
Comparable loescheMin( )--> Return und Rueckgabe des kleinsten Elements
Comparable findeMin( ) --> Return und Rueckgabe des kleinsten Elements
boolean istLeer( )
--> Return true, falls; sonst false
boolean istVoll( )
--> Return true, falls voll; sonst false
void macheLeer( )
--> Entferne alle Elemente
vod mische( rhs )
--> Absord rhs into this heap
****************** Fehler ********************************
Overflow, falls die Kapazitaet erschoepft ist
/**
* Implementierung einer Binomialqueue.
*/
public class BinomialQueue
{
private static final int MAX_BAEUME = 14;
private int aktuelleGroesse;
// Anzahl elemente der
Binomialqueue
private BinomialKnoten [] dieBaeume; // Ein Array mit den Baumwurzeln
/**
* Erzeuge die Binomialqueue.
*/
public BinomialQueue( )
{
dieBaeume = new BinomialKnoten[ MAX_BAEUME ];
macheLeer( );
}
/**
* Mische rhs in die Binomialqueue.
* rhs wird leer. rhs muss sich unterscheiden
* von der aufrufenden Binomialqueue.
* Parameter rhs ist die andere Binomialqueue.
* Ausnahme Overflow, falls das Ergebnis die Kapazitaet ueberschreitet
*/
public void mische( BinomialQueue rhs ) throws Overflow
{
if( this == rhs )
//
return;
if( aktuelleGroesse + rhs.aktuelleGroesse > kapazitaet( ) )
throw new Overflow( );
aktuelleGroesse += rhs.aktuelleGroesse;
BinomialKnoten carry = null;
for( int i = 0, j = 1; j <= aktuelleGroesse; i++, j *= 2 )
{
BinomialKnoten t1 = dieBaeume[ i ];
BinomialKnoten t2 = rhs.dieBaeume[ i ];
int welcherFall = t1 == null ? 0 : 1;
welcherFall += t2 == null ? 0 : 2;
welcherFall += carry == null ? 0 : 4;
switch( welcherFall )
{
case 0: /* Keine Baeume */
case 1: /* Nur die aufrufende Binomialqueue */
break;
case 2: /* Nur Parameter rhs */
dieBaeume[ i ] = t2;
6
Algorithmen und Datenstrukturen
case 4:
case 3:
case 5:
case 6:
case 7:
rhs.dieBaeume[ i ] = null;
break;
/* Only carry */
dieBaeume[ i ] = carry;
carry = null;
break;
/* this und rhs */
carry = verbindeBaeume( t1, t2 );
dieBaeume[ i ] = rhs.dieBaeume[ i ] = null;
break;
/* this and carry */
carry = verbindeBaeume( t1, carry );
dieBaeume[ i ] = null;
break;
/* rhs und carry */
carry = verbindeBaeume( t2, carry );
rhs.dieBaeume[ i ] = null;
break;
/* Alle drei */
dieBaeume[ i ] = carry;
carry = verbindeBaeume( t1, t2 );
rhs.dieBaeume[ i ] = null;
break;
}
}
for( int k = 0; k < rhs.dieBaeume.length; k++ )
rhs.dieBaeume[ k ] = null;
rhs.aktuelleGroesse = 0;
}
/**
* Rueckgabe des Ergebnis vom Mischen gleichgrosser b1 and 22.
*/
private static BinomialKnoten verbindeBaeume( BinomialKnoten b1,
BinomialKnoten b2)
{
if( b1.element.compareTo( b2.element ) > 0 )
return verbindeBaeume( b2, b1 );
b2.naechsterNachbar = b1.linkesKind;
b1.linkesKind = b2;
return b1;
}
/**
* Einfuegen in die Binomialqueue, Verwalten der heap Ordnung.
* Parameter x, einzufuegendes Element.
* Ausnahme Overflow, falls kapazitaet ueberschritten wird.
*/
public void insert( Comparable x ) throws Overflow
{
BinomialQueue einElement = new BinomialQueue( );
einElement.aktuelleGroesse = 1;
einElement.dieBaeume[ 0 ] = new BinomialKnoten( x );
mische( einElement );
}
/**
* Finde das kleinste Element in der Binomialqueue.
* Rueckgabe des kleinsten Elements, oder null, falls leer.
*/
public Comparable findeMin( )
{
if( istLeer( ) ) return null;
return dieBaeume[ findeMinIndex() ].element;
}
/**
7
Algorithmen und Datenstrukturen
* Finde den Index des Baums, der das kleinste Element in der
* Binomialqueue enthaelt.
* Die Binomialqueue darf nicht leer sein.
* Rueckgabe Index des Baums, der das kleinste Element enthaelt.
*/
private int findeMinIndex()
{
int i;
int minIndex;
for( i = 0; dieBaeume[ i ] == null; i++ )
;
for( minIndex = i; i < dieBaeume.length; i++ )
if( dieBaeume[ i ] != null &&
dieBaeume[ i ].element.compareTo( dieBaeume[ minIndex ].element )
< 0 )
minIndex = i;
return minIndex;
}
/**
* Entferne das kleinste Element aus der BinomialQueue.
* Rueckgabe des kleinsten Elements, oder null, falls leer.
*/
public Comparable loescheMin( )
{
if( istLeer( ) )return null;
int minIndex = findeMinIndex();
Comparable minItem = dieBaeume[ minIndex ].element;
BinomialKnoten deletedTree = dieBaeume[ minIndex ].linkesKind;
BinomialQueue deletedQueue = new BinomialQueue( );
deletedQueue.aktuelleGroesse = ( 1 << minIndex ) - 1;
for( int j = minIndex - 1; j >= 0; j-- )
{
deletedQueue.dieBaeume[ j ] = deletedTree;
deletedTree = deletedTree.naechsterNachbar;
deletedQueue.dieBaeume[ j ].naechsterNachbar = null;
}
dieBaeume[ minIndex ] = null;
aktuelleGroesse -= deletedQueue.aktuelleGroesse + 1;
try
{ mische( deletedQueue ); }
catch( Overflow e ) { }
return minItem;
}
/**
* Test, ob die Binomialqueue leer ist.
* Rueckgabe true, falls empty,anderenfallsfalse.
*/
public boolean istLeer( )
{
return aktuelleGroesse == 0;
}
/**
* Test, ob die Binomialqueue voll ist.
* Rueckgabe true, falls voll, anderenfall false.
*/
public boolean istVoll( )
{
return aktuelleGroesse == kapazitaet( );
}
/**
* Mache die Binomialqueue leer.
*/
8
Algorithmen und Datenstrukturen
public void macheLeer( )
{
aktuelleGroesse = 0;
for( int i = 0; i < dieBaeume.length; i++ )
dieBaeume[ i ] = null;
}
/**
* Rueckgabe kapazitaet.
*/
private int kapazitaet( )
{
return ( 1 << dieBaeume.length ) - 1;
}
}
Die Klasse BinomialQueueTest
public class BinomialQueueTest
{
public static void main( String [ ] args )
{
int anzElemente = 10000;
BinomialQueue h = new BinomialQueue( );
BinomialQueue h1 = new BinomialQueue( );
int i = 37;
System.out.println( "Starting check." );
try
{
for( i = 37; i != 0; i = ( i + 37 ) % anzElemente )
if( i % 2 == 0 )
h1.insert( new Integer( i ) );
else
h.insert( new Integer( i ) );
h.mische( h1 );
for( i = 1; i < anzElemente; i++ )
if( ((Integer)( h.loescheMin( ) )).intValue( ) != i )
System.out.println( "Oops! " + i );
}
catch( Overflow e )
{ System.out.println( "Unexpected overflow" ); }
System.out.println( "Check done." );
}
}
9
Herunterladen