Galileo Computing < openbook >
Galileo Computing - Programming the Net
Galileo Computing - Programming the Net


Java ist auch eine Insel (2. Aufl.) von Christian Ullenboom
Programmieren für die Java 2-Plattform in der Version 1.4
Java ist auch eine Insel (2. Auflage)
gp Kapitel 11 Datenstrukturen und Algorithmen
  gp 11.1 Mit einem Iterator durch die Daten wandern
  gp 11.2 Dynamische Datenstrukturen
  gp 11.3 Die Klasse Vector
    gp 11.3.1 Vektoren erzeugen
    gp 11.3.2 Funktionen
    gp 11.3.3 Arbeitsweise des internen Arrays
    gp 11.3.4 Die Größe eines Felds
    gp 11.3.5 Eine Aufzählung und gleichzeitiges Verändern
  gp 11.4 Stack, der Stapel
    gp 11.4.1 Die Methoden von Stack
    gp 11.4.2 Ein Stack ist ein Vektor – aha!
  gp 11.5 Die Klasse Hashtable und assoziative Speicher
    gp 11.5.1 Ein Objekt der Klasse Hashtable erzeugen
    gp 11.5.2 Einfügen und Abfragen der Datenstruktur
    gp 11.5.3 Die Arbeitsweise einer Hashtabelle
    gp 11.5.4 Aufzählen der Elemente
    gp 11.5.5 Ausgabe der Hashtabelle und Gleichheitstest
    gp 11.5.6 Klonen
  gp 11.6 Die abstrakte Klasse Dictionary
    gp 11.6.1 Zugriff und Abfrage
    gp 11.6.2 Metainformationen
    gp 11.6.3 Iterationen über die Elemente
  gp 11.7 Die Properties-Klasse
    gp 11.7.1 Über die Klasse Properties
    gp 11.7.2 put(), get() und getProperties()
    gp 11.7.3 Eigenschaften ausgeben
    gp 11.7.4 Systemeigenschaften der Java-Umgebung
    gp 11.7.5 Browser-Version abfragen
    gp 11.7.6 Properties von der Konsole aus setzen
  gp 11.8 Windows-typische INI-Dateien
  gp 11.9 Queue, die Schlange
  gp 11.10 Die Collection-API
    gp 11.10.1 Die Schnittstelle Collection
    gp 11.10.2 Schnittstellen, die Collection erweitern, und Map
    gp 11.10.3 Abstrakte Basisklassen für Container
    gp 11.10.4 Konkrete Container-Klassen
    gp 11.10.5 Unterschiede zu den älteren Datenstrukturen und die Synchronisation
    gp 11.10.6 Das erste Programm mit Container-Klassen
    gp 11.10.7 Iteratoren
    gp 11.10.8 Der Comparator
    gp 11.10.9 toArray() von Collection verstehen – Chance für eine Falle erkennen
  gp 11.11 Listen
    gp 11.11.1 AbstractList
    gp 11.11.2 Optionale Methoden
    gp 11.11.3 ArrayList
    gp 11.11.4 LinkedList
  gp 11.12 Algorithmen
    gp 11.12.1 Datenmanipulation
    gp 11.12.2 Größten und kleinsten Wert einer Collection finden
    gp 11.12.3 Sortieren
    gp 11.12.4 Elemente in der Collection suchen
  gp 11.13 Typsichere Datenstrukturen
  gp 11.14 Die Klasse BitSet für Bitmengen
    gp 11.14.1 Ein BitSet anlegen und füllen
    gp 11.14.2 Mengenorientierte Operationen
    gp 11.14.3 Funktionsübersicht
    gp 11.14.4 Primzahlen in einem BitSet verwalten
  gp 11.15 Ein Design-Pattern durch Beobachten von Änderungen
    gp 11.15.1 Design-Pattern
    gp 11.15.2 Das Beobachter-Pattern (Observer/Observable)

Kapitel 11 Datenstrukturen und Algorithmen

Einen Rat befolgen heißt,
die Verantwortung verschieben.
– Urzidil

Algorithmen sind ein zentrales Thema der Informatik. Ihre Erforschung und Untersuchung nimmt dort einen bedeutenden Platz ein. Algorithmen operieren nur dann effektiv mit Daten, wenn diese geeignet strukturiert sind. Schon das Beispiel Telefonbuch zeigt, wie wichtig die Ordnung der Daten nach einem Schema ist. Die Suche nach einer Telefonnummer bei gegebenem Namen gelingt schnell, jedoch ist die Suche nach einem Namen bei bekannter Telefonnummer ein mühseliges Unterfangen. Datenstrukturen und Algorithmen sind also eng miteinander verbunden und die Wahl der richtigen Datenstruktur entscheidet über effiziente Laufzeiten; beide erfüllen alleine nie ihren Zweck. Leider ist die Wahl der »richtigen« Datenstruktur nicht so einfach, wie es sich anhört, und eine Reihe von schwierigen Problemen in der Informatik sind wohl noch nicht gelöst, da eine passende Datenorganisation bis jetzt nicht gefunden wurde.

Die wichtigsten Datenstrukturen wie Liste, Vektor und Hashtabelle sollen in diesem Kapitel vorgestellt werden. In der zweiten Hälfte des Kapitels wollen wir uns dann den Algorithmen stärker widmen, die auf diesen Datenstrukturen operieren.

11.1 Mit einem Iterator durch die Daten wandern

Wir wollen bei den Datenstrukturen eine Möglichkeit kennen lernen, wie sich die gespeicherten Daten unabhängig von der Implementierung immer mit derselben Technik abfragen lassen. Bei den Datenstrukturen handelt es sich meistens um Daten in Arrays, Bäumen oder Ähnlichem. Oft wird nur die Frage nach der Zugehörigkeit eines Werts zum Datenbestand gestellt, also: »Gehört das Wort dazu?«. Dieses Wortproblem ist durchaus wichtig, aber die Möglichkeit, die Daten in irgendeiner Weise aufzuzählen, ist nicht minder bedeutend. Bei Arrays können wir über den Index auf die Elemente zuzugreifen. Da wir jedoch nicht immer ein Array als Datenspeicher haben und uns auch die objektorientierte Programmierung verbietet, hinter die Kulisse zu sehen, benötigen wir möglichst einen allgemeineren Weg. Hier bieten sich Enumeratoren an. Das Interface Enumeration bietet die zwei Funktionen hasMoreElements() und nextElement() an, mit denen durch eine Datenstruktur iteriert werden kann – wir sprechen in diesem Fall auch von einem Iterator. Bei jedem Aufruf von nextElement() erhalten wir ein weiteres Element der Datenstruktur. Im Gegensatz zum Index eines Felds können wir nicht noch einmal ein Objekt auslesen oder hin und her springen. Wollten wir ein Element zweimal besuchen, zum Beispiel von rechts nach links noch einmal durchwandern, dann müssen wir wieder ein neues Enumeration-Objekt erzeugen.

Abbildung

Damit wir durch eine Datenstruktur iterieren können, muss das Objekt beide Funktionen so implementieren, dass sie die Daten ihrer zugrunde liegenden Datenstruktur preisgeben. Wenn wir später die anderen Datenstrukturen wie Vector oder Stack kennen lernen, so werden wir sehen, dass auch sie das Interface Enumeration implementieren.

interface java.util.Enumeration

gp  boolean hasMoreElements()
Testet, ob noch ein weiteres Element aufgezählt werden kann.
gp  Object nextElement()
Liefert das nächste Element der Enumeration zurück. Diese Funktion kann eine NoSuch ElementException auslösen, wenn nextElement() aufgerufen wird und das Ergebnis false beim Aufruf von hasMoreElements() ignoriert wird.

Die Aufzählung erfolgt meistens über einen Zweizeiler: Die Datenstruktur ds besitzt eine Methode elements(), die ein Enumeration-Objekt zurückgibt, welches die Elemente von ds aufzählen kann.

for ( Enumeration e = ds.elements(); e.hasMoreElements(); )
  System.out.println( e.nextElement() );

Galileo Computing

11.1.1 Bauernregeln aufzählen  toptop

Doch nun zu einem Beispiel. Es zeigt die Möglichkeit, Bauernregeln aufzuzählen. Die Funktion nextElement() löst eine NoSuchElementException aus, wenn das Ergebnis false von hasMoreElements() ignoriert wird. NoSuchElementException ist eine RuntimeException, sodass sie nicht ausdrücklich aufgefangen werden muss.

Listing 11.1   Bauernregeln.java, Teil 1

import java.util.*;

class BauernregelnEnumerator implements Enumeration
{
  private int counter = 0;

  private String slogan[] =
  {
    "Der dümmste Bauer erntet die dicksten Kartoffeln.",
    "Wenn der Hahn kräht auf dem Mist, dann ändert sich "+
      "das Wetter oder es bleibt wie es ist.",
    "Ist der Juni kalt und nass, füllt's dem Bauern Scheun' "+
 "und Fass.",
    "Sind die Hühner platt wie Teller, war der Bauer "+
      "wieder schneller.",
    "Jodelt laut die Magd im Stall, kriegt die Kuh 'nen "+
 "Herzanfall",
    "Regnet es ins Hühnerhaus, holt der Hahn das Shampoo raus!",
    "Liegt der Bauer im Mist, weiß er nicht wie spät es ist.",
 "Liegt der Bauer tot im Zimmer, lebt er nimmer.",
    "Bauen im April die Schwalben, gibt es viel Futter, Korn "+
 "und Kalben."
  };

  public boolean hasMoreElements()
{ return ( counter < slogan.length ); } public Object nextElement()
{ if ( !hasMoreElements() ) throw new NoSuchElementException("Keine Bauernregeln mehr!"); return slogan[counter++]; } }

Listing 11.2   Bauernregeln.java, Teil 2

public class Bauernregeln
{
 public static void jederZweite( Enumeration e )
 {
 boolean toggle = true;

 while ( e.hasMoreElements() )
 {
 if ( toggle ^= true )
 e.nextElement();

 System.out.println( e.nextElement() );
 }
 }

   public static void main( String args[] )
  {
 BauernregelnEnumerator e1 = new BauernregelnEnumerator();

 while ( e1.hasMoreElements() )
 System.out.println( e1.nextElement() );

 System.out.println();

 BauernregelnEnumerator e2 = new BauernregelnEnumerator();
 jederZweite( e2 );
  }
}

Schön zu erkennen ist der Vorteil der Schnittstellen an der Funktion jederZweite(). Es ist der Funktion egal, was für Objekte reinkommen, hautsache sie sind vom Typ Enumeration.






1   Das Wort »Algorithmus« geht auf den im 9. Jahrhundert lebenden persisch-arabischen Mathematiker Ibn Mûsâ Al-Chwârismî zurück.

2   Es gibt auch eine Schnittstelle mit dem Namen »Iterator«, die eine neuere Variante von Enumeration ist.

3   Enumeratoren können nicht serialisiert werden, da diese die Schnittstelle Serializable nicht implementieren.

4   Mehr von diesen nicht ganz ernst zu nehmenden Bauernregeln gibt’s unter http://www.butterbrot.de/wahnsinn/bauer.htm.





Copyright © Galileo Press GmbH 2003
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press GmbH, Gartenstraße 24, 53229 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de