Elemente der doppelt verketteten Liste vertauschen



  • Soll der Code so aussehn? Mit den viele Ifs und gleichen Codebefehlen mehrfach? Und die 2. if geht er immer rein, weis aber nicht wie ich das verhindern könnte.
    Na klar ich könnte eine Variable nehemn und die in der 1. if hochzählen und dann vergleichen in der 2. if ob di variable noch den anfangswert hat, wenn nicht dann nicht reingehn, ansonsten schon. Aber eine elegante Lösung ist das auch nicht.

    Ich hab folgende Sonderfälle behandelt: change1=1. Element und change2=1. Element.

    Aber es gibt noch 2: change1 = letztes Element und change 2= letztes Element.

    Da werden es noch mehr ifs und noch mehr gleicher Befehlcode an verschiedenen Stellen.

    Soll das der Sinn sein dahinter?

    Wie kann ich das anders lösen? Ich kann mir nicht vorstellen das dies passen würde.

    spielzug* change_pointer(spielzug* liste, spielzug* change1, spielzug* change2) //liste zeigt auf das 1. Element der Kette, temp1 zeigt auf das element in der kette das mit einen anderen Element in der kette, wo change2 draufzeigt, vertauscht werden muss
    {
      spielzug* after1 = NULL;//element nach temp1
      spielzug* before1 = NULL;//element bevor temp1
    	spielzug* after2 = NULL;//element nach change2
      spielzug* before2 = NULL;//element bevor change2
    	spielzug* temp2 = NULL;//pointer zum zwischenspeichern von change2
    	spielzug* temp1 = NULL; //pointer zum zwischenspeichern von change1
    
    	before1 = change1->prev;
    	after1 = change1->next;
    	before2 = change2->prev;
    	after2 = change2->next;
    	temp1=change1;
    	temp2=change2;
    
      if(change2->prev == NULL)
    	{
        temp2->prev=before1;
    		after1->prev=temp2;
    		temp2->next=after1;
    
    		temp1->prev=before2;
    		temp1->next=after2;
    		after2->prev=temp1;
    	}
    
    	if(change1->prev == NULL && change2->prev != NULL) // hier geht er immer rein, aber soll nicht rein gehn...
    	{
        before2->next = temp1;
    	  temp1->prev = before2;
    	  temp1->next = after2;
    	  after2->prev = temp1;
    
    		temp2->prev=before1;
    		temp2->next=after1;
    		after1->prev=temp2;
    	}
    
    	if(change1->prev != NULL || change2 != NULL)
    	{
        before2->next = temp1;
    	  temp1->prev = before2;
    	  temp1->next = after2;
    	  after2->prev = temp1;
    
    	  before1->next = temp2;
    	  temp2->prev = before1;
    	  temp2->next = after1;
    	  after1->prev = temp2;
    	}
    
    	if(change1->prev == NULL)
    	{
    	  liste=temp1;
    	}
    
    	if(change2->prev == NULL)
    	{
    	  liste=change2;
    	}
    
    	return(liste);
    }
    


  • anonymer12 schrieb:

    Ich hab folgende Sonderfälle behandelt: change1=1. Element und change2=1. Element.

    Aber es gibt noch 2: change1 = letztes Element und change 2= letztes Element.

    Das sind keine zwei Sonderfälle sondern nur einer: change1 == change2 .
    Also das selbe Element.
    Da brauchst du gar nicht tauschen.

    Es gibt meiner Meinung nach nur zwei Sonderfälle: Wenn einer der prev == NULL ist.

    Aber wie du das machst ist das ein bisschen merkwürdig

    if(change1->prev == NULL) // hier vergleichst du das neue change1 (schon nach dem TAusch)
        {
          liste=temp1;  // das temp1 ist aber noch von vor dem Tausch
        }
    
        if(change2->prev == NULL)
        {
          liste=change2;  // hier ist das ok
        }
    

    Vertausch doch erstmal Elemente aus der Mitte. Dann kannst du noch schauen, ob das Probleme mit dem 1. bzw. letzten Element gibt.



  • Mh ok danke.

    Und was hat es mit Zeile 29 auf sich? Der geht da ja immer rein? Wie könnte ich das verhindern?



  • Zwei Anmerkungen zu meinem letzten Post.
    Der du musst auch next == NULL berücksichtigen.
    Und meine Kommentare in dem Listing sind nicht an der richtigen Stelle.
    Du musst dich aber entscheiden ob du temp oder change nimmst.

    anonymer12 schrieb:

    Und was hat es mit Zeile 29 auf sich? Der geht da ja immer rein? Wie könnte ich das verhindern?

    Du solltest beim Vergleich nicht change1->prev sondern das before1 nehmen
    Da change1 und temp1 auf das selbe Element zeigen, ändert sich bei temp1->prev=before2; logischerweise auch change1->prev

    Gib doch mal die Zeiger als Zwischenergebnis aus. Entweder im Debugger oder mit printf (für Zeiger ist %p da).



  • anonymer12 schrieb:

    Wie kann ich das anders lösen?

    Man kann auch gleich zu Beginn Pointer auf die next und prev zuweisen, respektive auf den Listenstart.
    Geht natürlich nur, wenn man die Funktion selbst als

    void change_pointer(spielzug** liste_zgr, spielzug* change1, spielzug* change2) //liste ist Referenz auf Zeiger auf das 1. Element der Kette, temp1 zeigt auf das element in der kette das mit einen anderen Element in der kette, wo change2 draufzeigt, vertauscht werden muss
    

    definiert, weil man ja auch den Startzeiger der Liste umbiegen muss. Lohnt aber eher, wenn die doppelt verkettete Liste auch Start- und Ende-Zeiger hat.
    Hat den Vorteil, dass man nicht im Zuweisungsteil große Entscheidungstabellen braucht.

    Ciao, Allesquatsch



  • mh ich weis nicht mehr weiter, mit den ganzen verschiedenen "Fällen" und so..

    Change1 kann 1. Element oder letztes Element sein. Change2 kann 1. Element oder letztes Element sein. --> schon 4 andere Fälle die man anders behandeln muss.

    Ich weiß zwar wie man die Elemente vertauscht, aber ich weiß nicht wie man das mit den ganze ifs und so macht, dass alle "Fälle" behandelt werden und sich nicht gegenseitig beeinflussen.

    Bitte gebt mir ein paar Tipps!

    Hier der aktuelle Code:

    spielzug* change_pointer(spielzug* liste, spielzug* change1, spielzug* change2) //liste zeigt auf das 1. Element der Kette, change1 zeigt auf das element in der kette das mit einen anderen Element in der kette, wo change2 draufzeigt, vertauscht werden muss
    {
      spielzug* after1 = NULL;//element nach change1
      spielzug* before1 = NULL;//element bevor change1
    	spielzug* after2 = NULL;//element nach change2
      spielzug* before2 = NULL;//element bevor change2
    	spielzug* temp = NULL;//pointer zum zwischenspeichern von change2
    
    	before1 = change1->prev;//sichern des elements bevor change1
    	after1 = change1->next;//sichern des elements nach change1
    	before2 = change2->prev;//sichern des elements bevor change2
    	after2 = change2->next;//sichern des elements nach change2
    	//temp=change2;//sichern des elements change2
    
    	if(change1->next == NULL)
    	{
    
    	}
    
    	if(change2->next == NULL)
    	{
    
    	}
    
    	if(change1->prev == NULL)//wenn change1 = 1. Elemente --> geht er in die if, sonst nicht.
    	{
    		/*vertauscht die beiden elemente*/
    	  before2->next=change1;
    		change1->prev=before2;
    		after2->prev=change1;
    		change1->next=after2;
    
    		change2->prev=NULL;
    		change2->next=after1;
    		after1->prev=change2;
    
    		liste=change2;
    	}
    	else
    	{
    		/*vertauscht die beiden elemente*/
    		before2->next = change1;
    		change1->prev = before2;
    		change1->next = after2;
    		after2->prev = change1;
    
    		before1->next = temp;
    		temp->prev = before1;
    		temp->next = after1;
    		after1->prev = temp;
    	}
    
    	if(change2->prev == NULL)
    	{
    
    	}
    
    	return(liste);
    }
    


  • anonymer12 schrieb:

    mh ich weis nicht mehr weiter, mit den ganzen verschiedenen "Fällen" und so..

    Change1 kann 1. Element oder letztes Element sein. Change2 kann 1. Element oder letztes Element sein. --> schon 4 andere Fälle die man anders behandeln muss.

    Macht gleich acht daraus 🙂

    Denn auch die Fälle, dass die beiden Elemente untereinander verzeigert sind, stellt einen Sonderfall dar, der zu berücksichtigen ist.

    Bevor Du Hirnkrebs kriegst, kannst Du ja mal die Varianten aufschreiben und jeweils identifizieren, welches die umzubiegenden Zeiger bzw. die neuen Werte sind.

    Ciao, Allesquatsch



  • Wenn ein Zeiger auf NULL zeigt, darfst du auf die Daten nicht zugreifen.
    DArum ist etwas einfacher, wenn du nicht auf if(change1->next == NULL) sondern auf if(after1 != NULL) vergleichst.
    Dann machst du alles das, was du mit after1-> anstellen kannst. (after->before umbiegen)

    Irgendwann brauchst du aber auch if(before1 == NULL) . Dann hat sich der Listenanfang geändert.

    Mal das Ganze auf ein Blatt Papier und dann radierst du die Verbindungen einzeln weg und malst neue. Schreib jedesmal auf was du machst.



  • Ok, danke.

    Ich hab jetzt die Fälle behandelt.

    Was sagt ihr dazu könnte es so funktionieren?

    spielzug* change_pointer(spielzug* liste, spielzug* change1, spielzug* change2) //liste zeigt auf das 1. Element der Kette, change1 zeigt auf das element in der kette das mit einen anderen Element in der kette, wo change2 draufzeigt, vertauscht werden muss
    {
      spielzug* after1 = NULL;//element nach change1
      spielzug* before1 = NULL;//element bevor change1
    	spielzug* after2 = NULL;//element nach change2
      spielzug* before2 = NULL;//element bevor change2
    	spielzug* temp = NULL;//pointer zum zwischenspeichern von change2
    
    	before1 = change1->prev;//sichern des elements bevor change1
    	after1 = change1->next;//sichern des elements nach change1
    	before2 = change2->prev;//sichern des elements bevor change2
    	after2 = change2->next;//sichern des elements nach change2
    	temp=change2;//sichern des elements change2
    	temp1=change1; //sichern des elements change1
    
    	if(before1 == NULL && after2 == NULL)
    	{
    	  before2->next=change1;
    		change1->prev=before2;
    		change1->next=NULL;
    
    		after1->prev=change2;
    		change2->next=after1;
    		change2->prev=NULL;
    	}
    
    	if(before2 == NULL && after1 == NULL)
    	{
    	  before1->next=change2;
    		change2->prev=before1;
    		change2->next=NULL;
    
    		after2->prev=change1;
    		change1->next=after2;
    		change1->prev=NULL;
    	}
    
    	if(after1 == NULL && before2 != NULL)
    	{
    	  before1->next=change2;
    		change2->prev=before1;
    		change2->next=NULL;
    
    		before2->next=change1;
    		change1->prev=before2;
    		after2->prev=change1;
    		change1->next=after2;
    	}
    
    	if(after2 == NULL && before1 != NULL)
    	{
    	  before2->next=change1;
    		change1->prev=before2;
    		change1->next=NULL;
    
    		before1->next=change2;
    		change2->prev=before1;
    		after1->prev=change2;
    		change2->next=after1;
    	}
    
    	if(before1 == NULL && after2 != NULL)//wenn change1 = 1. Elemente --> geht er in die if, sonst nicht.
    	{
    		/*vertauscht die beiden elemente*/
    	  before2->next=change1;
    		change1->prev=before2;
    		after2->prev=change1;
    		change1->next=after2;
    
    		change2->prev=NULL;
    		change2->next=after1;
    		after1->prev=change2;
    
    		liste=change2;
    	}
    
    	if(before2 == NULL && after1 != NULL)
    	{
    		before1->next=change2;
    		change2->prev=before1;
    		after1->prev=change2;
    		change2->next=after1;
    
    		change1->prev=NULL;
    		change1->next=after2;
    		after2->prev=change1;
    
    		liste=change1;
    	}
    
    	if(after1 != NULL && after2 != NULL && before1 != NULL && before2 != NULL)
    	{
    		/*vertauscht die beiden elemente*/
    		before2->next = change1;
    		change1->prev = before2;
    		change1->next = after2;
    		after2->prev = change1;
    
    		before1->next = change1;
    		change2->prev = before1;
    		change2->next = after1;
    		after1->prev = change2;
    	}
    	return(liste);
    }
    


  • Der letzte Teil bei dir ist ja der allgemeine Fall:

    /*vertauscht die beiden elemente*/
            before2->next = change1;
            change1->prev = before2;
            change1->next = after2;
            after2->prev = change1;
    
            before1->next = change1;
            change2->prev = before1;
            change2->next = after1;
            after1->prev = change2;
    

    Wenn man den jetzt nimmt und fragt da die Spezialfälle ab, sollte es etwas übersichtlicher sein.
    Selbst wenn ein Element auf der rechten Seite NULL ist, kannst du es ja zuweisen.
    Es geht ja vor allem darum, keinen Zugriff auf einen NULL-Zeiger zu haben.

    :warning:  ungeprüft.
            /*vertauscht die beiden elemente*/
          if(before2 != NULL)
            before2->next = change1;
          if(change1 != NULL)
          { change1->prev = before2; 
            change1->next = after2; }
          if(after2 != NULL)
            after2->prev = change1;
    
          if(before1 != NULL)
            before1->next = change1;
          if(change2 != NULL)
          { change2->prev = before1;
            change2->next = after1; }
          if(after1 != NULL)
            after1->prev = change2;
    
          if(before1 == NULL)
            liste=change2;
          if(before2 == NULL)
            liste=change1;
    


  • Hallo DirkB, anonymer12,

    Ihr habt nicht daran gedacht, dass es neben den NULL-Pointern noch weitere Sonderfälle gibt, die man unbedingt behandeln muss.
    Im anderen Fall macht ihr einen Loop in die Liste, wenn die beiden zu vertauschenden Elementen hintereinander hängen.

    Zumindest eine zusätzliche if-Abfrage muss noch in den Code.

    Ciao, Allesquatsch


  • Mod

    Allesquatsch schrieb:

    Hallo DirkB, anonymer12,

    Ihr habt nicht daran gedacht, dass es neben den NULL-Pointern noch weitere Sonderfälle gibt, die man unbedingt behandeln muss.
    Im anderen Fall macht ihr einen Loop in die Liste, wenn die beiden zu vertauschenden Elementen hintereinander hängen.

    Zumindest eine zusätzliche if-Abfrage muss noch in den Code.

    Ciao, Allesquatsch

    Der Fall hintereinander liegender Elemente ist allerdings nur deshalb ein Sonderfall, weil Null-zeiger vorkommen können. Im Fall von doppelt verketteten Listen gibt es fast nie gute Gründe, keine Ringlisten zu verwenden.
    Die Invarianten für 0-terminierte Listen sind unnötig komplex und verkomplizieren entsprechend die Algorithmen, die mit diesen arbeiten müssen.

    Ansonsten

    spielzug* remove(spielzug* p)
    {
        spielzug* next = p->next;
        p->prev && ( p->prev->next = p->next );
        p->next && ( p->next->prev = p->prev );
        return next;
    }
    
    void insert(spielzug* p, spielzug* prev, spielzug* next)
    {
        p->next = next;
        p->prev = prev;
        prev && ( prev->next = p );
        next && ( next->prev = p );
    }
    
    spielzug* change_pointer(spielzug* liste, spielzug* change1, spielzug* change2)
    {
        spielzug dummy1, dummy2;
        insert( &dummy1, change2->prev, change2 ); // dummy-element, change1 und chnage2 können so nicht mehr unmittelbar benachbart sein
        insert( &dummy2, change2, change2->next );
    
        spielzug* change1_old = remove( change1 );
        insert( change1, &dummy1, &dummy2 );       // das entfernt gleichzeitig change2, falls change1 != change2
        insert( change2, &dummy1, change1_old );   // hier passiert gar nichts, falls change1 == change2
    
        remove( &dummy1 );
        remove( &dummy2 );
    
        return liste->prev == 0 ? liste : liste == q ? p : q; // Falls der Listenanfang getauscht wurde, muss sich hier nat. etwas ändern.
    }
    

  • Mod

    Im Fall einer Ringliste wird das Ganze erheblich einfacher:

    void swap_spielzug(spielzug** p, spielzug** q)
    {
        spielzug* t = *p;
        *p = *q;
        *q = t;
    }
    
    void intersect(spielzug* p, spielzug* q)
    {
        p->prev->next = q;
        q->prev->next = p;
        swap_spielzug( &p->prev, &q->prev );
    }
    
    spielzug* change_pointer(spielzug* liste, spielzug* p, spielzug* q)
    {
        intersect( p, q );
        intersect( p->next, q->next );
        return liste == p ? q : liste == q ? p : liste;
    }
    

    Der Tausch völlig ohne Sonderfälle und if-Orgien. Die Frage, wo der Listenanfang sein soll, muss nat. zusätzlich geklärt werden.



  • camper schrieb:

    Allesquatsch schrieb:

    Hallo DirkB, anonymer12,

    Ihr habt nicht daran gedacht, dass es neben den NULL-Pointern noch weitere Sonderfälle gibt, die man unbedingt behandeln muss.
    Im anderen Fall macht ihr einen Loop in die Liste, wenn die beiden zu vertauschenden Elementen hintereinander hängen.

    Zumindest eine zusätzliche if-Abfrage muss noch in den Code.

    Ciao, Allesquatsch

    Der Fall hintereinander liegender Elemente ist allerdings nur deshalb ein Sonderfall, weil Null-zeiger vorkommen können.

    Meiner Meinung NEIN. Das Problem hintereinanderhängender Elemente ist, dass ein Element gleichzeitig auch der Vorgänger bzw. Nachfolger ist, in dem man die Zeiger anpasst.

    Damit sind die zu ändernden Zeiger identisch. Je nachdem in welcher Reihenfolge man arbeitet, überschreibt man den korrekten Wert mit einem Zeiger auf sich selbst.

    Ciao, Allesquatsch


  • Mod

    Allesquatsch schrieb:

    camper schrieb:

    Der Fall hintereinander liegender Elemente ist allerdings nur deshalb ein Sonderfall, weil Null-zeiger vorkommen können.

    Meiner Meinung NEIN. Das Problem hintereinanderhängender Elemente ist, dass ein Element gleichzeitig auch der Vorgänger bzw. Nachfolger ist, in dem man die Zeiger anpasst.

    Damit sind die zu ändernden Zeiger identisch. Je nachdem in welcher Reihenfolge man arbeitet, überschreibt man den korrekten Wert mit einem Zeiger auf sich selbst.

    Wenn man so vorgeht.
    Das Problem mit Nullzeigern ist, dass sie als Indikatoren für eine Position unbrauchbar sind, weil man den Nachfolger (beim Listenanfang) bzw. Vorgänger (am Ende) nicht aus ihnen ableiten kann. Da ein lineare Liste aus N Elementen über N+1 Einfügestelle verfügt, genügt für diese Einfügestellen nicht ein einfacher Verweis auf das Vorgäner- oder Nachfolgerelement. Sonderfälle sind damit unvermeidlich. Welche Form diese Sondefälle haben, hängt nun von der konkreten Strategie ab.
    Eine Ringliste hat dieses Problem nicht; eine N-elementige Ringliste verfügt auch nur über N Einfügestellen. Ich denke, mein obiger Code demonstriert das hinreichend.



  • camper schrieb:

    Allesquatsch schrieb:

    Meiner Meinung NEIN. Das Problem hintereinanderhängender Elemente ist, dass ein Element gleichzeitig auch der Vorgänger bzw. Nachfolger ist, in dem man die Zeiger anpasst.

    Damit sind die zu ändernden Zeiger identisch. Je nachdem in welcher Reihenfolge man arbeitet, überschreibt man den korrekten Wert mit einem Zeiger auf sich selbst.

    Wenn man so vorgeht.
    Das Problem mit Nullzeigern ist,

    Nochmals NEIN.
    Das von mir angesprochene Problem hat nichts mit NULL-Pointern zu tun und tritt auch auf, wenn man mit Ringketten arbeitet.
    Es hat damit zu tun, dass man jeweils für die beiden zu vertauschenden Elemente und in ihren Vorgängern/Nachfolgern Zeiger verbiegen muss. Und damit müssen die Sonderfälle berücksichtigt werden, wenn die beiden Elemente schon vorher in einer Vorgänger/Nachfolger-Beziehung stehen.

    Einfach mal das Problem auf Papier malen, dann fällt das Nachdenken leichter.

    Hängt Element2 hinter Element1 würde das Ändern des Vorgängers von Element2 bedeuten, dass man Element1 auf sich selbst zeigen lässt 🙂
    Hängt von der Schreibreihenfolge der Zeiger ab, wann man so die Kette korrumpiert.

    Ciao, Allesquatsch


  • Mod

    Allesquatsch schrieb:

    Einfach mal das Problem auf Papier malen, dann fällt das Nachdenken leichter.

    Danke, und gleich zurück. Ich habe bereits einfachen und funktionierenden Code (für Ringlisten) geliefert. Bei einer linearen Liste funktioniert entsprechend, sofern keine der getauschten Elemente unmittelbar am Anfang oder Ende liegt, also sind das die Spezialfälle.
    Ich weigere mich auf eine allgemeine Diskussion einzulassen, solange du kein Beispiel bringst, in dem die Funktion versagt.

    Allesquatsch schrieb:

    Hängt Element2 hinter Element1 würde das Ändern des Vorgängers von Element2 bedeuten, dass man Element1 auf sich selbst zeigen lässt 🙂

    Richtig. Ist das ein Problem? An dieser Stelle ist man schließlich noch nicht fertig.



  • Dann dürfte es so funktionieren oder?

    if(before2 != NULL && before2 != change1)
    	{
        before2->next = change1;
    	}
    
      if(change1 != NULL)
    	{ 
    	  change1->prev = before2;
        change1->next = after2; 
    	}
    
      if(after2 != NULL && after2 != change2)
    	{
        after2->prev = change1;
    	}
    
      if(before1 != NULL && before1 != change2)
    	{
        before1->next = change2;
    	}
    
      if(change2 != NULL)
      { 
    		change2->prev = before1;
        change2->next = after1; 
    	}
    
      if(after1 != NULL && after1 != change2)
    	{
        after1->prev = change2;
    	}
    
      if(before1 == NULL)
    	{
        liste=change2;
    	}
    
      if(before2 == NULL)
    	{
    		liste=change1;
    	}
    

  • Mod

    anonymer12 schrieb:

    Dann dürfte es so funktionieren oder?

    if(before2 != NULL && before2 != change1)
    	{
        before2->next = change1;
    	}
    
      if(change1 != NULL)
    	{ 
    	  change1->prev = before2;
        change1->next = after2; 
    	}
    
      if(after2 != NULL && after2 != change2)
    	{
        after2->prev = change1;
    	}
    
      if(before1 != NULL && before1 != change2)
    	{
        before1->next = change2;
    	}
    
      if(change2 != NULL)
      { 
    		change2->prev = before1;
        change2->next = after1; 
    	}
    
      if(after1 != NULL && after1 != change2)
    	{
        after1->prev = change2;
    	}
    
      if(before1 == NULL)
    	{
        liste=change2;
    	}
    
      if(before2 == NULL)
    	{
    		liste=change1;
    	}
    

    Keine Ahnung. Das ist schlicht zu lang.
    Nach ein bisschen mehr Überlegen finde ich, dass auch einfache lineare Listen ohne Sonderfallbehandlung auskommen, ganz analog zu zur Variante für Ringlisten kann man schreiben

    void swap_spielzug(spielzug** p, spielzug** q)
    {
        spielzug* t = *p;
        *p = *q;
        *q = t;
    }
    
    void crosslink_prev(spielzug* p, spielzug* q)
    {
        swap_spielzug( &p->prev, &q->prev );
        p->prev && ( p->prev->next = p );
        q->prev && ( q->prev->next = q );
    }
    
    void crosslink_next(spielzug* p, spielzug* q)
    {
        swap_spielzug( &p->next, &q->next );
        p->next && ( p->next->prev = p );
        q->next && ( q->next->prev = q );
    }
    
    spielzug* change_pointer(spielzug* liste, spielzug* p, spielzug* q)
    {
        crosslink_prev( p, q );
        crosslink_next( p, q );
        return liste->prev == 0 ? liste : p->prev == 0 ? p : q;
    }
    

    Und weils es mir sowieso nicht geglaubt wird, skizziere ich mal die wichtigsten Fälle:

    Fall1:
    Ausgangssituation:
          p       q
    0-->| A |-->| B |-->| C |-->| D |-->0
    
    Zwischenschritt:
          q                               p
    0-->| B |-->| C |-->| D |-->0    -->| A |--
                                     |        |
                                     -----<----
    2. Schritt:
          q       p
    0-->| B |-->| A |-->| C |-->| D |-->0
    
    Fall2:
          p               q
    0-->| A |-->| B |-->| C |-->| D |-->0
    
    Zwischenschritt:
          q                       p
    0-->| C |-->| D |-->0    -->| A |-->| B |--
                             |                |
                             -------<----------
    2. Schritt:
          q               p
    0-->| C |-->| B |-->| A |-->| D |-->0
    
    Fall3:
          p                       q
    0-->| A |-->| B |-->| C |-->| D |-->0
    
    Zwischenschritt:
          q               p
    0-->| D |-->0    -->| A |-->| B |--| C |--
                     |                       |
                     ------------<------------
    2. Schritt:
          q                       p
    0-->| D |-->| B |-->| C |-->| A |-->0
    
    Fall4:
    Ausgangssituation:
                  p       q
    0-->| A |-->| B |-->| C |-->| D |-->0
    
    Zwischenschritt:
                  q                       p
    0-->| A |-->| C |-->| D |-->0    -->| B |--
                                     |        |
                                     -----<----
    2. Schritt:
                  q       p
    0-->| A |-->| C |-->| B |-->| D |-->0
    


  • camper schrieb:

    Allesquatsch schrieb:

    Einfach mal das Problem auf Papier malen, dann fällt das Nachdenken leichter.

    Danke, und gleich zurück. Ich habe bereits einfachen und funktionierenden Code (für Ringlisten) geliefert. Bei einer linearen Liste funktioniert entsprechend, sofern keine der getauschten Elemente unmittelbar am Anfang oder Ende liegt, also sind das die Spezialfälle.
    Ich weigere mich auf eine allgemeine Diskussion einzulassen, solange du kein Beispiel bringst, in dem die Funktion versagt.

    Touchee, habe tatsächlich mehr auf den Text und die Listings im ursprünglichen Stil geachtet und mir Dein Coding nicht genau genug angesehen.

    Du hast recht, dass das Problem bei Deinem Code nicht auftritt, da Du das Herauslösen und das Wiedereinfügen in getrennten Schritten machst.
    Halte Deine Codierung für handwerklich perfekt. 👍

    Es liegt aber an dieser Vorgehensweise und weniger daran, dass die Kette "verringt" ist. Denn auch bei einem Ring bekommt man das Problem, wenn man die Zeigerverbiegerei in einem Schritt für beide Elemente ausführt.

    Ciao, Allesquatsch


Anmelden zum Antworten