Liste Implementation, doppelt next()

MikaMac1407

Neues Mitglied
Guten Nachmittag,
ich möchte eine Methode implementieren, die von einer LED-Kette jede zweite LED leuchten lässt. Allerdings wird das zweite next() schlicht nicht durchgeführt, auch nicht, wenn vorher eine if-Abfrage erfolgt, welche überprüft, ob ein aktuelles Objekt vorhanden ist. Hier der Quelltext zur Veranschaulichung, der Fehler liegt in den Methoden leuchten02 und leuchten03 vor.
Java:
[SIZE=3]public class Steuerung
{

    protected int anzahlLEDs;
    public List<LED> lichterkette;
 
    public Steuerung()
    {
        lichterkette = new List<LED>();
        anzahlLEDs = 0;
    }

    public void ledEinfuegen(LED pled)
    {
        anzahlLEDs++;
        lichterkette.append(pled);
    }

    public void lichterketteAnhaengen(List<LED> pLichterkette)
    {

        anzahlLEDs = 0;
        lichterkette.concat(pLichterkette);
        lichterkette.toFirst();
        while(lichterkette.hasAccess())
        {
            anzahlLEDs++;
            lichterkette.next();
        }
    }

    public int getAnzahlLEDs()
    {
        return anzahlLEDs;
    }

    public void leuchten01()
    {
        lichterkette.toFirst();
        while(lichterkette.hasAccess())
        {
            lichterkette.getContent().lichtAN();
            lichterkette.next();
        }
    }

    public void leuchten02()
    {
        lichterkette.toFirst();
        while(lichterkette.hasAccess())
        {
            lichterkette.getContent().lichtAN();
            lichterkette.next();

        }
        lichterkette.toFirst();
        lichterkette.next();
        while(lichterkette.hasAccess())
        {

            lichterkette.getContent().lichtAUS();
            lichterkette.next();
            if(lichterkette.hasAccess())
            {
                lichterkette.next();

            }
        }
    }

    public void leuchten03()
    {

        lichterkette.toFirst();
        while(lichterkette.hasAccess())
        {
            lichterkette.getContent().lichtAN();
            lichterkette.next();

        }
        lichterkette.toFirst();

        while(lichterkette.hasAccess())
        {

            lichterkette.getContent().lichtAUS();
            lichterkette.next();
            if(lichterkette.hasAccess())
            {
                lichterkette.next();

            }
         
        }
        if(lichterkette.hasAccess())
        {
            lichterkette.getContent().lichtAUS();
        }
    }
}
[/SIZE]
 
Zuletzt bearbeitet:
Moin, hier der Quelltext der Liste:
Java:
/**
 * <p>
 * Materialien zu den zentralen NRW-Abiturpruefungen im Fach Informatik ab 2017.
 * </p>
 * <p>
 * Generische Klasse List<ContentType>
 * </p>
 * <p>
 * Objekt der generischen Klasse List verwalten beliebig viele linear
 * angeordnete Objekte vom Typ ContentType. Auf hoechstens ein Listenobjekt,
 * aktuellesObjekt genannt, kann jeweils zugegriffen werden.<br />
 * Wenn eine Liste leer ist, vollstaendig durchlaufen wurde oder das aktuelle
 * Objekt am Ende der Liste geloescht wurde, gibt es kein aktuelles Objekt.<br />
 * Das erste oder das letzte Objekt einer Liste koennen durch einen Auftrag zum
 * aktuellen Objekt gemacht werden. Ausserdem kann das dem aktuellen Objekt
 * folgende Listenobjekt zum neuen aktuellen Objekt werden. <br />
 * Das aktuelle Objekt kann gelesen, veraendert oder geloescht werden. Ausserdem
 * kann vor dem aktuellen Objekt ein Listenobjekt eingefuegt werden.
 * </p>
 * 
 * @author Qualitaets- und UnterstuetzungsAgentur - Landesinstitut fuer Schule, Materialien zum schulinternen Lehrplan Informatik SII
 * @version Generisch_03 2014-03-01
 */
public class List<ContentType> {

  /* --------- Anfang der privaten inneren Klasse -------------- */

  public class ListNode {

    private ContentType contentObject;
    private ListNode next;

    /**
     * Ein neues Objekt wird erschaffen. Der Verweis ist leer.
     * 
     * @param pContent das Inhaltsobjekt vom Typ ContentType
     */
    public ListNode(ContentType pContent) {
      contentObject = pContent;
      next = null;
    }

    /**
     * Der Inhalt des Knotens wird zurueckgeliefert.
     * 
     * @return das Inhaltsobjekt des Knotens
     */
    public ContentType getContentObject() {
      return contentObject;
    }

    /**
     * Der Inhalt dieses Kontens wird gesetzt.
     * 
     * @param pContent das Inhaltsobjekt vom Typ ContentType
     */
    public void setContentObject(ContentType pContent) {
      contentObject = pContent;
    }

    /**
     * Der Nachfolgeknoten wird zurueckgeliefert.
     * 
     * @return das Objekt, auf das der aktuelle Verweis zeigt
     */
    public ListNode getNextNode() {
      return this.next;
    }

    /**
     * Der Verweis wird auf das Objekt, das als Parameter uebergeben
     * wird, gesetzt.
     * 
     * @param pNext der Nachfolger des Knotens
     */
    public void setNextNode(ListNode pNext) {
      this.next = pNext;  
    }

  }

  /* ----------- Ende der privaten inneren Klasse -------------- */

  // erstes Element der Liste
  ListNode first;

  // letztes Element der Liste
  ListNode last;

  // aktuelles Element der Liste
  ListNode current;

  /**
   * Eine leere Liste wird erzeugt.
   */
  public List() {
    first = null;
    last = null;
    current = null;
  }

  /**
   * Die Anfrage liefert den Wert true, wenn die Liste keine Objekte enthaelt,
   * sonst liefert sie den Wert false.
   * 
   * @return true, wenn die Liste leer ist, sonst false
   */
  public boolean isEmpty() {
    // Die Liste ist leer, wenn es kein erstes Element gibt.
    return first == null;
  }

  /**
   * Die Anfrage liefert den Wert true, wenn es ein aktuelles Objekt gibt,
   * sonst liefert sie den Wert false.
   * 
   * @return true, falls Zugriff moeglich, sonst false
   */
  public boolean hasAccess() {
    // Es gibt keinen Zugriff, wenn current auf kein Element verweist.
    return current != null; 
  }

  /**
   * 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
   * Ausfuehrung des Auftrags kein aktuelles Objekt, d.h. hasAccess() liefert
   * den Wert false.
   */
  public void next() {
    if (this.hasAccess()) {
      current = current.getNextNode();
    }
  }

  /**
   * 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()) {
      current = first;
    }
  }

  /**
   * 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()) {
      current = last;
    }
  }

  /**
   * Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das
   * aktuelle Objekt zurueckgegeben, andernfalls (hasAccess() == false) gibt
   * die Anfrage den Wert null zurueck.
   * 
   * @return das aktuelle Objekt (vom Typ ContentType) oder null, wenn es
   *         kein aktuelles Objekt gibt
   */
  public ContentType getContent() {
    if (this.hasAccess()) {
      return current.getContentObject();
    } else {
      return null;
    }
  }

  /**
   * Falls es ein aktuelles Objekt gibt (hasAccess() == true) und pContent
   * ungleich null ist, wird das aktuelle Objekt durch pContent ersetzt. Sonst
   * geschieht nichts.
   * 
   * @param pContent
   *            das zu schreibende Objekt vom Typ ContentType
   */
  public void setContent(ContentType pContent) {
    // Nichts tun, wenn es keinen Inhalt oder kein aktuelles Element gibt.
    if (pContent != null && this.hasAccess()) { 
      current.setContentObject(pContent);
    }
  }

  /**
   * Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird ein neues
   * Objekt vor dem aktuellen Objekt in die Liste eingefuegt. Das aktuelle
   * Objekt bleibt unveraendert. <br />
   * Wenn die Liste leer ist, wird pContent in die Liste eingefuegt und es
   * gibt weiterhin kein aktuelles Objekt (hasAccess() == false). <br />
   * Falls es kein aktuelles Objekt gibt (hasAccess() == false) und die Liste
   * nicht leer ist oder pContent gleich null ist, geschieht nichts.
   * 
   * @param pContent
   *            das einzufuegende Objekt vom Typ ContentType
   */
  public void insert(ContentType pContent) {
    if (pContent != null) { // Nichts tun, wenn es keinen Inhalt gibt.
      if (this.hasAccess()) { // Fall: Es gibt ein aktuelles Element.

        // Neuen Knoten erstellen.
        ListNode newNode = new ListNode(pContent); 

        if (current != first) { // Fall: Nicht an erster Stelle einfuegen.
          ListNode previous = this.getPrevious(current);
          newNode.setNextNode(previous.getNextNode());
          previous.setNextNode(newNode);
        } else { // Fall: An erster Stelle einfuegen.
          newNode.setNextNode(first);
          first = newNode;
        }

      } else { //Fall: Es gibt kein aktuelles Element.

        if (this.isEmpty()) { // Fall: In leere Liste einfuegen.

          // Neuen Knoten erstellen.
          ListNode newNode = new ListNode(pContent); 

          first = newNode;
          last = newNode;
        }

      }
    }
  }

  /**
   * Falls pContent gleich null ist, geschieht nichts.<br />
   * Ansonsten wird ein neues Objekt pContent am Ende der Liste eingefuegt.
   * Das aktuelle Objekt bleibt unveraendert. <br />
   * Wenn die Liste leer ist, wird das Objekt pContent in die Liste eingefuegt
   * und es gibt weiterhin kein aktuelles Objekt (hasAccess() == false).
   * 
   * @param pContent
   *            das anzuhaengende Objekt vom Typ ContentType
   */
  public void append(ContentType pContent) {
    if (pContent != null) { // Nichts tun, wenn es keine Inhalt gibt.

      if (this.isEmpty()) { // Fall: An leere Liste anfuegen.
        this.insert(pContent);
      } else { // Fall: An nicht-leere Liste anfuegen.

        // Neuen Knoten erstellen.
        ListNode newNode = new ListNode(pContent); 

        last.setNextNode(newNode);
        last = newNode; // Letzten Knoten aktualisieren.
      }

    }
  }

  /**
   * Falls pList null oder eine leere Liste ist, geschieht nichts.<br />
   * Ansonsten wird die Liste pList an die aktuelle Liste angehaengt.
   * Anschliessend wird pList eine leere Liste. Das aktuelle Objekt bleibt
   * unveraendert. Insbesondere bleibt hasAccess identisch.
   * 
   * @param pList
   *            die am Ende anzuhaengende Liste vom Typ List<ContentType>
   */
  public void concat(List<ContentType> pList) {
    if (pList != null && !pList.isEmpty()) { // Nichts tun, wenn pList leer oder nicht existent.

      if (this.isEmpty()) { // Fall: An leere Liste anfuegen.
        this.first = pList.first;
        this.last = pList.last;
      } else { // Fall: An nicht-leere Liste anfuegen.
        this.last.setNextNode(pList.first);
        this.last = pList.last;
      }

      // Liste pList loeschen.
      pList.first = null;
      pList.last = null;
      pList.current = null;
    }
  }

  /**
   * Wenn die Liste leer ist oder es kein aktuelles Objekt gibt (hasAccess()
   * == false), geschieht nichts.<br />
   * Falls es ein aktuelles Objekt gibt (hasAccess() == true), wird das
   * aktuelle Objekt geloescht und das Objekt hinter dem geloeschten Objekt
   * wird zum aktuellen Objekt. <br />
   * Wird das Objekt, das am Ende der Liste steht, geloescht, gibt es kein
   * aktuelles Objekt mehr.
   */
  public void remove() {
    // Nichts tun, wenn es kein aktuelle Element gibt oder die Liste leer ist.
    if (this.hasAccess() && !this.isEmpty()) { 

      if (current == first) {
        first = first.getNextNode();
      } else {
        ListNode previous = this.getPrevious(current);
        if (current == last) {
          last = previous;
        }
        previous.setNextNode(current.getNextNode());
      }

      ListNode temp = current.getNextNode();
      current.setContentObject(null);
      current.setNextNode(null);
      current = temp;

      //Beim loeschen des letzten Elements last auf null setzen. 
      if (this.isEmpty()) {
        last = null;
      }
    }
  }

  /**
   * Liefert den Vorgaengerknoten des Knotens pNode. Ist die Liste leer, pNode
   * == null, pNode nicht in der Liste oder pNode der erste Knoten der Liste,
   * wird null zurueckgegeben.
   *
   * @param pNode
   *         der Knoten, dessen Vorgaenger zurueckgegeben werden soll
   * @return der Vorgaenger des Knotens pNode oder null, falls die Liste leer ist,
   *         pNode == null ist, pNode nicht in der Liste ist oder pNode der erste Knoten
   *         der Liste ist
   */
  private ListNode getPrevious(ListNode pNode) {
    if (pNode != null && pNode != first && !this.isEmpty()) {
      ListNode temp = first;
      while (temp != null && temp.getNextNode() != pNode) {
        temp = temp.getNextNode();
      }
      return temp;
    } else {
      return null;
    }
  }
 
}
 
Was noch fehlt, ist der Aufruf an sich ... also die Main-methode.
Wie können hier weder sehen, wie du die Methoden aufrufst, wie du die Liste erstellst usw.
Wenn nichts anderes hilft, einfach mal durchsteppen und schauen, wo der Ablauf rausspringt. Ein grundsätzlicher Fehler in leuchten02 ist mir jedenfalls nicht aufgefallen, sie ist nur unnötig kompliziert: Zuerst schaltest du alle Lichter ein und dann erst schaltest du aus.
Die List-Klasse ist ziemlich überholungsbedürftig, aber dafür kannst du nichts (z.B. sollte next() entweder das nächste Element als Ergebnis haben oder einen Rückgabe, ob es ein nächstes Element überhaupt gibt).

Um es einfacher zu machen: Setz in Leuchten02 eine bool-Variable und laufe die Liste EINMAL durch. Nach jedem Schritt wird die Variable invertiert. Abhängig von der Variable wir AN oder AUS aufgerufen. Dann hast du kein Next im Next, das ist schon ziemlich übel.

Wenn du es flexibler willst:
Verwende eine Variable
Code:
int counter = 0;
Bei counter == 0 schalte ein, sonst aus.
Nach jedem Schritt setze counter auf
Code:
 counter = (counter + 1) % n;
, wobei n > 0 sein muss.
 
Die List-Klasse ist ziemlich überholungsbedürftig, aber dafür kannst du nichts (z.B. sollte next() entweder das nächste Element als Ergebnis haben oder einen Rückgabe, ob es ein nächstes Element überhaupt gibt).
Nein, das ist ja schon Absicht so. Ansonsten wäre es halt eine andere Art von Liste. Diese Liste verwaltet halt einfach ein "aktuelles" Element und das kann man hin- und herverschieben und abfragen ob es ein solches gibt bzw. sich dessen Inhalt geben lassen.
 
@MikaMac1407 : diese Abfrage auf hasAccess() vor dem zweiten next() bräuchtest du ja gar nicht die ist im next() selber ja auch schon drin. Es sollte doch auch gehen wenn du einfach zweimal next() aufrufst, bzw. dreimal in der leuchten03()
 
Doch, die braucht er.
Die Abfrage innerhalb des next()-Befehls dient einzig und allein dazu, damit der Zeiger sich nicht ändert, wenn er sich bereits außerhalb (hinter) der Liste befindet.
Spricht man die Liste von außen an, muss man mit hasAccess() testen, ob man sich noch nicht außerhalb der Liste befindet. Das kann nach jedem toFirst() (sofern die Liste leer ist) und next() der Fall sein.

Wie gesagt, die Klasse Liste ist schon etwas arg umständlich implementiert.
 
Nein, das ist ja schon Absicht so. Ansonsten wäre es halt eine andere Art von Liste. Diese Liste verwaltet halt einfach ein "aktuelles" Element und das kann man hin- und herverschieben und abfragen ob es ein solches gibt bzw. sich dessen Inhalt geben lassen.
Trotzdem, next() und toFirst() (und andere Verschiebeoptionen) könnten beispielsweise als Ergebnis hasAccess() liefern, dann würde man sich etwas Tiparbeit sparen.
 
Doch, die braucht er.
Tut mir leid, da muss ich dir widersprechen. Hast du dir next() angeguckt ? Da passiert genau das drin was er auch schon macht: nämlich nichts wenn hasAccess() false liefert ! So geht es genau so gut:
Code:
    public void leuchten02() {
        lichterkette.toFirst();
        while (lichterkette.hasAccess()) {
            lichterkette.getContent().lichtAN();
            lichterkette.next();

        }
        lichterkette.toFirst();
        lichterkette.next();
        while (lichterkette.hasAccess()) {

            lichterkette.getContent().lichtAUS();
            lichterkette.next();
            lichterkette.next();
        }
    }
Du kannst next() so oft aufrufen wie du willst. Entweder es passiert gar nichts (bei hasAccess() == false) oder der interne Zeiger wird auf das nächste Element gesetzt.
Aber von so Feinheit mal abgesehen ist sein Code den er gezeigt hat richtig und tut das was er soll.
 
Ja, hab ich. Dehalb meine Aussage.
Hab mich aber trotzdem geirrt, das ist mir dann ein paar Minuten später auch eingefallen, da war der Computer schon aus 🙂
Du hast recht, auf das erste könnte man verzichten.

Mein Ansatz ohne Bool-Variable wäre dieser hier
Java:
    public void leuchten02() {
        lichterkette.toFirst();
        while (lichterkette.hasAccess()) {
            lichterkette.getContent().lichtAN();
            lichterkette.next();
            if (lichterKette.hasAccess()) {
                lichterkette.getContent().lichtAUS();
                lichterkette.next();
            }
        }
    }
Ich seh nicht ein, warum man zuerst alles einschalten und dann wieder ausschalten soll.
Wenn man nur jedes dritte haben will oder 2 aus 3 oder was auch immer, einfach noch einen if-Block hinzufügen.
 
Wenn man nur jedes dritte haben will oder 2 aus 3 oder was auch immer, einfach noch einen if-Block hinzufügen.
Nein dann würde ich die Methode ändern in:
Code:
    public void leuchten(int count) {
        lichterkette.toFirst();
        while (lichterkette.hasAccess()) {
            lichterkette.getContent().lichtAN();
            lichterkette.next();

        }
        lichterkette.toFirst();
        lichterkette.next();
        while (lichterkette.hasAccess()) {

            lichterkette.getContent().lichtAUS();
            for (int i = 0; i < count; i++) {
                lichterkette.next();
            }
        }
    }
Aber es gibt sicher auch Muster wo du recht hast und es nicht so günstig ist zuerst mal alles an- oder auszuschalten !
 
Jedes n-te Element über einen Counter lösen, war der erste Vorschlag, den ich gemacht hatte. (counter = (counter + 1) % n)
Das Hinzufügen der Blöcke hätte den Vorteil, dass man jedes x-beliebige Muster einbauen kann.
Als Beispiel:
1110010110,1110010110,...
Da kommst du mathematisch nicht mehr hin. Hierfür entweder mehr Blöcke oder das Muster in einem Array hinterlegen.

Vorher alles einzuschalten ... nein, da seh ich immer noch keinen Sinn darin. Solche Listen sollten meiner Meinung nach nach Möglichkeit immer nur einmal durchlaufen werden.
 

Zurück
Oben