Home > Informatik > Stufe Q1 > ADTs > ADT List

14.61 Implementation einer Liste

Allgemeines - Abstrakte Datentypen - Stack - Queue - Dictionary - List - Axiome - ADTs im Abitur -

Der komplette Quelltext

Die Klasse Bruch
public class Bruch
{
    int zaehler, nenner;
    
    public Bruch(int z, int n)
    {
        zaehler = z;        
        nenner  = n;
    }
    
    public int getNenner()
    {
       return nenner;
    }
    
    public int getZaehler()
    {
       return zaehler;
    }    
    
    public double getWert()
    {
       return zaehler/nenner;
    }
    
    public void show()
    {
       System.out.println(zaehler + "/" + nenner);
    }
}

Die Klasse Bruch (siehe Quelltext) ist nur ein Beispiel für einen Objekttyp, der von der Liste verwaltet werden soll. Stattdessen hätte man auch irgendetwas anderes nehmen können, zum Beispiel eine Klasse Adresse oder eine Klasse Gegenstand etc.

Die Klasse Liste
public class List
{
    private Object[] liste;
    private int last, act;
    
    public List()
    {
        liste = new Object[100];
        last = act = -1;
    }
    
    /**
     * Die Anfrage liefert den Wert true, wenn die Liste keine Objekte enthält,
     * sonst liefert sie den Wert false.
     */
    public boolean isEmpty()
    {
       return (last == -1);
    }
    
    /**
     * Die Anfrage liefert den Wert true, wenn es ein aktuelles Objekt gibt, sonst
     * liefert sie den Wert false.
     */
    public boolean hasAccess()
    {
       return (act >= 0);
    }
    
    /**
     * Falls die Liste nicht leer ist, es ein aktuelles Objekt gibt und dieses nicht
     * das letzte Objekt der Liste ist, wird das dem aktuellen Objekt in der Liste
     * folgende Objekt zum aktuellen Objekt, andernfalls gibt es nach Ausführung
     * des Auftrags kein aktuelles Objekt, d. h., hasAccess() liefert den Wert
     * false.
     */
    public void next()
    {
       if ((!isEmpty()) && (hasAccess()) && (act < last))
          act++;
       else
          act = -1;
    }
    /**
     * Falls die Liste nicht leer ist, wird das erste Objekt der Liste aktuelles
     * Objekt. Ist die Liste leer, geschieht nichts.
     */
    public void toFirst()
    {
       if (!isEmpty())
          act = 0;
    }
    
    /**
     * Falls die Liste nicht leer ist, wird das letzte Objekt der Liste aktuelles
     * Objekt. Ist die Liste leer, geschieht nichts.
     */
    public void toLast()
    {
       if (!isEmpty())
          act = last;
    }
    
    /**
     * Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das
     * aktuelle Objekt zurückgegeben, andernfalls (hasAccess() == false)
     * gibt die Anfrage den Wert null zurück.
     */
    public Object getContent()
    {
       if (hasAccess())
          return liste[act];
       else
          return null;    
    }

   /**
    * Falls es ein aktuelles Objekt gibt (hasAccess() == true) und pObject
    * ungleich null ist, wird das aktuelle Objekt durch pObject ersetzt. Sonst
    * bleibt die Liste unverändert.
    */
    public void setContent(Object x)
    {
       if ((hasAccess()) && (x != null))
          liste[act] = x;
    }
    
    /**
     * Ein neues Objekt pObject wird am Ende der Liste eingefügt. Das aktuelle
     * Objekt bleibt unverändert. Wenn die Liste leer ist, wird das Objekt
     * pObject in die Liste eingefügt und es gibt weiterhin kein aktuelles Objekt
     * (hasAccess() == false). Falls pObject gleich null ist, bleibt die Liste
     * unverändert.
     */
    public void append(Object x)
    {
       if ((last < 99) && (x != null))
       {
          last++;
          liste[last] = x;
       }
    }
    
    /**
     * Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird ein neues
     * Objekt vor dem aktuellen Objekt in die Liste eingefügt. Das aktuelle Objekt
     * bleibt unverändert. Falls die Liste leer ist und es somit kein aktuelles Objekt
     * gibt (hasAccess() == false), wird pObject in die Liste eingefügt und
     * es gibt weiterhin kein aktuelles Objekt. Falls es kein aktuelles Objekt gibt
     * (hasAccess() == false) und die Liste nicht leer ist oder pObject
     * gleich null ist, bleibt die Liste unverändert.
     */
    public void insert(Object x)
    {
        if (hasAccess()) 
            last++;
        else 
            return;
            
        int h = last;
        
        while (h > act)
        {
           liste[h] = liste[h-1];
           h--;
        }
        liste[h] = x;
        act++;
    }
 
    /**
     * Die Liste pList wird an die Liste angehängt. Anschließend wird pList
     * eine leere Liste. Das aktuelle Objekt bleibt unverändert. Falls pList null
     * oder eine leere Liste ist, bleibt die Liste unverändert.
     */    
    public void concat(List pList)
    {
       if ((last + pList.last) > 99) return;
       
       for (int i=0; i<= pList.last; i++)
          liste[last + i + 1] = pList.liste[i];
       last = last + pList.last + 1;
       
       pList.last = pList.act = -1;
    }
    
    /**
     * Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das aktuelle
     * Objekt gelöscht und das Objekt hinter dem gelöschten Objekt wird zum
     * aktuellen Objekt. Wird das Objekt, das am Ende der Liste steht, gelöscht, 
     * gibt es kein aktuelles Objekt mehr (hasAccess() == false). Wenn die Liste
     * leer ist oder es kein aktuelles Objekt gibt (hasAccess() == false),
     * bleibt die Liste unverändert.
     */
    public void remove()
    {
    // Wenn die Liste leer ist oder es kein aktuelles Objekt gibt, bleibt die
    // Liste unverändert:
       if ( (isEmpty()) || (!hasAccess())) return;
       
    // Wenn das zu löschende Objekt am Ende der Liste steht, gibt es kein
    // aktuelles Objekt mehr. Das letzte Objekt wird aber trotzdem (virtuell)
    // entfernt durch last--.
       if (act == last)
       {
           last--;
           act = -1;
           return;
       }
       
       for (int i = act; i < last; i++)
          liste[i] = liste[i+1];
       last--;
    }
    
    /**
     * Eine rein interne show()-Methode, damit die Implementation der Liste
     * auf Herz und Nieren getestet werden kann.
     * Gehört nicht zu den offiziellen Methoden der Klasse Liste!
     */
    public void show()
    {
       for (int i=0; i<=last; i++)
       {
          Bruch b = (Bruch) liste[i];
          System.out.print(b.zaehler+"/"+b.nenner);
          
          if (i == 0)
             System.out.print(" <== first");
          if (i == act)
             System.out.print(" <== act");
          if (i == last)
             System.out.print(" <== last");

          System.out.println("");            
      }
    }
}

Die Klasse List (siehe Quelltext) wurde den Vorgaben zum Zentralabitur NRW entsprechend implementiert - hoffe ich jedenfalls stark. Ich habe die Klasse auf Herz und Nieren getestet, aber manchmal übersieht man ja doch ein paar Fehler. Falls mir das passiert sein sollte, bitte ich um Rückmeldung an info@u-helmich.de .

Die Klasse Test

Natürlich muss eine so umfangreiche Klasse ausführlich getestet werden. Dazu habe ich zwei verschiedene Testklassen geschrieben, deren Quelltext Sie sich hier herunterladen können: Klasse Test, in der die "üblichen" Methoden der Liste getestet werden, und Klasse TestConcat, in der die concat-Methode der Klasse List getestet wird.

Die dynamische Implementation

Ein Abstrakter Datentyp sagt ja überhaupt nichts über die Art und Weise der Implementation aus. Hier wurde der ADT Liste mit Hilfe eines statischen Arrays implementiert, ein durchaus übliches Vorgehen. Wenn wir das Thema "Referenzen" in Folge 15 behandeln, werden wir sehen, wie man den ADT List auch dynamisch mit Hilfe von Zeigern implementieren kann.