Quicksort Fehler: Endlosschleife

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Unplayable
User
Beiträge: 51
Registriert: Mittwoch 24. Februar 2016, 22:09

Hallo Zusammen,

ich bin dabei, einen Quicksort-Algorithmus zu schreiben, welcher nach dem folgenden Muster läuft:

-Pivot = erste Zahl der Liste
-i = Cursor, der von links so lange durchläuft wie die Zahl kleiner als die Pivot Zahl ist.
-j = Cursor, der von rechts so lange durchläuft, wie die Zahl größer als die Pivot Zahl ist

Wenn beide stehen bleiben, sollen die entsprechenden Zahlen getauscht werden
Wenn der rechte Cursor den linken überholt, dann wird die Liste zwischen den beiden Zahlen, auf denen die Cursor stehen in zwei neue Listen geteilt und das ganze beginnt von vorne. Leider bin ich hier bei diesem Code in einer Endlosschleife gefangen:

Code: Alles auswählen

def quicksort(liste):
  
    list = liste[:]


    if len(list) == 1 or len(list) == 0:
        return list

    else:

        p = list[0]

        i = 0
        j = -1

        while i < j:
            
             while list[i] <= p:
                i = i+1

             while list[j] >= p:
                j = j-1


             if list[i] > p and list[j] < p:
                 x = list[i]
                 list[i] = list[j]
                 list[j] = x
                 i = i+1
                 j = j-1
    
        if i > j:
            links = list[:i]
            rechts = list[i:]

     
        return quicksort(links) + quicksort(rechts)

Könnte mir jemand vielleicht helfen?
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@Unplayable: der Code ist wegen der vielen Leerzeilen sehr schlecht lesbar. `list` ist ein wichtiger vordefinierter Name und sollte nicht überschrieben werden. Ein neuer Variablenname ist hier auch gar nicht nötig, weil `liste` sonst nicht mehr gebraucht wird. Das `or` der ersten `if`-Abfrage ließe sich mit `<=` einfacher schreiben. Da die if-Abfrage ein `return` enthält, kann man sich das `else` und die weitere Einrückeben des Rests sparen. Das `if` in der `while`-Schleife kannst Du Dir sparen, weil die beiden Bedingungen wegen der `while`-Schleifen davo immer erfüllt sind; das `x` kannst Du Dir sparen, wenn Du Tuple zum Austauschen benutzt. Die letzte `if`-Abfrage ist falsch, wenn `i == j` ist, wird `links` und `rechts` nie definiert.
Ohen was an der Logik zu ändern kommt man dann zu:

Code: Alles auswählen

def quicksort(liste):
    liste = liste[:]
    if len(liste) <= 1:
        return liste
    p = liste[0]
    i = 0
    j = -1
    while i < j:
        while liste[i] <= p:
            i += 1
        while liste[j] >= p:
            j -= 1
        liste[i], liste[j] = liste[j], liste[i]
        i += 1
        j -= 1
    links = liste[:i]
    rechts = liste[i:]
    return quicksort(links) + quicksort(rechts)
Zu den eigentlichen Problemen: Man kann zwar mit negativen Zahlen Listen indizieren, die Mathematik ändert das aber nicht, so dass die while-Schleife nie betreten wird. Du packst das Pivot-Element in beide Listen; da sich das erste Element nie ändert, ändert es sich für den linken Ast nie, Zahlen kleiner dem ersten Element werden also nicht sortiert.
Unplayable
User
Beiträge: 51
Registriert: Mittwoch 24. Februar 2016, 22:09

Oh mist. Jetzt sehe ich es auch. Klar kann etwas negatives nie kleiner als etwas positives sein. Solche Anfängerfehler unterlaufen mir leider noch zu oft. Ich müsste also bei "j" versuchen mit dem Betrag von j zu arbeiten. Sehe ich das richtig so?

Zu deinen Anmerkungen bezüglich des Codes:

-ich habe das 3 Schritt-Tauschen so beigebracht bekommen weil das Tauschen mit den Tupeln angeblich Probleme machen kann. Außerdem hieß es, dass man gerne zwischen den Befehlen eine Leerzeile setzen kann. Ich habe es von Anfang an so gelernt, also entschuldige das bitte :)
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@Unplayable: nein, Betrag ist immer noch falsch. Leerzeilen sollen die Lesbarkeit steigern und das ist nur selten der Fall. Durch die Einrückung wird eigentlich meist schon genug strukturiert. Wer Dir das 3-Schritt-Tauschen beigebracht hat, weiß offensichtlich nicht, wie das einfachere Tauschen funktioniert; es gibt damit weniger Probleme als beim komplizierteren mit Hilfsvariable.
Aber keine Sorge, mit viel Geduld kann man sich schlechte Angewohnheiten auch wieder abgewöhnen.
Unplayable
User
Beiträge: 51
Registriert: Mittwoch 24. Februar 2016, 22:09

Also ich habe jetzt versucht, J positiv zu bekommen:

Code: Alles auswählen

def quicksort(liste):
    liste = liste[:]
    if len(liste) <= 1:
        return liste
    p = liste[0]
    i = 0
    j = -1
    while i < j*(-1):  
        for i in range(len(liste)-1):
            if liste[i] <= p:
                i = i+1
        for j in range(0,len(liste)):
            if liste[j] >= p:
                j = j-1
        if liste[i] > p and liste[j] < p:
            liste[i], liste[j] = liste[j], liste[i]
            i = i+1
            j = j-1
    links = liste[:i]
    rechts = liste[i:]
    return quicksort(links) + quicksort(rechts)
ist jedoch wie du gesagt hast immer noch nicht zielführend.
Die for Schleifen habe ich eingebaut, weil er mir sonst immer den Fehler: List index out of range liefert
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@Unplayable: Programmieren ist nicht Raten. Wenn Du die for-Schleifen nochmal genau anschaust, wirst Du sehen, dass sie Quatsch sind. Versuche die while-Schleifenbedingung entsprechend anzupassen. Versuch mal Deinen Algorithmus mit Papier und Bleistift an einem Beispiel Schritt für Schritt nachzuvollziehen.
Unplayable
User
Beiträge: 51
Registriert: Mittwoch 24. Februar 2016, 22:09

Tut mir leid. Ich steh mit der While Schleife gerade echt auf dem Schlauch. Ich denke ich werde es mir morgen noch mal in der Schule erklären lassen. :?
Antworten