Problem beim Kopieren von Objekten [etwas ordentlicher]



  • Hallo zusammen,

    ich merke, dass meine letzte Beschreibung meines Problems sehr in die Irre führen kann. Also probiere ich, mich etwas deutlicher auszudrücken.

    Ich bin dabei eine (lineare) List zu implementieren. Dabei hat jedes Element der Liste genau einen Wert und einen Nachfolger. So kann man sich durch die ganze Liste hangeln.

    Ich möchte nun eine Methode schreiben, die jedes Tripel zyklisch rotieren lässt. Angenommen, ich habe die Liste 0 1 2 3. Dann würde nun meine Methode das erste Tripel zyklisch rotieren lassen und es käme 2 0 1 3 heraus. Falls es zwei vollständige Tripel gäbe, so würden natürlich beide rotiert. Die Liste 0 1 2 3 4 5 würde also zu 2 0 1 5 3 4.

    Leider funktioniert meine Methode nicht. Ich hab erst einmal keine Schleife eingebaut, sodass erst einmal nur das erste Tripel bearbeitet wird.

    public void rotateTriplesIter() {
    	// a b c d --> c a b d
    	ListItem<T> p = first;
    	ListItem<T> tmp = null;
    
    	//while(p != null && p.next != null && p.next.next != null) {
    		tmp = p.next.next.next; //d zwischenspeichern
    		p.next.next.next = p; //Nachfolger von c wird a 
    		p = p.next.next; //erstes Element des Tripels wird c
    		p.next.next.next = tmp; //Nachfolger von b wird d
    
    	//}
    }
    

    Leider funktioniert dieser Code nicht. Im obigen auskommentiertem Buchstabenbeisoiel wird c nicht als erstes Element angefügt. Aus "a b c d" würde also "b a d" werden, aber nicht "c a b d".

    Sieht jemand den Fehler? Ich komm einfach nicht drauf?

    Vielen Dank
    LG, freakC++



  • du setzt doch first nicht neu, oder??

    Probiers doch ma so:

    tmp = first.next.next
    first.next.next = first.next.next.next
    tmp.next = first
    first = tmp



  • Nein, first setz ich nicht neu, obwohl ich weiß, dass ich es eigentlich machen müsste. Dann bekomme ich aber das Problem, diese Operation nicht auf eine ganze lineare Liste anwenden zu können, da ja nur beim ersten Mal first neugesetzt werden muss. first muss also immer das erste Element des aktuellen Trippels sein.

    Ich habe mal versucht, eine Schleife drumzubauen. Zumindest kommt keine NullPointerException, aber das Ergebnis ist trotzdem falsch.

    for(ListItem<T> p = first; p != null && p.next != null && p.next.next != null; p = p.next.next.next) {
    			tmp = p.next.next; //c zwischenspeichern
    			p.next.next = p.next.next.next; //Nachfolger von b wird d
    			tmp.next = first; //Nachfolger von c wird a
    			p = tmp; //c wird zum ersten Element
    		}
    

    Nur, wenn die nächsten drei Elemente alle ungleich null sind, darf der Schleifenrumpf ausgeführt werden. Es liegt bestimmt daran, dass ich first nicht richtig setze. Könnt ihr mir einen Tipp geben, meinen logischen Fehler zu finden?

    Bei einer Liste von 0 1 2 3 4 5 6 7 8 9 10 kommt mit obigem Code "0 1 3 4" heraus.

    Vielen Dank
    LG, freakC++



  • ... zuhause, anchher...

    aber mit Haskell wär das vieeeel leichter...



  • Keine gute Idee, in der Schleifensignatur und gleichzeitig im Rumpf mit der Laufvariablen 'p' rumzuhantieren.
    Würdest du doch mit einem 'int i' auch nicht machen.



  • Jockelx schrieb:

    Keine gute Idee, in der Schleifensignatur und gleichzeitig im Rumpf mit der Laufvariablen 'p' rumzuhantieren.
    Würdest du doch mit einem 'int i' auch nicht machen.

    Da haste recht :). Das ändere ich gleich. Trotzdem ist dadurch mein Problem noch nicht ganz gelöst, weil ich noch immer nicht weiß, wie ich mit dem "first" - Element umgehen muss. Habt ihr da noch einen Tipp für mich?

    Vielen Dank
    LG, freakC++



  • Ich würde das etwas mehr strukturieren (ungetestet):

    ListItem<T> item_1, item_2, item_3, item_4, ancestor_first = null;
    for(ListItem<T> p = first; p != null && p.next != null && p.next.next != null;){
        item_1 = p;
        item_2 = item_1.next;
        item_3 = item_2.next;
        item_4 = item_3.next;
    
        if(p == first) first = item_3;
        else ancestor_first.next = item_3;
    
        item_3.next = item_1;
        //item_1.next = item_2; stimmt schon
        item_2.next = item_4;
    
        ancestor_first = item_2;
        p = item_4; //statt dem alten Schleifenzähler, da war dank der Umordnung ein next zu viel (p == item_1, welches jetzt 2 vor dem neuen Start ist)
    }
    


  • Hallo wxSkip!

    Herzlichen Dank für deine Hilfe. Dein Code funktioniert. Bei mir war wohl das Problem, dass ich direkt mit "next" gearbeitet habe und damit die Verbindung zu Objekten verloren habe. Dieses Problem hast Du mit der Auslagerung in lokale Objekte behoben! Super! Gut, dass es in Java den Garbage Collector gibt 😃

    LG, freakC++



  • Was hat das mit dem GC zu tun? Du hantierst ja nur mit Pointern rum und legst keine neuen Objekte an.



  • Stimmt, in diesem Fall nicht. Wenn ich jedoch an das Löschen eines neuen Listenelements denke, so spielt der GC eine Rolle 🙂


Anmelden zum Antworten