# Liste



## babuschka (12. Jan 2012)

Hallo, ich will gerade für eine doppelt verkettete Ringliste eine Methode schreiben, die die Listenelemente zählt, wobei man das Ankerelement nicht mitzuzählen hat.

Dabei gibt es jeweils als Attribute Daten und eine Referenz auf das nächste Listenelement, die heißt n. Und natürlich eine Referenz aufs Vorgängerelement, p genannt.

Ich stecke irgendwie fest.

Also man kann bei irgendeinem Listeneintrag anfangen zu zählen und man zählt, bis man diesen Listeneintrag wieder erreicht hat. So weit ist es mir klar.


Aber die Umsetzung...


```
public int size(){
int counter=0;
RList e = this;

[...]
```

Weiter komme ich irgendwie partout nicht...


----------



## Firephoenix (12. Jan 2012)

Zeig doch bitte mal den kompletten Code der Ringliste, mit den 3 Zeilen lässt sich schwer arbeiten.

Ansonsten sollte das umsetzen doch nicht allzu schwer sein oder?

Du musst dir nur raussuchen
-Wie du auf das nächste Element zugreifst
-Wie du 2 Objekte der Liste vergleichst

Und dann nur noch deinen Satz in Codeform bringen:


> bei irgendeinem Listeneintrag anfangen zu zählen und man zählt, bis man diesen Listeneintrag wieder erreicht hat



(nur irgendeinem Listeneintrag sollte man evtl durch Anker ersetzen  )
Gruß


----------



## babuschka (12. Jan 2012)

```
@file RList.java Listenverwaltung  in Form einer <b>doppelt
 *  verketteten Ringliste</b>.
 *
 *   <ul>
 *    <li> Jedes Listenelement m ist mit einer Referenz m.n auf den
 *          Nachfolger und einer Referenz  m.p auf den Vorgänger versehen
 *         (sog. doppelte Verkettung).
 *    <li> Jede Liste enthält immer ein sog. <b>Ankerelement</b>.
 *          Dieses  trägt niemals
 *          Nutzdaten (Komponente 'data' ist die null-Referenz).
 *    <li> Die leere Liste wird allein durch das Ankerelement
 *          repräsentiert, bei dem Nachfolger
 *          und Vorgänger auf sich selbst zeigen.
 *    <li> Bei einer nicht leeren Liste ist der Nachfolger
 *          des Ankerelementes der <b>Listenkopf</b>, d.h.
 *          das erste Nutzdaten tragende Element der Liste. Der
 *          Vorgänger des Ankerelementes ist das <b>letzte Element</b>
 *          der Liste. Umgekehrt hat der Listenkopf immer das
 *          Ankerelement als Vorgänger, und das letzte Element der
 *          Liste hat immer das Ankerelement als Nachfolger.
 *    </ul>
 *
 *  Der Vorteil einer doppelt verketteten Ringliste besteht darin, 
 *  dass Einfüge- und Löschoperationen, sowie Konkatenation 
 *   ohne spezielle Fallunterscheidungen
 *  "Liste leer/nicht leer", "Löschen des letzten Elementes" etc.
 *  auskommen.
 */

/**
 *  Aus der Klasse Rlist werden einzelne Listenelemente instanziiert.
 *  Gleichzeitig repräsentiert das Ankerelement der Liste die
 *  gesamte Liste, denn vom Ankerelement aus lässt sich jedes 
 *  Listenelement erreichen.
 */
class Rlist<T extends Comparable<T>> {
    
    /** Jeder Listeneintrag hat ein Objekt vom Typ T als Nutzdaten.
     *  Das Ankerelement l der Liste ist durch die Bedingung
     *  
     *  <code>l.data == null</code>
     *
     *  eindeutig gekennzeichnet.
     */
    private T data;
    
    /** Referenz auf das Nachfolger-Listenelement */
    private Rlist<T> n;
    
    /** Referenz auf das Vorgänger-Listenelement */
    private Rlist<T> p;
    
    /**
     *  Konstruktor Rlist() erzeugt eine neue leere
     *  Liste.
     *
     *  @return Korrekt initialisiertes Ankerelement und damit
     *           eine leere Liste, die allein durch das Ankerelement
     *           repräsentiert ist.
     */
     
     public RList(){
    	 data = null;
    	 n = this;
    	 p = this;
     }
    
     /**
     *  Methode isEmpty() prüft, ob eine Liste 
     *  leer ist.
     *
     *
     *  @return Gibt genau dann true zurück, wenn die Liste leer ist,
     *          d.h. wenn Vorgänger und Nachfolger wieder
     *          auf das Listenelement zeigen, auf dem empty()
     *          aufgerufen wird: Damit ist nachgewiesen, dass
     *          die Liste allein aus dem Ankerelement besteht.
     *  
     */
    public boolean isEmpty() {
		return ( n = this && p = this);
    }
    
    /**
     *  Methode size() berechnet die Länge
     *  einer Liste. Das Ankerelement wird 
     *  dabei <b>nicht</b> mit gezählt.
     *
     *  @return Anzahl der Listenelemente,
     *          abzüglich des Ankerelements.
     *
     *  @note Wegen der Ringverkettung kann die Methode auf ein
     *        beliebiges Listenelement aufgerufen werden.
     *        Die Zählung endet, wenn bei der Traversion der List wieder
     *        das Ursprungselement erreicht wurde.
     *  
     */
    public int size() {
		int counter=0;
		RList e = this;
		
				
		while(e.n != this){
				counter++;
				e = e.n;
			}
		return counter;
    }
    
    /**
     *  Methode clear() löscht den Listeninhalt, so dass
     *  die leere Liste zurück bleibt.
     *  Diese Methode darf nur auf das Ankerelement aufgerufen
     *  werden.
     *
     */
    public void clear() {
    }
    
    /**
     * Methode add() fügt ein neues Listenelement
     * <b>hinter</b>  dem Element ein, auf welchem 
     * die Methode aufgerufen wurde.
     *
     *  @param d Einzufügendes Nutzdatenobjekt.
     *
     *  @note Die Operation lässt sich ohne ein
     *        einziges if-statement realisieren.
     *
     *  @note add(null) ist nicht zulässig,
     *        weil ansonsten das Ankerelement nicht eindeutig
     *        bestimmbar wäre.
     *
     */
    public void add(T d) {
    }
    
    /**
     * Methode insert() fügt ein neues Listenelement
     * <b>vor</b> demjenigen ein, auf welchem die Operation
     * aufgerufen wird.
     *
     *  @param d Nutzdaten für das neu
     *         anzulegende Listenelement.
     *
     *  @note Die Operation lässt sich ohne ein
     *        einziges if-statement realisieren.
     *
     *  @note insert(null) ist nicht zulässig,
     *        weil ansonsten das Ankerelement nicht eindeutig
     *        bestimmbar wäre.
     */
    public void insert(T d) {
    }
    
    
    /**
     * Methode get() gibt den Inhalt (Nutzdaten) des
     * Listenelements zurück, auf dem die Operation
     * aufgerufen wird.
     *
     *  @return Referenz auf die Nutzdaten (kann null sein,
     *  falls es sich um das Ankerelement handelt)
     *
     */
    public T get() {
		return null;
    }
    
    /**
     * Methode next() gibt die Referenz auf 
     * den Nachfolger des Listenelements l zurück,
     * auf dem die Methode aufgerufen wird.
     *
     *  @return Nachfolger l.n von l.
     *
     */
    public Rlist<T> next() {
        return null;
    }
    
    /**
     * Methode prev() gibt die Referenz auf 
     * den Vorgänger des Listenelements l zurück, auf dem
     * die Methode aufgerufen wird.
     *
     *  @return Vorgänger l.p von l.
     *
     */
    public Rlist<T> prev() {
		return null;
    }
    
    /**
     * Methode find() sucht nach einem Listenelement l,
     * welches ein vorgegebenes Nutzdatenelement enthält,
     * und gibt die Referenz auf dieses Element l zurück,
     * falls vorhanden.  
     *
     *  @param d Nutzdatenobjekt, das unter den Listenelementen
     *           gesucht werden soll.
     *  @return null, falls d bei keinem Element als Nutzdaten
     *          eingetragen ist.
     *  @return Referenz auf das erste gefundene Listenelement sonst.
     *
     *  @note Zum Vergleich der Nutzdaten wird die Methode equals()
     *        verwendet.
     */
    public Rlist<T> find(T d) {
		return null;
    }
    
    
    
    /**
     * Methode remove() löscht das Listenelement aus der Liste,
     * auf welchem die Methode aufgerufen wurde. 
     * Wirkungslos, wenn auf dem Ankerelement aufgerufen.
     *
     *
     *  @note Diese Operation benötigt eine if-Abfrage.
     *        Warum?
     */
    public void remove() {
    }
    
    
    /**
     * Methode toString() gibt den Nutzdateninhalt der Liste als String zurück.
     *
     * Der String ist eine durch spitze Klammern eingefasste und durch Komma
     * separierte Auflistung der einzelnen Nutzdaten in der entsprechenden
     * Reihenfolge. Die einzelnen Elemente werden selbst wieder mit der
     * Methode toString() formatiert.
     * Beispielrückgabe: "<1, 2, 4, 3>"
     *
     *  Diese Methode darf nur auf das Ankerelement aufgerufen
     *  werden.
     *
     * @return Der String.
     */
    public String toString() {
		return null;
    }
    
    
    /**
     * Methode equals() vergleicht zwei Listen auf
     * inhaltliche Gleichheit.
     *
     *  Diese Methode darf nur auf das Ankerelement aufgerufen
     *  werden.
     *
     *  @param o Referenz auf Ankerelement der zweiten Liste.
     *         Die Liste darf leer sein.
     *
     *  @return false, wenn o nicht vom Typ RList ist.
     *  @return false, wenn die Listen unterschiedliche Länge haben.
     *  @return false, wenn sich die Listen bei mindestens einem Element
     *           in den Nutzdaten unterscheiden.
     *  @return true, falls die Listen dieselbe Länge, dieselben
     *          Nutzdaten und dieselbe Sortierung besitzen.
     */
    public boolean equals(Object o) {
		return false;
    }
    
    
    /**
     *  Methode addSorted() fügt das Element d in die Liste
     *  ein, so dass eine vorher aufsteigend sortierte Liste
     *  nach  Ausführung von addSorted() immer noch aufsteigend 
     *  sortiert ist.
     *  Diese Methode darf nur auf das Ankerelement aufgerufen
     *  werden.
     *
     * @param d Das einzufügende Element.
     * 
     * @note Nutzdaten werden mit der Funktion compareTo() verglichen.
     */
    public void addSorted(T d) {
    }

    /**
     * Methode isSorted() überprüft, ob die Liste aufsteigend
     * sortiert ist. Diese Methode darf nur auf das
     * Ankerelement aufgerufen werden.
     *
     * @return Gibt genau dann true zurück, wenn die Liste sortiert ist.
     * 
     * @note Nutzdaten werden mit der Funktion compareTo() verglichen.
     */
    public boolean isSorted() {
		return false;
    }
}
```

Aufgabe ist es, die Methoden zu implementieren.

Ich habe mich schon an dem Konstruktor und isEmpty() versucht.


Nun wollte ich size() probieren.


Nur: So, wie es jetzt dort steht, zählt man ein Element zu wenig... oder


----------



## Firephoenix (12. Jan 2012)

Ein paar Fehler könntest du vermeiden wenn du einfach eine IDE wie Eclipse verwenden würdest 

-Im Konstruktor: RList und Rlist sind nicht identisch!
-bei isEmpty vergleichst du mit == , = ist eine Zuweisung
-Und bei size() gehört ebenfalls Rlist und nicht RList hin.

Ob die size-Methode funktioniert müsstest du Testen, dafür benötigst du aber erstmal eine Methode mit der du einfügen kannst  sonst haben deine Testlisten wohl immer größe 0 

Gruß


----------



## babuschka (12. Jan 2012)

Danke für die Hinweise. Das ist wirklich schlampig von mir.

Tests stehen noch aus, ich wollte nur gerne wissen, ob das Bisherige okay ist oder ob ich (schon wieder) auf dem falschen Dampfer bin.

Was würdest Du sagen? Sieht size() ganz gut aus (wenn ich die Schreibfehler berichtige)?





PS. Zur der IDE: Sicher wäre es nicht verboten, so eine zu verwenden, aber richtig vorgestellt soll eine IDE erst im nächsten Semester werden (PI 2, so weit ichs mitbekommen habe).


Dann habe ich nochmal eine Frage zu der zu implementierenden Methode clear():

Diese darf nur auf das Ankerelement angewandt werden, meine Idee ist ganz grundsätzlich (da das Ankerelement keine Nutzdatan trägt, was es m.E. von allen anderen Listenelementen unterscheidet):


```
public void clear() {
    
if( this.data == null ){
    n = this;
    p = this;
    data = null;
}
}
```

Das heißt, wenn man diese Methode auf ein vom Ankerelement verschiedenes Element anwendet, hat sie keinerlei Wirkung. Wobei ich nicht weiß, ob nicht auch andere Elemente der Liste data == null erfüllen können.

Ist das korrekt?


----------



## Firephoenix (12. Jan 2012)

Die Methode size() an sich sieht erstmal nicht schlecht aus.
Ist die Liste leer kriegst du eine 0 raus - das ist trivial.
Ansonsten hangelst du dich Element für Element durch die Liste und zählst mit.
Wie gesagt - testen - insbesondere die Randfälle wie leere liste und liste nach löschen/einfügen.

Bei der clear-Methode klingt der Ansatz auch gut, spontan fällt mir auch keine andere Möglichkeit ein den Anker zu erkennen, allerdings solltest du dir da nochmal anschauen ob so etwas sinn macht:

```
if( this.data == null ){
    [...]
    data = null;
}
```

Gruß


----------



## babuschka (12. Jan 2012)

Vielen lieben Dank für die Reaktion!



Firephoenix hat gesagt.:


> Ansonsten hangelst du dich Element für Element durch die Liste und zählst mit.



Zählt man auch die richtige Anzahl? Meine Gedanken hierzu:
Man hört ein Element vor dem Element, bei man zu zählen anfing, auf zu zählen. Das müsste mit der Anzahl hinkommen (das Ankerelement zählt man so nämlich nicht mit).

Beispiel:

Anker - Element 1 - Element 2

Ich fange an zu zählen bei Element 1: Schritt von Element 1 nach Element 2 (Zähler geht auf 1), Schritt von Element 2 zum Anker (Zähler geht auf 2). Ende des Zählens und das kommt ja auch hin, da man das Ankerelement nicht mitzählen soll.

Wenn ich bei Element 2 anfange zu zählen, komme ich auch auf die Anzahl 2.

Ebenso, wenn ich beim Anker beginne zu zählen.


Und das mit dem Testen werde ich machen, das ist nämlich sowieso dann noch eine weiterführende Aufgabe. 



Firephoenix hat gesagt.:


> Bei der clear-Methode klingt der Ansatz auch gut, spontan fällt mir auch keine andere Möglichkeit ein den Anker zu erkennen, allerdings solltest du dir da nochmal anschauen ob so etwas sinn macht:
> 
> ```
> if( this.data == null ){
> ...



Okay, das ist natürlich doppelt & dreifach, da dann data ohnehin null ist.
Es reicht, die Referenzen auf this zu setzen.


Ich habe oben in der Beschreibung noch gelesen, daß das Ankerelement durch data == null eindeutig identifiziert sein soll; demnach müsste die Methode wohl so okay sein.


----------



## babuschka (13. Jan 2012)

Hallo!

Ich befasse mich nun gerade mit der Methode add(T d).

Dort steht, daß man kein einziges if-statement benötigt. Das ist mir unklar, wie das funktionieren kann.

Ich habe bisher nur Folgendes hinbekommen:

1. Fall: leere Menge, d.h. Anwenden der Methode auf das Ankerelement


```
public void add(T d){
if(d != null){

this.n = d;
this.p = d;
d.n = this;
d.p = this;
}
}
```

2. Fall: Anwenden der Methode auf ein Element bei nicht leerer Menge (das Element auf das die Methode angewandt wird ist nicht das letzte Element)


```
public void add(T d){
if(d != null){

this.n = d;
d.p = this;
d.n = this.n;
this.n.p = d;
}
}
```

3. Fall: Anwenden der Methode auf das letzte Element


```
public void add(T d){
if( d!= null){

this.n = d;
d.p = this;
d.n = this.n;
}
}
```


Ich habe hierzu also 2 Fragen:

1.) Stimmen die Einzelfälle?

2.) Wie kann man das nun zusammen und ohne if-statement(s) realisieren?



Besten Dank!



*Edit:*
Ich glaube, ich habe nicht gut genug überlegt.
Wenn ich mir das recht ansehe, kommt das Folgende doch für *alle 3* Fälle hin:


```
public void add(T d){
 if(d != null){
   this.n = d;
   d.p = this;
   d.n = this.n;
   this.n.p = d;
  }
}
```

Stimmt's?

Jetzt müsste ich bloß noch das eine if-statement wegbekommen.


----------



## Firephoenix (13. Jan 2012)

Schau dir dazu mal den Kommentar der Methode an und überleg dir was genau dein if-statement abfängt.
Gruß


----------



## babuschka (13. Jan 2012)

Ich bin gerade ein bisschen irritiert, weil der Parameter d gar kein Element, sondern nur die Nutzdaten (also data) eines hinzuzufügenden Elements sein soll?

Verstehe ich da was falsch?



Edit: Quatsch: d soll ein Nutzdatenobjekt sein, also Listenelement, aber kein Ankerelement...

Dann würde ich zumindest verbessern:


```
if(d.data != null){...}
```

Aber das if-statement kreucht da dann immer noch rum.


Edit 2:

Nee, das ist doch nicht so toll.

Ich bleibe bei if(d != null), weiß aber leider noch immer nicht, wie ich das wegbekomme. :rtfm:

Also Du hast mir den Tipp gegeben, mal zu überlegen, was ich mit diesem if-statement abfange.

Ich würde meinen, den Fall, daß das hinzuzufügende Nutzdatenobjekt auf nichts verweist...


----------



## babuschka (13. Jan 2012)

Also nochmal ein bisschen geordneter. Ich fange schon wieder an, die Hinweise zu überlesen, sorry. Das soll nicht wieder passieren, also konkret zu Deinem Hinweis: 


Was fange ich mit dem if-statement ab.
Den Fall, daß man ein Listenelement einfügt, das auf nichts verweist. (null verweist doch auf nichts)

Kann man über diese Überlegung darauf kommen, wie man das if-statement da wegbekommen kann?



*Edit:*

Achso, eine Überlegung: Als Parameter soll man ja ein Nutzdatenobjekt übergeben und das zeichnet sich ja dadurch aus, daß es Nutzdaten und eine Referenz auf Vorgänger bzw. Nachfolger hat.

Und null hat ja diese Referenzen nicht, von daher kann man das if-statement einfach weglassen, weil sowieso eine Fehlermeldung kommt, wenn man null als Parameter der Methode übergibt?

(Nur eine Idee.)


----------



## Firephoenix (13. Jan 2012)

> @note add(null) ist nicht zulässig,
> *        weil ansonsten das Ankerelement nicht eindeutig
> *        bestimmbar wäre.



Add(null) ist nicht erlaubt, da man ohne if-Bedingungen auskommen soll würde ich daraus folgern, dass man diesen fall auch nicht prüfen muss.
Gruß


----------



## babuschka (13. Jan 2012)

Also tatsächlich nur:


```
public void add(T d) {
    	this.n = d;
    	d.p = this;
    	d.n = this.n;
    	this.n.p = d;
   }
```

und das ist schon die ganze Methode?



----------------------

Macht es eigentlich einen Unterschied, daß bei der Methode insert(T d) bei der Beschreibung steht, daß d hier die Nutzdaten sind? (Bei add(T d) ist d ja das Nutzdatenobjekt).

Im Grunde sind die Methoden doch aber sehr ähnlich, nur, daß man einmal davor und einmal danach einfügt, deswegen verstehe ich nicht ganz, wieso der Parameter d unterschiedliche Bedeutungen haben soll.


Ich würde einfach meinen:


```
public void insert(T d){
   this.p = d;
   d.n. = this;
   d.p = this.p;
   this.p.n = d;
}
```

---------------------------

Dann nochmal ein paar Methoden, die ich wohl meine zu haben und gern kontrolliert hätte:


```
public T get() {
		return this.data;
    }
```

sowie


```
public Rlist<T> next() {
        return this.n;
    }
```

sowie


```
public Rlist<T> prev() {
		return this.p;
    }
```


----------



## babuschka (13. Jan 2012)

Und noch eine Methode (ergänzend zum letzten Post), von der ich gern wüsste, ob's okay ist:


```
public Rlist<T> find(T d) {
    	Rlist e = this;
    	do {
            if ( e.data.equals(d) ) {
                return e;
            }
            e = e.n;
        } while ( e != this );
        return null;       
    }
```


----------



## Firephoenix (13. Jan 2012)

Überleg dir mal was bei dem 1. Durchlauf passiert wenn e.data.equals(d) ausgewertet wird.
Gruß


----------



## babuschka (13. Jan 2012)

Hm, ich würde sagen: Wenn eine Übereinstimmung vorliegt, wird e ausgegeben, sonst e um eine Position weiterverschoben.

Stimmt daran etwas nicht?


(Bestimmt, sonst würdest Du nicht drauf hinweisen...)


Hm, ich sehe da nichts Falsches. :bahnhof:


Kannst Du noch einen Hinweis geben?


----------



## Firephoenix (13. Jan 2012)

Was passiert denn wenn du am Anker anfängst und loslegst?


```
Rlist e = this;
```
e ist jetzt dein Listenanker. Bei dem ist data ja bekanntlich null.

Jetzt prüfst du

```
f ( e.data.equals(d) )
```

also if null.equals(d)

und sobald du per Punkt-Notation Aufrufe auf einer null-referenz durchführst fliegt eine Nullpointer-Exception.

Bei solchen Fehlern bist du aber wirklich schneller wenn du dir einfach mal eine Main-Methode anlegst, dir eine Testliste erstellst (z.b. eine Liste die Strings speichert) und einfach mal deine Methoden aufrufst und mit ein paar println prüfst ob auch das herauskommt was du erwartest.

Bzw Falls ihr schon eine Testumgebung wie JUnit hattet kannst du auch dort direkt Tests für deine Liste anlegen und einfach mal prüfen ob das herauskommt was du erwartest.

Das macht es einfacher und ist schneller als nach jedem Stück Code einen Post zu erstellen 

Gruß


----------



## babuschka (13. Jan 2012)

Diese fiese NullPointerException immer.
Die habe ich noch nie so richtig verstanden.

Aber wenn ich so frage, lerne ich am meisten. Aber ich werde versuchen, weniger zu posten und mehr zu testen.


Ich würde dann also am liebsten sowas vorschlagen:


```
public Rlist<T> find(T d) {
    	Rlist e = this;
    	do {
            if ( e.data != null && e.data.equals(d) ) {
                return e;
            }
            e = e.n;
        } while ( e != this );
        return null;       
    }
```

:toll: oder  ?

---------------------------

Ich hoffe, es nervt Dich nicht allzu sehr, aber hier ist noch eine Methode, auf die Du vllt. mal ein Auge werfen kannst, wenn Du Lust hast. Das ist meine Idee zur Methode remove():


```
public void remove() {
    	if(this.data != null){
    		this.p.n = this.n;
    		this.n.p = this.p;
    	}
    }
```

Im Kommentarteil ist gefragt, wieso man hier ein if-statement braucht.
Meine Antwort ist: Damit man ausschließen kann, daß man die Methode auf das Ankerelement anwendet (s. Code, Zeile 2). Wäre das die richtige Antwort?


----------



## Firephoenix (13. Jan 2012)

Klingt doch brauchbar, wie siehts denn mit deiner Ausgabe aus wenn du die Methoden einfach mal laufen lässt?

Müsst ihr für die Klasse eigentlich eine Testsuite mit z.B. JUnit einrichten um zu prüfen ob eure Methoden auch der Funktion entsprechen oder wird das später erst bei der Abgabe von demjenigen gemacht der das ganze bewertet?

Gruß


----------



## babuschka (13. Jan 2012)

Wenn Du mit Ausgabe das Kompilieren meinst, so bekomme ich die Fehlermeldungen, die ich als Screenshot angefügt habe und nicht gut verstehe.


Ja, wir sollen mit JUnit eine Testsuite schreiben, das ist Aufgabe Nr. 2.

--------------------------------------

Nochmal eine weitere Frage:

Meine Idee zu toString():


```
public String toString() {
    	if(this.data == null){
    	
		    String s = new String();
		    for(Rlist e = this.n; e != this; e.next() ){
		    	s += e.get().toString() + "\n";
		    }
    		  return s;
    		}
    }
```


Allerdings weiß ich nicht, wie ich die gewünschte Ausgabe mit den eckigen Klammern und den Kommata realisieren kann, jetzt habe ich ja nur, daß die Listenelemente (abzüglich des Ankerlements)untereinander ausgegeben werden oder?


Es soll ja aber <Element 1, Element 2,...> sein.

Wie macht man sowas?


----------



## Firephoenix (13. Jan 2012)

Erstmal die aktuellen Fehler raus bevor du weitere Methoden schreibst, Java ist bei den Fehlermeldungen auch relativ freundlich (ich erinner mich da nur an meine Assembler-Versuche: 200 Zeilen Registermatsch und als Fehlermeldung kommt: Segmentation Fault :applaus

Der erste Fehler tritt bei dir in Zeile 139 auf, hier hast du offenbar eine Zuweisung und versuchst ein Objekt vom Typ T in ein Objekt vom Typ Rlist<T> zu packen -> das geht logischerweise schief.
Vermutlich musst du hier erst das T-Objekt in ein neues Rlist-Objekt stecken.

Bei den nächsten 2 Fehlermeldungen in Zeile 140/141 hast du ein ähnliches Problem, diese sind vom Typ T implements Comparable und nicht vom Typ Rlist<T> , du kannst hier nicht auf .n oder .p zugreifen.

142 und 161 sind das gleiche Problem wie in Zeile 139

162 und 163 das gleiche wie 140/141

und 164 wieder das gleiche wie 139

Die Mal beheben und neu versuchen, falls neue Fehler finden erstmal das neue Wissen anwenden und schauen ob du sie beheben kannst (die meisten lösen sich auf wenn man sich nur den Text anschaut und dann die Zeile, gerade sowas wie incompatible types findet man in einer Zeile x = y sehr schnell wenn man sich einfach überlegt welchen Typ x und y haben können)
Gruß


----------



## babuschka (13. Jan 2012)

Kurze Zwischenfrage zur Fehlerbehebung Zeile 139 nach Deinem Vorschlag:

Um ein neues Rlist - Objekt zu erzeuge, das das T - Objekt enthält, muss ich erst einen zusätzlichen Konstruktor schreiben, oder? Bisher habe ich ja nur einen, der die leere Menge erzeugt, aber keinen, der dafür sorgt, daß eine Liste erzeugt wird, die ein als Parameter übergebenes Element enthält.

Mein erster Gedanke war, eine leere Liste zu erzeugen und dann mit add(d) das Element d hinzuzufügen, aber das geht ja nicht, weil der Fehler gerade im Rumpf der Methode add(T d) auftaucht.


Wenn ja, wie könnte dieser Konstruktor aussehen?
Bin da gerade ein bisschen ratlos.


----------



## Firephoenix (13. Jan 2012)

du willst ja auch keine Leere Liste erzeugen und dann add an die Leere Liste hängen und die einfügen, dann kriegst du ja sowas:

Anker(data = null) - Leere Liste (data = null) - data
(was von den Typen her auch nicht geht)

Besser wäre statdessen:

Anker(data=null)
->
Anker(data=null) - Leere Liste (data = null)
->
Anker(data = null) - Leere Liste (data = d)

Natürlich kannst du auch erst die data setzen und dann anhängen, wichtig ist, dass du am Ende eine Ringliste bekommst die um 1 größer ist und bei der hinter deinem aktuellem Element ein neues eingefügt wurde dessen data-feld das einzufügende data-feld speichert.

Gruß


----------



## babuschka (13. Jan 2012)

Oh, das habe ich nicht verstanden.

Anker - Leere Liste

Das ist der 1. Schritt. Also mit dem Konstruktor eine leere Liste erzeugen. Und noch eine leere Liste erzeugen. Und die an die erste dranhängen.

Und dann bei der zweiten Liste data=d setzen und die entsprechenden Referenzen, dann hat man eine Liste Anker - Element 1 mit data==d



So?

Was ich aber, wie gesagt, nicht verstanden habe: Wie kann ich das denn anhängen? Add kann ich ja nicht benutzen,wenn ich da den Fehler habe?


*EDIT*: Ich hab Dich doch richtig verstanden, daß Du mir beschrieben hast, wie man den Konstruktor schreiben muss? Und darf ich den Konstruktor, der die leere Liste erzeugt, ínnerhalb dieses Konstruktors verwenden??

Dann würde ich es glaube ich verstanden haben.

Der Konstruktor wäre dann nach meiner Idee:


```
public Rlist(T d){

Rlist<T> l = new Rlist<T>();
Rlist<T> m = new Rlist<T>();
m.data = d;
m.n = l;
m.p =l;
l.n = m;
l.p =m;
}
```

Ich hoffe, das ist okay! Ansonsten habe ich wieder Murks produziert...


----------



## babuschka (13. Jan 2012)

Ich hoffe, mein Edit im letzten Post gleicht die blöde Frage davor wieder aus. 

(Wenn das stimmt. Bin mir nämlich (wie immer) nicht sicher.)


----------



## Firephoenix (13. Jan 2012)

```
Rlist<T> m = new Rlist<T>();
m.data = d;
```

Damit kriegst du doch genau das was du willst - eine Liste die die neuen Daten enthält die du einfügen willst.
Jetzt musst du die Liste nur noch richtig in die andere Liste hängen, der richtige Ort dafür ist genau die add()-Methode (kein neuer Konstruktor )
Gruß


----------



## babuschka (13. Jan 2012)

Achso!


```
public void add(T d){
Rlist<T> m = new Rlist<T>();
m.data = d;

this.n = m;
m.p = this;
m.n = this.n;
this.n.p = m;
}
```

Kompilieren zeigt:

Die Fehleranzahl hat sich auf 4 reduziert, also kann's so verkehrt nicht sein. :toll:


Jetzt hab ichs auch kapiert!

Danke hoch drei!

:idea:



Um die restlichen Fehler kümmere ich mich später, für heute ist Feierabend.


----------



## babuschka (14. Jan 2012)

Hallo und guten "Morgen",

ich habe jetzt die Fehler, wie ich sie als Screenshot gepostet hatte beseitigt, es bleibt noch folgende Konsolenausgabe übrig (s. Screenshot).

Was hat das zu bedeuten bzw. wie behebe ich das?

----------------------

Dann kann ich ja jetzt mit der Methode toString() weitermachen. 
Da habe ich folgenden Code:


```
public String toString() {
    	String s = new String();
    	
    	if(this.data == null){
	      for(Rlist e = this.n; e != this; e.next() ){
		    	s += e.get().toString() + "\n";
		    }
    	}
   
    	return s;		
    }
```

Ich weiß allerdings nicht, wie ich die gewünschte Ausgabe machen kann, also in spitzen Klammern und die Listeneinträge mit Kommata voneinander getrennt...

Könnte ich da einen Tipp bekommen?



LG


----------



## Firephoenix (14. Jan 2012)

Zeig mal den Code von der kompletten Klasse wegen der unchecked-Meldung.

Für die toString:
Am Anfang und am Ende steht immer ein "<" und ein ">".
Warum fügst du dann nicht einfach am Anfang und am Ende der Methode die Zeichen an den String an?
Dann musst du nur noch einmal über die Liste laufen und den rest in den String packen.
Gruß


----------



## babuschka (14. Jan 2012)

```
public String toString() {
    	String s = new String();
    	
    	if(this.data == null){
	      for(Rlist e = this.n; e != this; e.next() ){
		    	s += e.get().toString() + ",";
		    }
    	}
   
    	return "<" + s + ">";		
    }
```

Meinst Du das so?

----------------------

Okay, hier ist die ganze Klasse:


```
/** 
 *  @file RList.java Listenverwaltung  in Form einer <b>doppelt
 *  verketteten Ringliste</b>.
 *
 *   <ul>
 *    <li> Jedes Listenelement m ist mit einer Referenz m.n auf den
 *          Nachfolger und einer Referenz  m.p auf den Vorgänger versehen
 *         (sog. doppelte Verkettung).
 *    <li> Jede Liste enthält immer ein sog. <b>Ankerelement</b>.
 *          Dieses  trägt niemals
 *          Nutzdaten (Komponente 'data' ist die null-Referenz).
 *    <li> Die leere Liste wird allein durch das Ankerelement
 *          repräsentiert, bei dem Nachfolger
 *          und Vorgänger auf sich selbst zeigen.
 *    <li> Bei einer nicht leeren Liste ist der Nachfolger
 *          des Ankerelementes der <b>Listenkopf</b>, d.h.
 *          das erste Nutzdaten tragende Element der Liste. Der
 *          Vorgänger des Ankerelementes ist das <b>letzte Element</b>
 *          der Liste. Umgekehrt hat der Listenkopf immer das
 *          Ankerelement als Vorgänger, und das letzte Element der
 *          Liste hat immer das Ankerelement als Nachfolger.
 *    </ul>
 *
 *  Der Vorteil einer doppelt verketteten Ringliste besteht darin, 
 *  dass Einfüge- und Löschoperationen, sowie Konkatenation 
 *   ohne spezielle Fallunterscheidungen
 *  "Liste leer/nicht leer", "Löschen des letzten Elementes" etc.
 *  auskommen.
 */

/**
 *  Aus der Klasse Rlist werden einzelne Listenelemente instanziiert.
 *  Gleichzeitig repräsentiert das Ankerelement der Liste die
 *  gesamte Liste, denn vom Ankerelement aus lässt sich jedes 
 *  Listenelement erreichen.
 */
class Rlist<T extends Comparable<T>> {
    
    /** Jeder Listeneintrag hat ein Objekt vom Typ T als Nutzdaten.
     *  Das Ankerelement l der Liste ist durch die Bedingung
     *  
     *  <code>l.data == null</code>
     *
     *  eindeutig gekennzeichnet.
     */
    private T data;
    
    /** Referenz auf das Nachfolger-Listenelement */
    private Rlist<T> n;
    
    /** Referenz auf das Vorgänger-Listenelement */
    private Rlist<T> p;
    
    /**
     *  Konstruktor Rlist() erzeugt eine neue leere
     *  Liste.
     *
     *  @return Korrekt initialisiertes Ankerelement und damit
     *           eine leere Liste, die allein durch das Ankerelement
     *           repräsentiert ist.
     */
     
     public Rlist(){
    	 data = null;
    	 n = this;
    	 p = this;
     }
    
     
     
     /**
     *  Methode isEmpty() prüft, ob eine Liste 
     *  leer ist.
     *
     *
     *  @return Gibt genau dann true zurück, wenn die Liste leer ist,
     *          d.h. wenn Vorgänger und Nachfolger wieder
     *          auf das Listenelement zeigen, auf dem empty()
     *          aufgerufen wird: Damit ist nachgewiesen, dass
     *          die Liste allein aus dem Ankerelement besteht.
     *  
     */
    public boolean isEmpty() {
		return ( n == this && p == this);
    }
    
    /**
     *  Methode size() berechnet die Länge
     *  einer Liste. Das Ankerelement wird 
     *  dabei <b>nicht</b> mit gezählt.
     *
     *  @return Anzahl der Listenelemente,
     *          abzüglich des Ankerelements.
     *
     *  @note Wegen der Ringverkettung kann die Methode auf ein
     *        beliebiges Listenelement aufgerufen werden.
     *        Die Zählung endet, wenn bei der Traversion der List wieder
     *        das Ursprungselement erreicht wurde.
     *  
     */
    public int size() {
		int counter=0;
		Rlist<T> e = this;
		
		while(e.n != this){
				counter++;
				e = e.n;
			}
		return counter;
    }
    
    /**
     *  Methode clear() löscht den Listeninhalt, so dass
     *  die leere Liste zurück bleibt.
     *  Diese Methode darf nur auf das Ankerelement aufgerufen
     *  werden.
     *
     */
    public void clear() {
	    if(this.data==null){
		    n = this;
		    p = this;
   }
}
    /**
     * Methode add() fügt ein neues Listenelement
     * <b>hinter</b>  dem Element ein, auf welchem 
     * die Methode aufgerufen wurde.
     *
     *  @param d Einzufügendes Nutzdatenobjekt.
     *
     *  @note Die Operation lässt sich ohne ein
     *        einziges if-statement realisieren.
     *
     *  @note add(null) ist nicht zulässig,
     *        weil ansonsten das Ankerelement nicht eindeutig
     *        bestimmbar wäre.
     *
     */
    public void add(T d){
    	Rlist<T> m = new Rlist<T>();
    	m.data = d;
    	this.n = m;
    	m.p = this;
    	m.n = this.n;
    	this.n.p = m;
   }
    
    /**
     * Methode insert() fügt ein neues Listenelement
     * <b>vor</b> demjenigen ein, auf welchem die Operation
     * aufgerufen wird.
     *
     *  @param d Nutzdaten für das neu
     *         anzulegende Listenelement.
     *
     *  @note Die Operation lässt sich ohne ein
     *        einziges if-statement realisieren.
     *
     *  @note insert(null) ist nicht zulässig,
     *        weil ansonsten das Ankerelement nicht eindeutig
     *        bestimmbar wäre.
     */
    public void insert(T d) {
    	Rlist<T> m = new Rlist<T>();
    	m.data = d;
    	this.p = m;
    	m.n = this;
    	m.p = this.p;
    	this.p.n = m;
    }
    
    
    /**
     * Methode get() gibt den Inhalt (Nutzdaten) des
     * Listenelements zurück, auf dem die Operation
     * aufgerufen wird.
     *
     *  @return Referenz auf die Nutzdaten (kann null sein,
     *  falls es sich um das Ankerelement handelt)
     *
     */
    public T get() {
		return this.data;
    }
    
    /**
     * Methode next() gibt die Referenz auf 
     * den Nachfolger des Listenelements l zurück,
     * auf dem die Methode aufgerufen wird.
     *
     *  @return Nachfolger l.n von l.
     *
     */
    public Rlist<T> next() {
        return this.n;
    }
    
    /**
     * Methode prev() gibt die Referenz auf 
     * den Vorgänger des Listenelements l zurück, auf dem
     * die Methode aufgerufen wird.
     *
     *  @return Vorgänger l.p von l.
     *
     */
    public Rlist<T> prev() {
		return this.p;
    }
    
    /**
     * Methode find() sucht nach einem Listenelement l,
     * welches ein vorgegebenes Nutzdatenelement enthält,
     * und gibt die Referenz auf dieses Element l zurück,
     * falls vorhanden.  
     *
     *  @param d Nutzdatenobjekt, das unter den Listenelementen
     *           gesucht werden soll.
     *  @return null, falls d bei keinem Element als Nutzdaten
     *          eingetragen ist.
     *  @return Referenz auf das erste gefundene Listenelement sonst.
     *
     *  @note Zum Vergleich der Nutzdaten wird die Methode equals()
     *        verwendet.
     */
    public Rlist<T> find(T d) {
    	Rlist e = this;
    	do {
            if ( e.data != null && e.data.equals(d) ) {
                return e;
            }
            e = e.n;
        } while ( e != this );
        return null;       
    }
    
    
    
    /**
     * Methode remove() löscht das Listenelement aus der Liste,
     * auf welchem die Methode aufgerufen wurde. 
     * Wirkungslos, wenn auf dem Ankerelement aufgerufen.
     *
     *
     *  @note Diese Operation benötigt eine if-Abfrage.
     *        Warum?
     */
    public void remove() {
    	if(this.data != null){
    		this.p.n = this.n;
    		this.n.p = this.p;
    	}
    }
    
    
    /**
     * Methode toString() gibt den Nutzdateninhalt der Liste als String zurück.
     *
     * Der String ist eine durch spitze Klammern eingefasste und durch Komma
     * separierte Auflistung der einzelnen Nutzdaten in der entsprechenden
     * Reihenfolge. Die einzelnen Elemente werden selbst wieder mit der
     * Methode toString() formatiert.
     * Beispielrückgabe: "<1, 2, 4, 3>"
     *
     *  Diese Methode darf nur auf das Ankerelement aufgerufen
     *  werden.
     *
     * @return Der String.
     */
    public String toString() {
    	String s = new String();
    	
    	if(this.data == null){
	      for(Rlist e = this.n; e != this; e.next() ){
		    	s += e.get().toString() + ",";
		    }
    	}
   
    	return "<" + s + ">";		
    }
    
    	
    /**
     * Methode equals() vergleicht zwei Listen auf
     * inhaltliche Gleichheit.
     *
     *  Diese Methode darf nur auf das Ankerelement aufgerufen
     *  werden.
     *
     *  @param o Referenz auf Ankerelement der zweiten Liste.
     *         Die Liste darf leer sein.
     *
     *  @return false, wenn o nicht vom Typ RList ist.
     *  @return false, wenn die Listen unterschiedliche Länge haben.
     *  @return false, wenn sich die Listen bei mindestens einem Element
     *           in den Nutzdaten unterscheiden.
     *  @return true, falls die Listen dieselbe Länge, dieselben
     *          Nutzdaten und dieselbe Sortierung besitzen.
     */
    public boolean equals(Object o) {
		return false;
    }
    
    
    /**
     *  Methode addSorted() fügt das Element d in die Liste
     *  ein, so dass eine vorher aufsteigend sortierte Liste
     *  nach  Ausführung von addSorted() immer noch aufsteigend 
     *  sortiert ist.
     *  Diese Methode darf nur auf das Ankerelement aufgerufen
     *  werden.
     *
     * @param d Das einzufügende Element.
     * 
     * @note Nutzdaten werden mit der Funktion compareTo() verglichen.
     */
    public void addSorted(T d) {
    }

    /**
     * Methode isSorted() überprüft, ob die Liste aufsteigend
     * sortiert ist. Diese Methode darf nur auf das
     * Ankerelement aufgerufen werden.
     *
     * @return Gibt genau dann true zurück, wenn die Liste sortiert ist.
     * 
     * @note Nutzdaten werden mit der Funktion compareTo() verglichen.
     */
    public boolean isSorted() {
		return false;
    }
}
```


----------



## Firephoenix (14. Jan 2012)

Bin mal drüber gegangen bzgl des unchecked:
aus der Methode find:


```
public Rlist<T> find(T d) {
        Rlist e = this;
        do {
            if ( e.data != null && e.data.equals(d) ) {
                return e;
            }
            e = e.n;
        } while ( e != this );
        return null;       
    }
```

e ist nur eine Rlist ohne generische Typisierung, zurückliefern willst du aber eine Rlist<T>, hier musst du korrekt typisieren (gleiches typproblem auch in der toString)

Und in der toString hast du auch noch einen anderen kleinen Fehler eingebaut, den findest du aber sofort wenn du toString mal auf einer nicht-leeren Liste ausführst 

Gruß


----------



## babuschka (14. Jan 2012)

Was ein fehlendes <T> alles auslösen kann...

Also da habe ich jetzt:


```
public Rlist<T> find(T d) {
    	Rlist<T> e = this;
    	do {
            if ( e.data != null && e.data.equals(d) ) {
                return e;
            }
            e = e.n;
        } while ( e != this );
        return null;       
    }
```

Es kommt auch beim Kompilieren keine Fehlermeldung bzw. auch sonst keine Ausgabe mehr.

-----------------

Bei toString() sehe ich jedoch nicht, wo etwas falsch ist.
Ich glaube nur, daß das Komma da falsch steht.

Wenn ich zum Beispiel eine Liste habe, die ein Element hat, also

Anker - Element 1

so wäre die Ausgabe wohl nicht

<Element 1>, sondern <Element 1,>...


----------



## Firephoenix (14. Jan 2012)

```
public static void main( String[] args )
    {
        Rlist<String> rlist = new Rlist<String>();
        System.out.println(rlist.toString());
        rlist.add( "Hello" );
        System.out.println(rlist.toString());
        rlist.add( "World" );
        System.out.println(rlist.toString());
    }
```

Meine Ausgabe (mit meiner Version):


> <>
> <Hello>
> <World, World>



Bekommst du eine identische Ausgabe?
(sowas ist auch eine gute Gelegenheit direkt mit den Tests anzufangen - hier sei dir nochmal zu eclipse geraten - da schreibste die tests in JUnit, drückst auf den run-test button und kriegst nen schicken grünen balken wenns geht  )
Gruß


----------



## babuschka (14. Jan 2012)

Nein, ich bekomme als Ausgabe nur

<>


:autsch:


-----

Sollte es bei Dir heißen: <Hello,World> oder wirklich <World, World>?


----------



## Firephoenix (14. Jan 2012)

> Methode toString() gibt den Nutzdateninhalt der Liste als String zurück. Der String ist eine durch spitze
> * Klammern eingefasste und durch Komma separierte Auflistung der einzelnen Nutzdaten in der entsprechenden
> * Reihenfolge. Die einzelnen Elemente werden selbst wieder mit der Methode toString() formatiert. Beispielrückgabe:
> * "<1, 2, 4, 3>" Diese Methode darf nur auf das Ankerelement aufgerufen werden.



Der Fehler der dafür sorgt, dass deine Liste leer bleibt kann auch gut in deiner add-Methode liegen.

Mal dir mal auf einem Papier auf was du für Elemente hast (jeweils mit data, next und prev-teil) und geh dann den Code per Hand durch um zu prüfen ob am Ende auch das herauskommt was du willst:


```
Rlist<T> m = new Rlist<T>();
        m.data = d;
        this.n = m;
        m.p = this;
        m.n = this.n;
        this.n.p = m;
```

Gruß


----------



## babuschka (14. Jan 2012)

Für mich ist bei der Methode add() so alles okay.

Habe es mal durchgespielt...





Das verwirrt mich jetzt dann doch ein bisschen.


----------



## Firephoenix (14. Jan 2012)

Sicher?

Gruß

Edit: 333 Posts sehe ich gerade - Schnapszahl


----------



## babuschka (14. Jan 2012)

Ich habe wohl den Fehler gemacht, daß ich Werte zuweise und später diese Variablen wieder verwende.

Nützt es was die Reihenfolge zu ändern?

Ich habe jetzt dies überlegt an der Skizze von Dir:


```
public void add(T d){
    	Rlist<T> m = new Rlist<T>();
    	m.data = d;
    	m.n = this.n;
             m.p = this;
             this.n = m;
             m.n.p = m;

   }
```


Edit: Nee, das ändert auch nix, ich glaube ich habe den gleichen Fehler wieder gemacht.


----------



## Firephoenix (14. Jan 2012)

Rlist<T> newElement = new Rlist<T>();
        newElement.data = d;
        newElement.n = this.n;
        this.n.p = newElement;
        this.n = newElement;
        newElement.p = this;


Geh doch einfach mal Schritt für Schritt drüber 

1. Neues Element erzeugen und data setzen.
Jetzt willst du die 2 Elemente verbinden.
Was du direkt kennst, ohne etwas kaputt zu machen ist, das du den Vorgänger des neuen Elementes setzt, das ist ja dein aktuelles Element.
das nächste Element hinter deinem aktuellem Kennt allerdings das neue als vorgänger nicht nicht, also teilst du diesem jetzt mit, dass es einen neuen Vorgänger hat.

Jetzt hast du das neue und dein voriges folgeElement verknüpft.
Was noch fehlt ist das neue Element mit dem aktuellem,
Also hängst du das neue an dein aktuelles und dann dein aktuelles element noch als vorgänger an das neue element.

Wenn du den Vorgang einfach mal auf dem Papier aufmals (auch mal mit mehr Elementen) kommst du da wesentlich schneller drauf 
15 Minuten Papier und Zeichnen können 2-3 Stunden probieren und Fehlersuche vermeiden.
Gruß


----------



## babuschka (14. Jan 2012)

Jetzt habe ich es verstanden.

Aber auch damit wird immer nur noch <> ausgegeben. 


:noe:


Edit: Achso und was ich noch dazu sagen sollte:

Wenn ich also java Rlist eingebe...

Erscheint <> und dann kann man nichts mehr machen, so, als wenn es laden und laden und laden würde.


----------



## babuschka (14. Jan 2012)

Da ich mir jeden noch so blöden Fehler zutraue...

Mal eine Frage... habe ich die main-Methode denn überhaupt richtig eingefügt...

Vielleicht liegt die komische Ausgabe einfach daran, daß ich das wieder falsch gemacht habe?!


Ich habe die main-methode einfach unten an die Klasse gemacht:


```
/** 
 *  @file RList.java Listenverwaltung  in Form einer <b>doppelt
 *  verketteten Ringliste</b>.
 *
 *   <ul>
 *    <li> Jedes Listenelement m ist mit einer Referenz m.n auf den
 *          Nachfolger und einer Referenz  m.p auf den Vorgänger versehen
 *         (sog. doppelte Verkettung).
 *    <li> Jede Liste enthält immer ein sog. <b>Ankerelement</b>.
 *          Dieses  trägt niemals
 *          Nutzdaten (Komponente 'data' ist die null-Referenz).
 *    <li> Die leere Liste wird allein durch das Ankerelement
 *          repräsentiert, bei dem Nachfolger
 *          und Vorgänger auf sich selbst zeigen.
 *    <li> Bei einer nicht leeren Liste ist der Nachfolger
 *          des Ankerelementes der <b>Listenkopf</b>, d.h.
 *          das erste Nutzdaten tragende Element der Liste. Der
 *          Vorgänger des Ankerelementes ist das <b>letzte Element</b>
 *          der Liste. Umgekehrt hat der Listenkopf immer das
 *          Ankerelement als Vorgänger, und das letzte Element der
 *          Liste hat immer das Ankerelement als Nachfolger.
 *    </ul>
 *
 *  Der Vorteil einer doppelt verketteten Ringliste besteht darin, 
 *  dass Einfüge- und Löschoperationen, sowie Konkatenation 
 *   ohne spezielle Fallunterscheidungen
 *  "Liste leer/nicht leer", "Löschen des letzten Elementes" etc.
 *  auskommen.
 */

/**
 *  Aus der Klasse Rlist werden einzelne Listenelemente instanziiert.
 *  Gleichzeitig repräsentiert das Ankerelement der Liste die
 *  gesamte Liste, denn vom Ankerelement aus lässt sich jedes 
 *  Listenelement erreichen.
 */
class Rlist<T extends Comparable<T>> {
    
    /** Jeder Listeneintrag hat ein Objekt vom Typ T als Nutzdaten.
     *  Das Ankerelement l der Liste ist durch die Bedingung
     *  
     *  <code>l.data == null</code>
     *
     *  eindeutig gekennzeichnet.
     */
    private T data;
    
    /** Referenz auf das Nachfolger-Listenelement */
    private Rlist<T> n;
    
    /** Referenz auf das Vorgänger-Listenelement */
    private Rlist<T> p;
    
    /**
     *  Konstruktor Rlist() erzeugt eine neue leere
     *  Liste.
     *
     *  @return Korrekt initialisiertes Ankerelement und damit
     *           eine leere Liste, die allein durch das Ankerelement
     *           repräsentiert ist.
     */
     
     public Rlist(){
    	 data = null;
    	 n = this;
    	 p = this;
     }
    
     
     
     /**
     *  Methode isEmpty() prüft, ob eine Liste 
     *  leer ist.
     *
     *
     *  @return Gibt genau dann true zurück, wenn die Liste leer ist,
     *          d.h. wenn Vorgänger und Nachfolger wieder
     *          auf das Listenelement zeigen, auf dem empty()
     *          aufgerufen wird: Damit ist nachgewiesen, dass
     *          die Liste allein aus dem Ankerelement besteht.
     *  
     */
    public boolean isEmpty() {
		return ( n == this && p == this);
    }
    
    /**
     *  Methode size() berechnet die Länge
     *  einer Liste. Das Ankerelement wird 
     *  dabei <b>nicht</b> mit gezählt.
     *
     *  @return Anzahl der Listenelemente,
     *          abzüglich des Ankerelements.
     *
     *  @note Wegen der Ringverkettung kann die Methode auf ein
     *        beliebiges Listenelement aufgerufen werden.
     *        Die Zählung endet, wenn bei der Traversion der List wieder
     *        das Ursprungselement erreicht wurde.
     *  
     */
    public int size() {
		int counter=0;
		Rlist<T> e = this;
		
		while(e.n != this){
				counter++;
				e = e.n;
			}
		return counter;
    }
    
    /**
     *  Methode clear() löscht den Listeninhalt, so dass
     *  die leere Liste zurück bleibt.
     *  Diese Methode darf nur auf das Ankerelement aufgerufen
     *  werden.
     *
     */
    public void clear() {
	    if(this.data==null){
		    n = this;
		    p = this;
   }
}
    /**
     * Methode add() fügt ein neues Listenelement
     * <b>hinter</b>  dem Element ein, auf welchem 
     * die Methode aufgerufen wurde.
     *
     *  @param d Einzufügendes Nutzdatenobjekt.
     *
     *  @note Die Operation lässt sich ohne ein
     *        einziges if-statement realisieren.
     *
     *  @note add(null) ist nicht zulässig,
     *        weil ansonsten das Ankerelement nicht eindeutig
     *        bestimmbar wäre.
     *
     */
    public void add(T d){
    	Rlist<T> m = new Rlist<T>();
    	m.data = d;
    	m.n = this.n;
    	this.n.p = m;
    	this.n = m;
    	m.p = this;
    	
    }
    
    /**
     * Methode insert() fügt ein neues Listenelement
     * <b>vor</b> demjenigen ein, auf welchem die Operation
     * aufgerufen wird.
     *
     *  @param d Nutzdaten für das neu
     *         anzulegende Listenelement.
     *
     *  @note Die Operation lässt sich ohne ein
     *        einziges if-statement realisieren.
     *
     *  @note insert(null) ist nicht zulässig,
     *        weil ansonsten das Ankerelement nicht eindeutig
     *        bestimmbar wäre.
     */
    public void insert(T d) {
    	Rlist<T> m = new Rlist<T>();
    	m.data = d;
    	m.p = this.p;
    	this.p.n = m;
    	this.p = m;
    	m.n = this;
    }
    
    
    /**
     * Methode get() gibt den Inhalt (Nutzdaten) des
     * Listenelements zurück, auf dem die Operation
     * aufgerufen wird.
     *
     *  @return Referenz auf die Nutzdaten (kann null sein,
     *  falls es sich um das Ankerelement handelt)
     *
     */
    public T get() {
		return this.data;
    }
    
    /**
     * Methode next() gibt die Referenz auf 
     * den Nachfolger des Listenelements l zurück,
     * auf dem die Methode aufgerufen wird.
     *
     *  @return Nachfolger l.n von l.
     *
     */
    public Rlist<T> next() {
        return this.n;
    }
    
    /**
     * Methode prev() gibt die Referenz auf 
     * den Vorgänger des Listenelements l zurück, auf dem
     * die Methode aufgerufen wird.
     *
     *  @return Vorgänger l.p von l.
     *
     */
    public Rlist<T> prev() {
		return this.p;
    }
    
    /**
     * Methode find() sucht nach einem Listenelement l,
     * welches ein vorgegebenes Nutzdatenelement enthält,
     * und gibt die Referenz auf dieses Element l zurück,
     * falls vorhanden.  
     *
     *  @param d Nutzdatenobjekt, das unter den Listenelementen
     *           gesucht werden soll.
     *  @return null, falls d bei keinem Element als Nutzdaten
     *          eingetragen ist.
     *  @return Referenz auf das erste gefundene Listenelement sonst.
     *
     *  @note Zum Vergleich der Nutzdaten wird die Methode equals()
     *        verwendet.
     */
    public Rlist<T> find(T d) {
    	Rlist<T> e = this;
    	do {
            if ( e.data != null && e.data.equals(d) ) {
                return e;
            }
            e = e.n;
        } while ( e != this );
        return null;       
    }
    
    
    
    /**
     * Methode remove() löscht das Listenelement aus der Liste,
     * auf welchem die Methode aufgerufen wurde. 
     * Wirkungslos, wenn auf dem Ankerelement aufgerufen.
     *
     *
     *  @note Diese Operation benötigt eine if-Abfrage.
     *        Warum?
     */
    public void remove() {
    	if(this.data != null){
    		this.p.n = this.n;
    		this.n.p = this.p;
    	}
    }
    
    
    /**
     * Methode toString() gibt den Nutzdateninhalt der Liste als String zurück.
     *
     * Der String ist eine durch spitze Klammern eingefasste und durch Komma
     * separierte Auflistung der einzelnen Nutzdaten in der entsprechenden
     * Reihenfolge. Die einzelnen Elemente werden selbst wieder mit der
     * Methode toString() formatiert.
     * Beispielrückgabe: "<1, 2, 4, 3>"
     *
     *  Diese Methode darf nur auf das Ankerelement aufgerufen
     *  werden.
     *
     * @return Der String.
     */
    public String toString() {
    	String s = new String();
    	
    	if(this.data == null){
	      for(Rlist e = this.n; e != this; e.next() ){
		    	s += e.get().toString() + ",";
		    }
	      return "<" + s + ">";
    	}
    	
    	return "<" + s + ">";
   
    			
    }
    
    	
    /**
     * Methode equals() vergleicht zwei Listen auf
     * inhaltliche Gleichheit.
     *
     *  Diese Methode darf nur auf das Ankerelement aufgerufen
     *  werden.
     *
     *  @param o Referenz auf Ankerelement der zweiten Liste.
     *         Die Liste darf leer sein.
     *
     *  @return false, wenn o nicht vom Typ RList ist.
     *  @return false, wenn die Listen unterschiedliche Länge haben.
     *  @return false, wenn sich die Listen bei mindestens einem Element
     *           in den Nutzdaten unterscheiden.
     *  @return true, falls die Listen dieselbe Länge, dieselben
     *          Nutzdaten und dieselbe Sortierung besitzen.
     */
    public boolean equals(Object o) {
		return false;
    }
    
    
    /**
     *  Methode addSorted() fügt das Element d in die Liste
     *  ein, so dass eine vorher aufsteigend sortierte Liste
     *  nach  Ausführung von addSorted() immer noch aufsteigend 
     *  sortiert ist.
     *  Diese Methode darf nur auf das Ankerelement aufgerufen
     *  werden.
     *
     * @param d Das einzufügende Element.
     * 
     * @note Nutzdaten werden mit der Funktion compareTo() verglichen.
     */
    public void addSorted(T d) {
    }

    /**
     * Methode isSorted() überprüft, ob die Liste aufsteigend
     * sortiert ist. Diese Methode darf nur auf das
     * Ankerelement aufgerufen werden.
     *
     * @return Gibt genau dann true zurück, wenn die Liste sortiert ist.
     * 
     * @note Nutzdaten werden mit der Funktion compareTo() verglichen.
     */
    public boolean isSorted() {
		return false;
    }
    
    public static void main( String[] args )
    {
        Rlist<String> rlist = new Rlist<String>();
        System.out.println(rlist.toString());
        rlist.add( "Hello" );
        System.out.println(rlist.toString());
        rlist.add( "World" );
        System.out.println(rlist.toString());
    }
}
```


Ist das vllt. der Fehler??


----------



## babuschka (14. Jan 2012)

Nee, also im Moment sehe ich weder einen Fehler in add(), noch einen in toString() und kann das Verhalten daher nicht nachvollziehen. :bahnhof:


Kannst Du mir einen Hinweis geben?

--------------------------

Ich mache derweil weiter mit der Methode equals(Object o), hier meine Idee:


```
public boolean equals(Object o) {
		if( ! (o instanceof Rlist)) return false;
		
		Rlist lAux = (Rlist)o;
        Rlist l;
        
        if( this.size() != lAux.size() ) return false;
        
        
        for(l=this.n; l != this; l=l.next(), lAux=lAux.next()){
        	if( ! l.get().equals(lAux.get()) ) return false;
        }
    	
    return true;
    }
```

Auch hier würde ich mich über ein Feedback freuen.


----------



## babuschka (14. Jan 2012)

Und weiter geht's. Hier meine Idee zu addSorted(T d):


```
public void addSorted(T d) {
    	Rlist<T> m = new Rlist<T>();
    	m.data = d;
    	
    	if( this.isEmpty() ) {
    		m.p = this;
    		m.n = this;
    		this.n = m;
    		this.p = m;
    	}
    
         Rlist<T> prev = this;
         for( Rlist<T> l = this.next(); l != this; l = l.next(), prev = prev.next() ){
        	 if( l.get().compareTo(m.data) >= 0){
        		 m.n = l;
        		 m.p = prev;
        		 prev.n = m;
        		 l.p = m;
        	 }
         }
    
        m.p = this.n;
        m.n = this;
        this.p.n = m;
    
    
    }
```


EDIT:

Oder muss es in Zeile 14 heißen:


```
if( l.get().compareTo(m.data) >= 0 && prev.get().compareTo(m.data) <= 0 ){
```

? (Es muss ja auch größer gleich dem vorherigen Listeneintrag sein...

Feedback erwünscht. 

-------------------------------

Und dann auch noch zur Methode isSorted():


```
public boolean isSorted() {
		Rlist<T> prev = this;
		Rlist<T> l;
		
		for( l = this.next(); l != this; l = l.next(), prev = prev.next() ){
			if( prev.get().compareTo(l.get()) > 0 ) return false;
		}
  
       return true;
    }
```

Auch hier: Feedback erbeten.


----------



## Firephoenix (14. Jan 2012)

Shame on me  ich sehe gerade meine Ausgabe bzgl der Main war falsch (copy-paste fehler )


```
public static void main( String[] args )
    {
        Rlist<String> rlist = new Rlist<String>();
        System.out.println(rlist.toString());
        rlist.add( "Hello" );
        System.out.println(rlist.toString());
        rlist.add( "World" );
        System.out.println(rlist.toString());
    }
```

muss folgenden output produzieren:


> <>
> <Hello>
> <World, Hello>



Was auch Sinn macht, denn das World wird nach Hello eingefügt, rückt also zwischen Anker und Hello.
Bei der Ausgabe fängt man nach dem Anker an, kommt zuerst zu World und dann zu Hello.
Deine Main ist aber korrekt.

Die Ausgabe "<>" produziert deine fehlerhafte toString(), den Fehler findest du sobald du dir einfach mal in die for-schleife ein sysout einbaust.


Edit:
Ich würde dir übrigens gerade in Hinsicht auf Aufgabe 2 dringend raten dir mal eclipse zu besorgen, das Programm beißt nicht und die Einarbeitungszeit hält sich in Grenzen.
Auf dem Javavideokurs von hdi sind die ersten 6 Videos übrigens frei und dort beschreibt er sehr gut wie du dir eclipse besorgst und ein erstes Projekt einrichtest, JUnit dann in das Projekt zu bekommen sind auch nur 3-4 klicks - das kann man schnell machen.
Java Video Kurs - Java Video Tutorials - Online Java lernen! (Video 1/2 müssten das sein).
Falls es dir die 50€ Wert ist kann ich den kurs übrigens sehr empfehlen - Videomaterial von der Qualität dürfte man in der Form nur schwer finden.

Sobald du das Eingerichtet hast kannst du nämlich dein Projekt mit einem Button ausführen, anstatt jedes mal per Konsole zu Compilen und dort auszuführen.
Gerade wenn man viel ausprobiert kommt doch oft die Idee "ach das wird schon gehen, ich schreib noch etwas mehr bevor ich wieder 2 Minuten in Konsole und Konsorten verblase" und nach ner halben Stunde Coden am Stück kommt dann eine Fehlerpalette die so lang ist wie dein Screen von Seite 2 

Die meisten Fehler kannst du auch direkt vermeiden, weil Eclipse so nett ist dir syntaktisch falsche Stellen anzustreichen.

Außerdem lernst du gleich noch etwas wichtiges mit wenn du Tests schreibst bevor der Code funktioniert  Du musst dir nämlich Gedanken darüber machen was dein Code tun soll, ohne ihn zu kennen.
Ein Beispiel dafür ist die kleine main die ich dir gegeben habe.
Die kann man ohne weiteres in einen Testfall packen und hat eine schöne prüfung dafür ob add in Kombination mit toString() das produziert was sie tut.
Und statt konsole ablesen ein assertEquals(..) darum zu klatschen kostet wirklich wenig Zeit 



Gruß


----------



## babuschka (14. Jan 2012)

Firephoenix hat gesagt.:


> Die Ausgabe "<>" produziert deine fehlerhafte toString(), den Fehler findest du sobald du dir einfach mal in die for-schleife ein sysout einbaust.
> 
> Gruß




Das habe ich gemacht und es scheint eine Endlos-Schleife zu sein!


Jetzt muss ich das bloß noch kapieren, wieso. I try. :rtfm:


----------



## babuschka (14. Jan 2012)

Okay, ich habe den Fehler entdeckt, es muss bei der Inkrementierung der for-Schleife lauten:


```
e = e.next()
```

Die Ausgabe ist dann nicht so wie Deine, sondern so, wie es in folgendem Screenshot zu sehen ist:



EDIT: Wenn ich das System.out von oben wieder rausnehme, komme ich dann auch auf das, was bei Dir ausgegeben wird.


----------



## Firephoenix (14. Jan 2012)

Ich war etwas langsam mit dem Editieren - bitte nochmal meinen vorigen Post durchlesen 

Deine Ausgabe ist relativ ähnlich, ich vermute, dass du irgendwo nochmal s direkt ausgibst oder?
Außerdem fehlen dir noch Leerstellen hinter den Daten und du solltest hinter den letzten Eintrag kein Komma mehr schreiben 
Gruß


----------



## babuschka (14. Jan 2012)

Ich habe das verbessert: Ja, ich hatte ja ein System.out.println(s) eingeführt um den Fehler zu entdecken und jetzt habe ich das wieder entfernt und bekomme auch nur die Ausgaben mit den eckigen Klammern.



Die Leerzeilen nach den Kommata habe ich jetzt auch.

Aber zwei Fragen bleiben bei mir doch noch:

1. Wie kann man bei dem letzten Eintrag das Komma wegbekommen.

2. Soll nicht <Hello, World> ausgegeben werden? Ich habe oben gelesen, wo Du erklärst, wie <World, Hello> zustande kommt, aber soll nicht idealerweise doch <Hello, World> ausgegeben werden?


----------



## Firephoenix (14. Jan 2012)

zu 1.
In der for-schleife unterscheiden, was machst du bei jedem durchlauf, was nur bei bestimmten durchläufen (z.b. alle außer dem letzten) und wie erkennst du den letzten durchlauf?

2.
Du kannst die Strings auch durch "Blau" und "Magentacyan" ersetzen,
wenn du zuerst Blau einfügst und dann Magentacyan bekommst du als Ausgabe <Magentacyan, Blau>

3.
Edit oben -> eclipse 

Gruß


----------



## babuschka (14. Jan 2012)

Tipp 1.) und 3.) behalte ich im Hinterkopf.


Aber zu 2.)

Möchte man denn nicht aber bei add() daß das Element 1 (also das, was man zuerst einfügt, z.B. "Blau") auch als erstes in der Liste steht?..




EDIT: Zu 1.)

Hab es hinbekommen.


```
for(Rlist e = this.n; e != this; e=e.next() ){
		    	if(e.n != this) s += e.get().toString() + ", ";


		    	else s += e.get().toString();
```


EDIT2:

Achso... rlist wird ja neu erzeugt als leere Liste. Dann wird darauf add() angewandt, damit rückt das HELLO hinter den Anker, also rlist.. Dann wird nochmal add() auf rlist angewandt und damit rückt world zwischen anker (rlist) und HELLO.

Alles klar!! :toll:


----------



## babuschka (14. Jan 2012)

Hast Du evtl. noch ein Wörtchen zu meinen Ideen zu equals(), isSorted(), addSorted()?


Dann könnte ich morgen damit weitermachen.


----------



## Firephoenix (14. Jan 2012)

Für die Methoden bietet sich TDD an, erst die Tests schreiben, dann die Methode und prüfen ob die Tests laufen.
Gerade die addSorted ist ja nicht gerade ein Stück Code wo man 2 mal draufschaut und direkt sieht ob was nicht geht

Gruß


----------



## babuschka (14. Jan 2012)

Konkreter kannst/ möchtest Du nichts sagen? 

Okay, dann eine andere Frage.

Wenn ich zum Beispiel die Methoe add() testen will.

Kann ich mir dann auch so Beispiele ausdenken?


Testfall 1 leere Liste... und dann HELLO und WORLD anfügen...

Testfall 2 nicht leere Liste <World, Hello>... und dann add() anwenden.


Woher weiß ich was ich alles testen muss?


----------



## Firephoenix (14. Jan 2012)

Ein ganz brauchbarer Ansatz zum testen einer Klasse:
Schau dir an welche Schnittstellen die Klasse liefert (quasi nur die Methoden und die Dokumentation der Methoden) - beim Tests schreiben schau NIEMALS in die Implementierung der Methoden, stell dir vor du kennst den Code der Klasse nicht.

Dann könnte man z.B. anfangen einen basistestfall für die leere Liste zu schreiben.
Du erzeugst also eine leere Liste und prüfst alle Daten ab die du von ihr kriegen kannst (get() , size(), isSorted() usw).
Dann schnappst du dir eine Methode wie add, benutzt sie entsprechend und prüfst dann über die anderen Methoden ob auch das herauskommt was soll. Fügst du z.b. ein Element ein, erwartest du ja, dass du immer noch eine Ringliste hast (also bei allen Elementen entsprechend mal die prev() und next() prüfen), das kannst du auch gerne mit Schleifen machen.

Nach dem Schema gehst du alle Methoden durch, es gibt aber auch noch andere Testansätze wie Block Coverage , Condition Coverage etc - ich weiß nicht wieviel ihr davon gemacht habt.
Persönlich bevorzuge ich aber die Herangehensweise, sich Gedanken darüber zu machen was alles kaputt gehen kann wenn man eine Methode benutzt (z.B. bei add könnte die Ringliste zerbrechen, addSorted könnte die sortiereigenschaft verletzen oder versehentlich Elemente entfernen usw..)
Gruß


----------



## babuschka (14. Jan 2012)

Danke. Ich werde morgen mal daran mich versuchen.

Wir hatten JUnit und einmal einen Aufgabenzettel, wo es um das Implementieren des Spiels Skat ging. Da sollte man dann einige Grenzwerttestfälle bedenken und dafür Tests schreiben.


----------



## babuschka (15. Jan 2012)

Ich versuche mich jetzt an JUnit und wollte zuerst Tests für die Methode add() schreiben.

Ist das hier zum Beispiel okay:


```
import org.junit.*;
import org.junit.runner.*;
import org.junit.Assert.*;

public class RlistTest {

    @Test
    public String testadd() {
	
      Rlist<String> rlist = new Rlist<String>();
      rlist.add("World");
      rlist.add("Hello");
        
        

          return rlist.toString();
        
      };

      Assert.assertTrue( "False", rlist.toString() == "<Hello, World>" );
    }

   

    public static void main(String[] args) {
    	JUnitCore junit = new JUnitCore();
    	junit.addListener( new PI1TestRunListener() );
    	junit.run( RlistTest.class );
    }

}
```


Ich kriege den Test aber in Eclipse nicht zum Laufen...


Noch eine andere Idee:


```
import org.junit.*;
import org.junit.runner.*;
import org.junit.Assert.*;

public class RlistTest {

    @Test
    public String testadd() {
	
      Rlist<String> rlist = new Rlist<String>(){
      
        
      return rlist.toString();
      };
      Assert.assertTrue("False!", rlist.add("Hello").toString() == "<Hello>");
    }
    
    

   

    public static void main(String[] args) {
    	JUnitCore junit = new JUnitCore();
    	junit.addListener( new PI1TestRunListener() );
    	junit.run( RlistTest.class );
    }

}
```

Kriege ich aber auch nicht getestet...


----------



## babuschka (15. Jan 2012)

Wenn ich dies durchlaufen lasse:#


```
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.JUnitCore;




public class RlistTest<T extends Comparable<T>> {

    @Test
    public void testadd() {
	
      Rlist<String> rlist = new Rlist<String>();
      
        
      
      
      Assert.assertTrue("False!", rlist.add("Hello").toString() == "<Hello>");
    }
    
    

   

    public static void main(String[] args) {
    	JUnitCore junit = new JUnitCore();
    	junit.addListener( new PI1TestRunListener() );
    	junit.run( RlistTest.class );
    }

}
```




kommt diese Ausgabe hier:

testadd	[FAIL]
	assertion failed -> Unresolved compilation problems: 
	Rlist cannot be resolved to a type
	Rlist cannot be resolved to a type

1 of 1 tests failed!

Hm, wie komm ich weiter??


----------



## Gast2 (15. Jan 2012)

> Rlist cannot be resolved to a type


Import vergessen?


```
rlist.add("Hello").toString() == "<Hello>"
```
Strings vergleicht man mit equals.


----------



## babuschka (15. Jan 2012)

Was müsste denn importiert sein?

Edit: Ich habe bei den imports:

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.JUnitCore;


----------------

Danke, habe den Vergleich nun mit equals(...)


----------



## babuschka (15. Jan 2012)

Ich muss irgendwie Rlist importieren??
Aber wie mache ich das?


----------



## babuschka (15. Jan 2012)

Hat nicht mal eben bittte eine Idee?

Ich will gern diese Tests schreiben und sehe einfach nicht, wie ich Rlist importeiren kann.



EDIT: Ah, ich habs wohl hinbekommen. Einfach bei Eclipse Add External Class Folder...


----------



## babuschka (15. Jan 2012)

Nochmal eine Frage zum Testen.

Ich habe nun für die Methode add(T d) vier Tests geschrieben.

1.) Anwenden auf leere Liste

2.) Anwenden auf eine Liste mit 1 Element, wobei auf das Ankerelement angewandt wird. Test, ob einzufügende Element wirklich hinter das Ankerelement eingefügt wurde. 

3.) Anwenden auf eine Liste mit 1 Element, wobei auf das Nicht-Ankerelement angewandt wird. Test, ob das hinzuzufügende Element hinter das Nicht-Ankerelement eingefügt wird und sich die Liste also um ein Element erweitert.

4.) Einfügen eines Elements mitten in eine Liste aus 5 Elementen.


Dabei habe ich implizit die Methoden toString() und next() mitgetestet.


Wäre das ausreichend für die Methode add()?


-------------------

Ich frage nur, weil ich mich dann für die anderen Methoden daran orientieren könnte.


----------



## Firephoenix (15. Jan 2012)

Wenn du dir nach den Tests sicher bist (und jemand anderes sich auch sicher sein kann), dass deine add-Methode das macht was sie soll (ohne auf den internen Code zu schauen) - wenn die Tests durchlaufen, sind die Tests fürs erste ausreichend - daran kannst du dich auch für die weiteren Methoden orientieren.

Gruß


----------



## babuschka (15. Jan 2012)

Dankesehr!

Morgen schreibe ich weitere Tests.

Ich bin auf den Geschmack gekommen.


----------



## babuschka (15. Jan 2012)

Achso, ich poste doch nochmal meine bisherigen Tests, quasi aus Sicherheit, damit ich nicht mich bei den weiteren Tests an Quatsch halte, falls die Tests fehlerhaft sind von der Idee her.


```
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.JUnitCore;


public class RlistTest<T> {
    
	@Test
    public void testadd01() {
		/**
    	 * @test
    	 * <br><b>tag</b>          T01 
    	 * <br><b>condition</b>    	
    	 * <br><b>event</b>        Aufruf add(String) auf leere Liste 
    	 * 						   implizit: Aufruf toString()
    	 * <br><b>expected</b>     PASS 
    	 */
	
      Rlist<String> rlist = new Rlist<String>();
      rlist.add("Hello");
      
      Assert.assertTrue("False!", rlist.toString().equals("<Hello>") );
    }
    
    
    @Test
    public void testadd02() {
		/**
    	 * @test
    	 * <br><b>tag</b>          T02 
    	 * <br><b>condition</b>    	
    	 * <br><b>event</b>        Aufruf add(String) auf Liste mit 1 Element
    	 * 						   auf Ankerlement,
    	 * 						   implizit: Aufruf next(),
    	 * 						   implizit: Aufruf toString()
    	 * <br><b>expected</b>     PASS 
    	 */
	
      Rlist<String> rlist = new Rlist<String>();
      rlist.add("Hello");
      rlist.add("World");
      
      Assert.assertTrue("False!", rlist.toString().equals("<World, Hello>") );
    }
    
    @Test
    public void testadd03() {
		/**
    	 * @test
    	 * <br><b>tag</b>          T03 
    	 * <br><b>condition</b>    	
    	 * <br><b>event</b>        Aufruf add(String) auf Liste mit 1 Element
    	 * 						   auf Ankerlement,
    	 * 						   implizit: Aufruf next(),
    	 * 						   implizit: Aufruf toString()
    	 * <br><b>expected</b>     FAIL 
    	 */
	
      Rlist<String> rlist = new Rlist<String>();
      rlist.add("Hello");
      rlist.add("World");
      
      Assert.assertTrue("False!", rlist.toString().equals("<Hello, World>") );
    }
    
    @Test
    public void testadd04() {
		/**
    	 * @test
    	 * <br><b>tag</b>          T04 
    	 * <br><b>condition</b>    	
    	 * <br><b>event</b>        Aufruf add(String) auf Liste mit 1 Element
    	 * 						   auf Nicht-Ankerlement,
    	 * 						   implizit: Aufruf next(),
    	 * 						   implizit: Aufruf toString()
    	 * <br><b>expected</b>     PASS 
    	 */
	
      Rlist<String> rlist = new Rlist<String>();
     
      rlist.add("Hello");
      Rlist<String> rlist2 = rlist.next();
      rlist2.add("World");
       
      Assert.assertTrue("False!", rlist.toString().equals("<Hello, World>") );
    }
    
    @Test
    public void testadd05() {
		/**
    	 * @test
    	 * <br><b>tag</b>          T05 
    	 * <br><b>condition</b>    	
    	 * <br><b>event</b>        Aufruf add(String) auf Liste mit 1 Element
    	 * 						   auf Nicht-Ankerlement,
    	 * 						   implizit: Aufruf next(),
    	 * 						   implizit: Aufruf toString()
    	 * <br><b>expected</b>     PASS 
    	 */
	
      Rlist<String> rlist = new Rlist<String>();
      rlist.add("Hello");
      Rlist<String> rlist2 = rlist.next();
      rlist2.add("World");
      Rlist<String> rlist3 = rlist.next().next();
      rlist3.add("this");
      Rlist<String> rlist4 = rlist.next().next().next();
      rlist4.add("me!");
      Rlist<String> rlist5 = rlist.next().next().next();
      rlist5.add("is");
      
       
      Assert.assertTrue("False!", rlist.toString().equals("<Hello, World, this, is, me!>") );
    }
    
    
    
    public static void main(String[] args) {
    	JUnitCore junit = new JUnitCore();
    	junit.addListener( new PI1TestRunListener() );
    	junit.run( RlistTest.class );
    }




}
```

Ich hoffe, daß die Tests auch das machen, was ich oben beschrieben habe.


----------



## Firephoenix (16. Jan 2012)

Anstatt Assert.assertTrue(... bla.equals(blubb) ...)
kannst du auch Assert.assertEquals(expected , actual) verwenden, falls du dazu gerne noch eigene Fehlermeldungen hättest geht auch Assert.assertEquals(message, expected, actual).

Wenn du die Funktionen statisch importierst (entweder per wildcard wie unten, oder sauber einzeln falls du nicht mehr von Assert verwendest)

```
import static org.junit.Assert.*;
```
sparst du dir übrigens sehr viele "Assert." 

Außerdem solltest du den Tests ordentliche Namen geben,
Wenn testadd01 fehlschlägt kann sich kein Mensch etwas darunter vorstellen, schlägt dagegen ein Test Namens addInsertDataInList fehl, weiß man direkt, dass die add-Methode wohl einen Datensatz nicht in die Liste eingefügt hat.

Außerdem solltest du versuchen abhängigkeiten zwischen Tests zu vermeiden.
Du prüfst alle Tests mit deiner toString(), kannst aber nicht davon ausgehen, dass diese das tut was sie soll - wenn die Methode einmal geändert wird schlagen alle deine anderen Tests fehl - eine Kaskade die man später nur schwer auswerten kann.

Daher die Ergebnisse lieber über die von der Klasse bereitgestellten getter prüfen (get(), next(), prev() ), da diese einfach nur felder zurückgeben und keine logik enthalten kann man davon ausgehen, dass die Methoden das machen was sie sollen (irgendwo muss man ja mal anfangen)

Übrigens: Die toString() Methode gibt den Anker nicht aus, angenommen deine add-Methode würde neben dem Einfügen in die Liste noch das Ankerelement suchen und dessen Datensatz überschreiben, würdest du den Fehler finden? (immer davon ausgehen, du kennst den code nicht - klar wenn der Ankerdatensatz != null würde er wohl in der toString auftauchen, aber gerade solche Tests helfen später Fehler zu vermeiden falls man wirklich mal größere Sachen schreibt und nicht davon ausgehen kann, dass alle Methoden sich nicht mehr ändern).

Gruß


----------



## babuschka (16. Jan 2012)

Ich muss einen Fehler in der Methode addSorted(T d) haben, denn ich hab bei einem Test

Anker - Hello - World

und wollte jetzt addSorted("this") anwenden.

Dann müsste ich doch haben:

Anker - Hello - this - World


Aber das ergibt sich nicht.



Sieht jemand meinen Fehler??


```
/**
     *  Methode addSorted() fügt das Element d in die Liste
     *  ein, so dass eine vorher aufsteigend sortierte Liste
     *  nach  Ausführung von addSorted() immer noch aufsteigend 
     *  sortiert ist.
     *  Diese Methode darf nur auf das Ankerelement aufgerufen
     *  werden.
     *
     * @param d Das einzufügende Element.
     * 
     * @note Nutzdaten werden mit der Funktion compareTo() verglichen.
     */
    public void addSorted(T d) {
    	Rlist<T> m = new Rlist<T>();
    	m.data = d;
    	
    	if( this.isEmpty() ) {
    		m.p = this;
    		m.n = this;
    		this.n = m;
    		this.p = m;
    	}
    
         Rlist<T> prev = this.next();
         for( Rlist<T> l = this.next().next(); l != this; l = l.next(), prev = prev.next() ){
        	 if( l.get().compareTo(m.data) >= 0 && prev.get().compareTo(m.data)<=0 ){
        		 m.n = l;
        		 m.p = prev;
        		 prev.n = m;
        		 l.p = m;
        		 
        	 }
        	 
         }
    
         m.p = this.n;
         m.n = this;
         this.p.n = m;
        
    
    
    }
```


----------



## babuschka (16. Jan 2012)

Kann das sein, dass ich deutsche Wörter nehmen muss???

Wenn ich das mit Affe, Katze Zebra mache, scheint es zu gehen!


----------



## Firephoenix (16. Jan 2012)

Kommt dir das hier bekannt vor?


```
Rlist<T> m = new Rlist<T>();
m.data = d;
```

und

```
m.n = l;
m.p = prev;
prev.n = m;
l.p = m;
```

bzw

```
m.n = l;
m.p = prev;
prev.n = m;
l.p = m;
```

Tipp:

```
Rlist<T> m = new Rlist<T>();
        m.data = d;
        m.n = this.n;
        this.n.p = m;
        this.n = m;
        m.p = this;
```

Deutsche oder Englische Wörter machen bei Zeichenketten übrigens keinen unterschied, Strings werden lexikographisch verglichen

Gruß


----------



## babuschka (16. Jan 2012)

Das hatten wir bei add()

aber inwiefern hilft mir das hier weiter?


EDIT:


Achso, ich kann einfach 

prev.add(m.data)

nehmen?


----------



## babuschka (16. Jan 2012)

Das ist doch seltsam!!

Wenn ich das so teste:


```
@Test
    public void testaddSorted01() {
		/**
    	 * @test
    	 * <br><b>tag</b>          T21 
    	 * <br><b>condition</b>    	
    	 * <br><b>event</b>        Aufruf addSorted(String) auf Liste mit 2 Elementen, 
    	 * 						   die lexikalisch geordnet ist.
    	 * 						    					   
    	 * <br><b>expected</b>     PASS 
    	 */
	
    	Rlist<String> rlist = new Rlist<String>();
        rlist.insert("Hello");
        rlist.insert("World");
        rlist.addSorted("this");
        
        
        Assert.assertTrue("False!", rlist.toString().equals("<Hello, this, World>"));
    }
```

stimmt der test nicht.


Teste ich aber so:


```
@Test
    public void testaddSorted01() {
		/**
    	 * @test
    	 * <br><b>tag</b>          T21 
    	 * <br><b>condition</b>    	
    	 * <br><b>event</b>        Aufruf addSorted(String) auf Liste mit 2 Elementen, 
    	 * 						   die lexikalisch geordnet ist.
    	 * 						    					   
    	 * <br><b>expected</b>     PASS 
    	 */
	
    	Rlist<String> rlist = new Rlist<String>();
        rlist.insert("Affe");
        rlist.insert("Zebra");
        rlist.addSorted("Katze");
        
        
        Assert.assertTrue("False!", rlist.toString().equals("<Affe, Katze, Zebra>"));
    }
```


dann stimmt das Testergebnis.. :bahnhof:


----------



## babuschka (16. Jan 2012)

Sorry, aber ich muss nochmal nachfragen:

Dies ist jetzt mein Code für addSorted(T d)...

Irgendwie komme ich da einfach nicht weiter!


```
public void addSorted(T d) {
    	Rlist<T> m = new Rlist<T>();
    	m.data = d;
    	
    	if( this.isEmpty() ) {
    		m.p = this;
    		m.n = this;
    		this.n = m;
    		this.p = m;
    	}
    
         Rlist<T> prev = this.next();
         for( Rlist<T> l = this.next().next(); l != this; l = l.next(), prev = prev.next() ){
        	 if( l.get().compareTo(m.data) >= 0 && prev.get().compareTo(m.data)<=0 ){
        		 prev.add(m.data);
        		 break;	 
        	 }
        	 
         }
    
         this.p.add(m.data);
        
    
    
    }
```


Auch die Zeile 21 weiß ich nicht, ob sie stimmt.
Da will ich den Fall abdecken, daß das ganz hinten dran gehängt werden muss.


----------



## Firephoenix (16. Jan 2012)

Wenn du Affe, Zebra, Katze reinpackst und es kommt Hello this und World raus will ich den Code garnicht erst sehen 

Und da ich kein Anrufbeantworter bin:


> Anstatt Assert.assertTrue(... bla.equals(blubb) ...)
> kannst du auch Assert.assertEquals(expected , actual) verwenden, falls du dazu gerne noch eigene Fehlermeldungen hättest geht auch Assert.assertEquals(message, expected, actual).
> 
> Wenn du die Funktionen statisch importierst (entweder per wildcard wie unten, oder sauber einzeln falls du nicht mehr von Assert verwendest)



Übrigens solltest du dringend mal einen Blick auf die Dokumentation der Methode addSorted werfen


> so dass eine vorher aufsteigend sortierte Liste nach Ausführung von addSorted() immer noch aufsteigend sortiert ist


 - deine insert-Aufrufe erhalten zwar netterweise die sortierbarkeit, aber du läufst hier in die Gefahr, dass du vorher die sortiertheit der Liste zerstörst und damit keinen konsistenten Methodenausgang bei addSorted() mehr garantieren kannst.

Für Strings ist dir sortiertheit übrigens korrekt, compare ist case-sensitive.


```
public static void main( String[] args )
    {
        ArrayList<String> list = new ArrayList<String>();
        list.add( "this" );
        list.add("Hello");
        list.add("World");
        list.add("A");
        list.add("a");
        Collections.sort( list );
        System.out.println(list);
    }
```
Ausgabe:


> [A, Hello, World, a, this]


(Collections.sort() benutzt intern ebenfalls compareTo() aus dem Interface Comparable)

Gruß


----------



## babuschka (16. Jan 2012)

Ich hatte den Code falsch kopiert, da stand natürlich Affe, Katze, Zebra...


Ich verstehe gar nicht was Du damit meinst..
Ich habe die Dokumentation gelesen und die Liste ist doch sortiert.

Nur verstehe ich eben nicht, was an meinem Code falsch ist, denn ich bin ihn jetzt zig mal durchgegangen, aber mir will einfach nichts auffallen bzw. kommen mir einfach keine Verbesserungsideen. 


Die Methoden addSorted und equals dachte ich einigermaßen richtig zu haben, aber anscheinend sind sie ja total verkehrt...

Oh man, ich dachte, ich hätte mal was hinbekommen.


EDIT: Dann müsste doch Hello- This - World ausgegeben werden? Aber auch da geht es nicht.


----------



## Firephoenix (16. Jan 2012)

Ich meinte damit das hier:

```
Assert.assertTrue("False!", rlist.toString().equals("<Hello, this, World>"));
```

das eigentlich so aussehen sollte (passende Methode verwenden mit import und den String auch sortiert benutzen (siehe mein Beispiel oben wie Strings verglichen werden).

```
assertEquals("<Hello, World, this>" , rlist.toString() )
```

Außerdem solltest du dir das hier mal anschauen und dir in ruhe darüber gedanken machen (ich habe deine addSorted mal mir 3 println() versehen)

```
public void addSorted( T d )
    {
        Rlist<T> m = new Rlist<T>();
        m.data = d;

        if ( this.isEmpty() )
        {
            m.p = this;
            m.n = this;
            this.n = m;
            this.p = m;
        }

        System.out.println( "Stelle 1 " + this );

        Rlist<T> prev = this.next();
        for ( Rlist<T> l = this.next().next(); l != this; l = l.next(), prev = prev.next() )
        {
            if ( l.get().compareTo( m.data ) >= 0 && prev.get().compareTo( m.data ) <= 0 )
            {
                prev.add( m.data );
                break;
            }

        }

        System.out.println( "Stelle 2 " + this );

        this.p.add( m.data );
        
        System.out.println( "Stelle 3 " + this);

    }
```

Aufrufende Methode:

```
public static void main( String[] args )
    {
        Rlist<String> rlist = new Rlist<String>();
        rlist.addSorted( "Banane" );
        rlist.addSorted( "Affe" );
        rlist.addSorted( "Kuchen" );
    }
```

Ausgabe:

```
Stelle 1 <Banane>
Stelle 2 <Banane>
Stelle 3 <Banane, Banane>
Stelle 1 <Banane, Banane>
Stelle 2 <Banane, Banane>
Stelle 3 <Banane, Banane, Affe>
Stelle 1 <Banane, Banane, Affe>
Stelle 2 <Banane, Banane, Affe>
Stelle 3 <Banane, Banane, Affe, Kuchen>
```

Edit:
Erwarteter output:


> <Affe, Banane, Kuchen>



Gruß


----------



## babuschka (16. Jan 2012)

Ich schau es mir gleich an, danke!

Aber wieso ist denn <Hello, World, this> korrekt... t kommt doch vor W...


----------



## Firephoenix (16. Jan 2012)

> Für Strings ist dir sortiertheit übrigens korrekt, compare ist case-sensitive.
> 
> 
> ```
> ...



Wenn ich als Student meine Posts bis zum Ende schreiben kann, kannst du sie auch bis zum Ende lesen :toll:

Gruß


----------



## babuschka (16. Jan 2012)

Aber ich habs nicht verstanden, was case sensitive bedeutet.

Groß- und Kleinschreibung - also das die von Bedeutung ist?

(Deswegen hatte ich This mal groß geschrieben, da gings auch nicht.)


-----------------


Mein Problem in der addSorted ist nachdem ich Deinen Post eben las glaube ich zwei Dinge:

Erstens ich muss 

prev=this;

und l=this.next

[Ich hatte immer einen Schritt zu viel, gklaube ich) und

ich weiß nicht, wie ich die forSchleife bzw. die ganze Methode verlassen kann, wenn ich den Eintrag irgendwo mitten rein sortiert habe.

NACH der Schleife ist ja nur der Fall, dass man es an das Ende einfügen muss. Aber ich weiß niocht, wie man das abtrennen kann, sodass man auch nur dann da hin jkommt.


----------



## Firephoenix (16. Jan 2012)

Die Methode ist auch etwas kompliziert geraten 

Das einfügen kann man sich aber iterativ relativ leicht aufbauen:

1. Einfachster Fall - einfügen in leere Liste



> wenn liste leer (also das nächste element wieder das aktuelle ist)
> einfach anhängen (add)



So jetzt hast du den Schnipsel durchgelaufen, deine Liste ist nicht leer - was machst du?


> wenn liste leer (also das nächste element wieder das aktuelle ist)
> einfach anhängen (add)
> ansonsten: Hinter dem aktuellem Element ist also ein anderes Element.



Jetzt musst du prüfen wann du einfügen darfst und wann nicht, auch hier ist wieder der einfachste Fall der Randfall: Du hast die Liste bis zum Ende durchgelaufen und dein nächstes Element ist wieder der Anker, dann musst du einfügen, denn du bist bereits am Ende und konntest das Element am Ende nicht einfügen



> wenn liste leer (also das nächste element wieder das aktuelle ist)
> einfach anhängen (add)
> ansonsten: Hinter dem aktuellem Element ist also ein anderes Element.
> ist es wieder der anker:
> ...



Der letzte fall ist also der, dass du noch in der Liste irgendwo zwischen Elementen bist, hier gibt es zwei Fälle - entweder dein nächstes Element ist logisch kleiner als das das du einfügen willst, dann darfst du es nicht einfügen, oder es ist größer, gleich, dann kannst du dein Element ohne bedenken dazwischen setzen.



> wenn liste leer (also das nächste element wieder das aktuelle ist)
> einfach anhängen (add)
> ansonsten: Hinter dem aktuellem Element ist also ein anderes Element.
> ist es wieder der anker:
> ...



Versuch das doch einfach mal mit deinem Code abzugleichen oder passend um/neu zuschreiben, wenn dann probleme auftauchen kann man die passender angehen 

Gruß


----------



## babuschka (16. Jan 2012)

Ich glaube, jetzt ist es noch komplizierter.. 


```
public void addSorted(T d) {
    	Rlist<T> m = new Rlist<T>();
    	m.data = d;
    	
    	if( this.isEmpty() ) {
    		this.add(m.data);
    	}
    	else{
         Rlist<T> prev = this;
         for( Rlist<T> l = this.next(); l != this; l = l.next(), prev = prev.next() ){
        	 if(l == prev){l.add(m.data);}
        	 else {if( l.get().compareTo(m.data) >= 0  ){
        		 prev.add(m.data);
        		 break;	 
        	 }
        	 
         }
   }
    }
```


----------



## Firephoenix (16. Jan 2012)

Ich poste normalerweise nur sehr ungerne Lösungen, aber hier hat es mit den Kommentaren hoffentlich einen Lernerfolg.
Schau dir die Kommentare an, vergleich das mit dem Code der daneben steht
(bis auf den compare-Aufruf sind die Kommentare fast überflüssig, der Code ließt sich von selbst)
Und dann schau dir nochmal meine Textlösung von oben an - die Struktur ist 1-1 identisch.

```
public void addSorted( T d )
    {
        Rlist<T> actualElement = this;
        boolean elementAdded = false;
        while ( !elementAdded ) //Solange das Element nicht eingefügt wurde
        {
            if ( actualElement.next() == this ) //Wenn Liste leer
            {
                actualElement.add( d ); //Einfach anhängen
                elementAdded = true;
            }
            else //Ansonsten: hinter dem aktuellem Element ist ein anderes Element
            {
                if ( actualElement.next().get().compareTo( d ) >= 0 ) //Ist das nächste Element größer bzw gleich dem einzufügendem
                {
                    actualElement.add( d ); //Einfügen
                    elementAdded = true;
                }
                else //Falls es kleiner ist (else)
                {
                    actualElement = actualElement.n; //Eins weitergehen
                }
            }
        }
    }
```


hier auch noch ein Auszug aus meiner Testklasse (ich kann hier direkt sagen - das ist keine komplette Verifikation für addSorted(), da hier abhängigkeiten zu isSorted() bestehen, ich prüfe hier nur ob sich isSorted konsistent zu dem sortierten Einfügen in eine leere Liste verhält)

```
@Test
    public void addSortedDoesNotChangeIsSorted()
    {
        Rlist<Integer> rlist = new Rlist<Integer>();
        int[] testNumbers = new int[] { 5, 2, 3, 42, 0, -1, 13, 7, 12, 15, 12 };
        for ( int i = 0; i < testNumbers.length; i++ )
        {
            rlist.addSorted( testNumbers[i] );
            assertTrue( "AddSorted führte dazu, dass isSorted() false zurücklieferte", rlist.isSorted() );
        }
    }
```
Gruß


----------



## babuschka (16. Jan 2012)

Kannst Du es bitte wieder entfernen? bzw. editeiren?

ich danke dir sehr. aber ich habe sorge, dass ich noch ärger mit tutoren habe oder so.

ich werde es mir ansehen und auf mein können anpassen!


----------



## Firephoenix (16. Jan 2012)

Ärger gibt es höchstens wenn du Code 1-1 übernimmst, Code als Anreiz für eine eigene (im optimalfall bessere) Lösung zu nehmen kann dagegen nie schaden.
Und da viele Wege nach Rom führen gibt es noch genug alternativen, selbiges bei den Testfällen.

Gruß


----------



## babuschka (16. Jan 2012)

Okay.

Wir sollen noch im Rahmen der Tests eine Methode 

check(Rlist<?> list)

schreiben, die testet, ob eine Liste genau ein Ankerelement hat und ob die Ringverkettung noch in Ordnung ist.

Ich hab mir dazu bis jetzt Folgendes überlegt (ein bisschen von der Idee "inspiriert"):
Ich denke es mir so, daß man diese Methode nur auf das Ankerlement anwenden darf.


```
publich boolean check(Rlist<T> list){
Rlist<T> actualElement=this;
boolean onlyOneAnchorElement=true;

if(this.isEmpty()) return true;

while(onlyOneAnchorElement){
 if(actualElement.next().get() == null) || (actualElement.n=null || actualElement.p==null) ){
    onlyOneAnchorElement=false;
    return false;
 }

else actualElement=actualElement.n;
}

return true;

}
```



Ich weiß nicht genau, wie man testen kann, ob die Ringverkettung noch in Ordnung ist.
Ich dachte mir: Wenn es keine Verkettungen gibt (also n==null oder p==null), dann ist die Ringverkettung nicht mehr okay.


----------



## Firephoenix (16. Jan 2012)

Ein Ankerelement -> Es gibt genau ein Element bei dem Data = null ist.

Ringverkettung kann man nach einem Stack-prinzip machen:
Du startest am Anker, gehst die Liste in eine Richtung durch und schaufelst dabei alle Elemente (Listenelemente, nicht data-elemente) in deine Liste oder einen Stack, solange bis du wieder am Anker bist.
Dann gehst du rückwärts über die Liste, für jedes Element an dem du jetzt vorbeikommst prüfst du ob es das gleiche ist das in der Liste/Dem Stack steht (falls du eine Liste nimmst musst du die natürlich auch rückwärts auslesen)
Ist es ungleich/Die Liste leer und du bist nicht am Anker / Du bist am Anker und die liste ist nicht leer, war die Verkettung nicht in Ordnung

Gruß


----------



## babuschka (16. Jan 2012)

```
public boolean check(Rlist<T> list){
int counter = 0;
Rlist<T> l;
for(l=this.next() ; l ! = this ; l=l.next() ){

if(l.get() == null) counter++;
}

if(counter>1) return false;
}
```

Das ist meine Idee zu dem Teil mit dem einen Ankerlement.
Das Andere habe ich nicht verstanden.


----------



## babuschka (17. Jan 2012)

Ach, nee...

Ich habe ja so gar nicht die als Parameter übergebene Liste einbezogen.
Ich weiß nicht so genau, wie ich das hinbekomme, daß ich bei der als Parameter übergebenen Liste vorne beim Ankerelement anfangen und dann immer eins weiter rutsche um zu schauen, ob da auch data==null ist (dann geht der counter eins hoch).



```
public boolean check(Rlist<T> list){
int counter = 1 ;

for(Rlist<T> l.next = list; l != this; l=l.next() ){
if(l.data==null) counter++;
}

if(counter>1) return false;

else [...]

}



//Hier soll das mit der Ringverkettung folgen...
```


----------



## babuschka (17. Jan 2012)

Edit: hat sich erledigt. war eine klammer zu viel


----------



## tfa (17. Jan 2012)

Was soll das else in Zeile 399? 
Lass dir den Quelltext vernünftig formatieren. Die Klammerung stimmt nicht.


----------



## babuschka (17. Jan 2012)

Der Code für die letzte Methode ist nicht richtig und ich bastelte gerade noch daran rum, daher kam das else, aber so macht es natürlich keinen Sinn.


----------



## babuschka (17. Jan 2012)

Kann mir vllt. jemand sagen, wo in diesem Code der Fehler ist.

Tetsts haben ergeben, dass bei zwei identischen Listen nicht true ausgegeben wird...


```
public boolean equals(Object o) {
		if( ! (o instanceof Rlist)) return false;
		
		Rlist lAux = (Rlist)o;
        Rlist l;
        
        if( this.size() != lAux.size() ) return false;
        
        
        for(l=this.next(); l != this; l=l.next(), lAux=lAux.next()){
        	if( ! l.get().equals(lAux.get()) ) return false;
        }
    	
    return true;
    }
```


Der Fall, wenn die Listen ungleich lang sind geht.
Listen gleicher Länge und unterschiedlichen Einträgen: Das scheint auch zu gehen.

Nur: Identische Listen werden nicht als gleich ermittelt.


----------



## Firephoenix (17. Jan 2012)

> *  Diese Methode darf nur auf das Ankerelement aufgerufen
> *  werden.
> *
> *  @param o Referenz auf Ankerelement der zweiten Liste.
> *         Die Liste darf leer sein.




```
Rlist lAux = (Rlist)o;
l=this.next()
if( ! l.get().equals(lAux.get()) ) return false;
```

was hindert dich daran einfach mal ein paar System.out.println() eiunzubauen und dir entsprechende Datenstellen auszugeben? (l.get() und lAux.get() hätten gereicht)
Der Verursacher ist doch ganz offensichtlich die for-Schleife, da der Rest geht.

Nach dem Java-Zeitraum sollte man eigentlich erwarten können, dass man in der Lage ist solche Fehler von sich aus zu finden denke ich.

Gruß


----------



## babuschka (17. Jan 2012)

Achso, dort muss es im Schleifenrumpf

lAux.next().get()

heißen, weil ich ja sonst zuerst Nicht-Anker mit Anker vergleiche.




Noch eine andere Frage:

Wie kann ich das mit dem 

instanceof testen?


Ich hatte mir in einem Test überlegt das ich eine Liste mit int ,also Rlist<int> mache, aber das geht nicht. (irgendwelche Dimensionen soll ich dann angeben).


der test fehlt nämlich noch ob da dann false rauskommt, wenn man so ein andere objekt von einem anderen typ nimmt und vergleicht


----------

