Suchen, Sortieren und Effizienz

Lerne, wie Computer Daten finden und ordnen und wie du ein schnelles von einem langsamen Verfahren unterscheidest. Vollziehe die lineare und die binäre Suche sowie die drei klassischen Sortierverfahren Bubblesort, Selectionsort und Mergesort an konkreten Listen nach. Zähle die Rechenschritte der Verfahren, untersuche, wie ihre Anzahl mit der Datenmenge wächst, und schätze Laufzeiten ab. Begründe anschließend, warum ein Algorithmus immer das richtige Ergebnis liefert, teste ihn anhand von Randfällen und wähle den zur Situation passenden Algorithmus.

AnfängerEinheit 4 von 7 in Kurs: Informatik – Computer, Algorithmen, Internet und KI verstehen

Was du lernst

  1. Finde einen Suchwert in einer Liste mit der linearen Suche und, wenn die Liste sortiert ist, mit der binären Suche. Vollziehe beide Verfahren an konkreten Listen nach und zähle, wie viele Elemente sie prüfen.
    • Durchsuche eine beliebige Liste mit der linearen Suche
      Prüfe die Elemente vom Anfang an einzeln, gib die Position des ersten Treffers zurück oder melde, dass der Suchwert fehlt, und zähle die Vergleiche im besten und schlechtesten Fall.
    • Durchsuche eine sortierte Liste mit der binären Suche
      Nutze die sortierte Reihenfolge, um den noch infrage kommenden Teil der Liste bei jeder Prüfung zu halbieren, verfolge die untere, obere und mittlere Position und erkläre, warum etwa log₂ n Prüfungen ausreichen.
  2. Beschreibe, was eine korrekte Sortierung liefern muss, vollziehe dann Bubblesort und Selectionsort Durchlauf für Durchlauf nach und zähle Vergleiche und Vertauschungen.
    • Beschreibe, woran du eine korrekt sortierte Liste erkennst
      Definiere sortierte Reihenfolge, Sortierschlüssel, Vertauschungen, Stabilität, Sortieren innerhalb der Liste und Inversionen, um Sortierverfahren nachzuvollziehen, zu prüfen und zu vergleichen.
    • Vollziehe Bubblesort nach und zähle die Rechenschritte
      Sortiere eine Liste, indem du wiederholt falsch angeordnete Nachbarn vertauschst, vollziehe die einzelnen Durchläufe nach, brich ab, wenn ein Durchlauf keine Vertauschung vornimmt, und zähle Vergleiche und Vertauschungen.
    • Vollziehe Selectionsort nach und zähle die Rechenschritte
      Sortiere eine Liste, indem du wiederholt das kleinste verbliebene Element auswählst und an seinen Platz tauschst, vollziehe die einzelnen Durchläufe nach und vergleiche die Anzahl der Vergleiche und Vertauschungen mit Bubblesort.
  3. Verschmelze zwei sortierte Listen zu einer Liste, vollziehe nach, wie Mergesort eine Liste teilt und die Teile wieder verschmilzt, und erkläre, warum es etwa n log₂ n Vergleiche benötigt.
    • Verschmelze zwei sortierte Listen zu einer Liste
      Führe zwei bereits sortierte Listen zusammen, indem du wiederholt das kleinere Kopfelement entnimmst, zähle die Vergleiche und erkläre, warum das Ergebnis sortiert ist.
    • Vollziehe Mergesort nach und erkläre, warum der Aufwand mit n log n wächst
      Sortiere, indem du eine Liste halbierst, bis einzelne Elemente übrig sind, und die Teile geordnet wieder verschmilzt. Nutze einen Basisfall, um das Teilen zu beenden, und zähle die Vergleiche Ebene für Ebene.
  4. Zähle die elementaren Schritte eines Algorithmus in Abhängigkeit von der Eingabegröße, vergleiche logarithmisches, lineares und quadratisches Wachstum sowie Wachstum der Größenordnung n log n und nutze Wachstumsraten, um Laufzeiten abzuschätzen.
    • Zähle die Rechenschritte eines Algorithmus
      Miss einen Algorithmus daran, wie viele Elementaroperationen er bei einer Eingabe der Größe n ausführt, bestimme die Anzahl für Schleifen und verschachtelte Schleifen und unterscheide den besten, schlechtesten und durchschnittlichen Fall.
    • Vergleiche, wie die Anzahl der Rechenschritte mit der Eingabegröße wächst
      Erkenne konstanten, logarithmischen, linearen, quadratischen und exponentiellen Aufwand sowie Aufwand der Größenordnung n log n, untersuche die Verdopplung der Eingabe, lies die informellen O-Schreibweisen und erkläre, warum die Wachstumsrate bei großen Eingaben wichtiger ist als konstante Faktoren.
    • Schätze Laufzeiten ab und miss sie
      Nutze eine bekannte Laufzeit und eine Wachstumsrate, um die Zeit für eine größere Eingabe abzuschätzen, überprüfe eine Wachstumsrate durch Zeitmessungen bei sich verdoppelnden Größen und kennzeichne Prognosen als Schätzungen.
  5. Zeige, dass ein Algorithmus für jede zulässige Eingabe anhält und das richtige Ergebnis liefert, teste ihn anhand von Randfällen und wäge Zeit, Speicher und weitere Zielkonflikte ab, um einen zur Situation passenden Algorithmus zu wählen.
    • Begründe, warum ein Algorithmus korrekt ist
      Beschreibe, was ein Algorithmus leisten muss, erkläre, warum Tests allein seine Korrektheit nicht beweisen können, und zeige mithilfe von Schleifeninvarianten und einem Terminierungsargument, dass Such- und Sortieralgorithmen funktionieren.
    • Teste Algorithmen anhand von Randfällen
      Wähle Eingaben an den Rändern dessen, was ein Algorithmus verarbeiten kann, sage vor der Ausführung das erwartete Ergebnis voraus und finde Off-by-one-Fehler und Endlosschleifen, die bei gewöhnlichen Eingaben unentdeckt bleiben.
    • Wähle einen zur Situation passenden Algorithmus
      Vergleiche Such- und Sortieralgorithmen hinsichtlich Zeit, Speicher, Stabilität und Anforderungen an die Daten und entscheide, welcher zu einer Aufgabe passt und wann sich vorheriges Sortieren lohnt.

Suchen, Sortieren und Effizienz einfach erklärt

5 Kapitel

1

Durchsuche eine Liste Schritt für Schritt

Die Suche nach einem Wert beginnt mit einer einfachen Frage: Welche Positionen müssen noch geprüft werden? Vollziehe die lineare Suche in einer gewöhnlichen Liste nach und nutze dann bei der binären Suche die sortierte Reihenfolge, um große Teile einer Liste auszuschließen. Du verfolgst Positionen und Werte getrennt, siehst, wie beide Suchverfahren einen Misserfolg melden, und zählst den Aufwand für einfache und schwierige Eingaben. Kurze Abläufe zeigen außerdem, warum auch die letzte verbliebene Position geprüft werden muss.

1.1 Durchsuche eine beliebige Liste mit der linearen Suche

Eine Suche klärt, ob ein Suchwert vorkommt und wo er vorkommt. Eine Liste hat nummerierte Positionen, die Indizes heißen. Python zählt ab null: In [7, 3, 9, 3, 5] steht an Index 0 die 7 und an Index 4 die 5. Der Wert und sein Index beantworten verschiedene Fragen.

Ein Element nach dem anderen prüfen

Die lineare Suche, auch sequenzielle Suche genannt, beginnt beim ersten Element und vergleicht jedes Element mit dem Suchwert. Sie gibt sofort einen Index zurück, wenn sie einen Treffer findet. Endet die Liste ohne Treffer, gibt sie -1 zurück, unser Zeichen für „nicht gefunden“.

def linear_search(items, target):
    for i in range(len(items)):
        if items[i] == target:
            return i
    return -1

len(items) liefert die Anzahl der Elemente. range(len(items)) liefert jeden zulässigen Index, beginnend bei 0 und endend unmittelbar vor der Länge. items[i] liest den Wert am aktuellen Index. Ein return beendet die Funktion, sodass ein späterer Treffer den ersten nie ersetzt.

Die Suche nach 3 in der obigen Liste verläuft so:

  1. Vergleiche an Index 0 die 7 mit der 3. Sie sind verschieden, also suche weiter.
  2. Vergleiche an Index 1 die 3 mit der 3. Sie stimmen überein, also gib Index 1 zurück.

Das Ergebnis ist nach zwei Vergleichen Index 1. Die zweite 3 an Index 3 wird nicht mehr geprüft. Bei der Suche nach 4 werden stattdessen 7, 3, 9, 3 und 5 geprüft; nach fünf Vergleichen wird -1 zurückgegeben. Ein zurückgegebener Index 1 bezeichnet das zweite Element, nicht ein Element mit dem Wert 1.

Den Aufwand zählen

Sei n die Anzahl der Elemente. Bei einer nicht leeren Liste ist der beste Fall ein Vergleich: Das erste Element stimmt überein. Der schlechteste Fall sind n Vergleiche: Der Suchwert steht am Ende oder fehlt. Eine leere Liste benötigt null Vergleiche und gibt -1 zurück.

Kommt ein Suchwert einmal vor und steht er mit gleicher Wahrscheinlichkeit an jeder Position, beträgt die durchschnittliche Anzahl der Vergleiche

1+2+⋯+nn=n+12.

Bei 1.000 Elementen sind das 500,5 Vergleiche. Ein Durchschnitt kann eine Bruchzahl sein, obwohl jede einzelne Suche eine ganze Anzahl von Vergleichen ausführt. Dieser Durchschnitt beschreibt genau diese Verteilung erfolgreicher Suchen; häufige erfolglose Suchen würden den Gesamtdurchschnitt erhöhen.

Den Misserfolg nach der Schleife zurückgeben

Ein else: return -1 innerhalb der Schleife würde beim ersten nicht übereinstimmenden Element aufgeben. Bei [7, 3, 9] würde es die Suche nach 3 zurückweisen, nachdem nur 7 geprüft wurde. Die Rückgabe bei Misserfolg gehört hinter die Schleife, wenn jede Position ausgeschlossen wurde.

Die lineare Suche benötigt weder eine sortierte Reihenfolge noch eine Vorbereitung. Sie funktioniert mit Zahlen, Wörtern oder Datensätzen, die anhand einer ID verglichen werden. Eine für sortierte Daten entwickelte Version kann anhalten, wenn sie die mögliche Position des Suchwerts passiert: In [2, 5, 8, 12] reicht es, die 8 zu sehen, um die 6 auszuschließen. Der obige Code sucht bewusst weiter, bis er einen Treffer findet oder das Ende erreicht.

Verwandte Aufgaben nutzen denselben Durchlauf, aber eine andere Abbruchregel. Um jedes Vorkommen zu zählen, jeden passenden Index zu sammeln oder ein größtes Element zu finden, muss die gesamte Liste geprüft werden; bei der Suche nach dem ersten Treffer ist eine frühere Rückgabe möglich.

Wichtige Erkenntnisse

  • Die lineare Suche prüft Positionen der Reihe nach und gibt den ersten passenden Index zurück.
  • Gib -1 erst zurück, nachdem jeder mögliche Treffer ausgeschlossen wurde.
  • Eine nicht leere Liste benötigt bestenfalls einen Vergleich und schlechtestenfalls n.
  • Der Durchschnitt (n+1)/2 setzt voraus, dass der Suchwert einmal vorkommt und mit gleicher Wahrscheinlichkeit an jeder Position steht.

1.2 Durchsuche eine sortierte Liste mit der binären Suche

Die binäre Suche nutzt die sortierte Reihenfolge, um Positionen auszuschließen, ohne sie einzeln zu prüfen. Ihre Eingabe muss aufsteigend sortiert sein. Außerdem benötigt sie schnellen Zugriff auf ein Element an einem gewählten Index, wie ihn ein Array oder eine Python-Liste bietet.

Ein Intervall mit eingeschlossenen Endpunkten verwalten

low und high markieren die erste und letzte noch mögliche Position; beide Endpunkte gehören dazu. Beginne mit low = 0 und high = len(items) - 1. Wähle den mittleren Index durch Abrunden. Ist der mittlere Wert zu klein, ist jeder Wert links davon ebenfalls zu klein; verschiebe low hinter die Mitte. Ist er zu groß, verschiebe high unmittelbar vor die Mitte.

def binary_search(items, target):
    low = 0
    high = len(items) - 1
    while low <= high:
        mid = (low + high) // 2
        if items[mid] == target:
            return mid
        elif items[mid] < target:
            low = mid + 1
        else:
            high = mid - 1
    return -1

// dividiert und rundet ab. Die Schleife schließt den Fall low == high ein, weil noch eine ungeprüfte Position übrig ist. Bei low > high ist das Suchintervall leer.

Treffer und Misserfolg nachvollziehen

Verwende [3, 8, 12, 17, 23, 31, 42, 56, 64, 77, 85] mit den Indizes 0 bis 10. Bei der Suche nach 64 ist der erste mittlere Index 5 und enthält 31. Da 31 zu klein ist, setze low = 6. Der nächste mittlere Index ist 8 und enthält 64. Gib nach zwei Prüfungen eines mittleren Elements 8 zurück.

Bei der Suche nach 20 in derselben Liste:

PrüfunglowhighmidMittlerer WertAktualisierung
1010531high wird 4
204212low wird 3
334317low wird 4
444423high wird 3

Jetzt ist das Suchintervall leer, gib also -1 zurück. Dieser Misserfolg ist begründet: Die sortierte Reihenfolge rechtfertigte jeden ausgeschlossenen Teil.

Warum das Verfahren schnell ist

Jede erfolglose Prüfung lässt höchstens die Hälfte des Suchintervalls übrig. Bei einer nicht leeren Liste beträgt die maximale Anzahl der Prüfungen mittlerer Elemente ⌊log⁡2n⌋+1. Der Logarithmus zur Basis 2 beschreibt wiederholtes Halbieren: 210=1.024, sodass tausend Elemente höchstens 10 Prüfungen benötigen; eine Million benötigt höchstens 20. Eine Prüfung in diesem Python-Code kann zwei Vergleiche ausführen, == und <. Prüfungen und Vergleiche sind verschiedene Zähleinheiten.

Voraussetzungen und Fehler an den Rändern

Die sortierte Reihenfolge ist unerlässlich. Die Suche nach 2 in [9, 2, 7, 4, 1] sieht zuerst 7 und verwirft den rechten Teil, sieht dann 9 und verwirft den verbliebenen Treffer an Index 1. Auch der schnelle Zugriff auf die Mitte ist wichtig: Musst du Verweisen folgen, um die Mitte einer verketteten Liste zu erreichen, geht der Geschwindigkeitsvorteil der Array-Version verloren.

Schließe das geprüfte mittlere Element nach einem Misserfolg immer aus. Mit low = mid kann [10, 20] bei der Suche nach 20 für immer unverändert bleiben. while low < high überspringt den letzten Kandidaten und schlägt bei der Suche nach 5 in [5] fehl. Bei einer leeren Liste gilt high = -1, sodass die korrekte Schleife nie beginnt.

Bei Duplikaten gibt diese Version einen beliebigen passenden Index zurück. Die Suche nach 4 in [2, 4, 4, 4, 9] gibt sofort Index 2 zurück; um das erste Vorkommen zu finden, braucht man eine abgewandelte Suche, die nach einem Treffer links weitersucht.

Wichtige Erkenntnisse

  • Die binäre Suche benötigt sortierte Daten und schnellen Zugriff auf Positionen.
  • Verwalte ein Suchintervall mit eingeschlossenen Endpunkten und fahre fort, solange low <= high gilt.
  • Schließe nach einem Misserfolg mid mit mid + 1 oder mid - 1 aus.
  • Für n>0 sind höchstens ⌊log⁡2n⌋+1 Prüfungen mittlerer Elemente nötig.
  • Ein passender Index muss nicht das erste Vorkommen bezeichnen.
  • Ein leeres Suchintervall bedeutet, dass der Suchwert fehlt.
2

Sortiere eine Liste mit Bubblesort und Selectionsort

Eine Liste kann geordnet aussehen und dennoch die falschen Elemente enthalten. Präzisiere zunächst die Sortieraufgabe, einschließlich wiederholter Schlüssel und der zugehörigen Datensätze. Vollziehe dann zwei Verfahren nach, die durch Vertauschungen Ordnung herstellen: Bubblesort platziert das größte verbliebene Element rechts, Selectionsort das kleinste verbliebene Element links. Ihre Abläufe zeigen unterschiedliche Kosten für Vergleiche und Verschiebungen.

2.1 Beschreibe, woran du eine korrekt sortierte Liste erkennst

Beim Sortieren werden Elemente nach einem gewählten Schlüssel umgeordnet. Bei aufsteigend sortierten Zahlen ist jedes Element kleiner als oder gleich dem nächsten. „Nicht absteigend“ lässt gleiche Nachbarn zu: [2, 5, 5, 9] ist sortiert. Die absteigende Reihenfolge kehrt die Richtung um.

Zwei Bedingungen prüfen

Eine korrekte Sortierung muss eine geordnete Ausgabe erzeugen, die genau die ursprünglichen Elemente mit allen Wiederholungen enthält. Das Sortieren von [3, 1, 2] zu [1, 2, 3] gelingt. Sowohl [1, 2] als auch [1, 1, 3] sind falsch, obwohl ihre Nachbarn geordnet sind. Im ersten Fall fehlt ein Element; im zweiten hat sich geändert, welche Elemente vorkommen. Eine Umordnung, die alle Vorkommen erhält, heißt Permutation.

Bei einem Datensatz ist der Schlüssel nur das Feld, anhand dessen verglichen wird. Städte könnten nach Name oder Einwohnerzahl sortiert werden. Wird der Schlüssel mit der Einwohnerzahl verschoben, bewegt sich der gesamte Stadtdatensatz mit; den Namen davon zu trennen würde die Daten verfälschen.

Die Textreihenfolge hängt vom Schlüssel ab

Ein einfacher Textvergleich folgt den Zeichencodes, Zeichen für Zeichen. In ASCII und Unicode nutzen A–Z die Codes 65–90 und a–z die Codes 97–122. Deshalb steht „Zebra“ bei einem einfachen Vergleich vor „apfel“. Der Vergleich kleingeschriebener Kopien kann bei diesen Beispielen eine Reihenfolge unabhängig von Groß- und Kleinschreibung liefern.

Auch Ziffern in Texten verhalten sich wie Zeichen. „10“ steht beim Sortieren vor „9“, weil sein erstes Zeichen „1“ ist. Ein numerischer Schlüssel wandelt diese Zeichenketten in die Zahlen um, die sie darstellen, sodass 9 vor 10 steht. Entscheide, was die Daten bedeuten, bevor du den Vergleich wählst.

Werte verschieben, ohne sie zu verlieren

Eine Vertauschung tauscht zwei Positionen aus. Eine temporäre Variable sichert den Wert, der sonst überschrieben würde:

temp = items[i]
items[i] = items[j]
items[j] = temp

Python erlaubt auch items[i], items[j] = items[j], items[i]. Schreibst du die beiden Zuweisungen, ohne den ersten Wert zu sichern, wird aus [4, 7] die Liste [7, 7]. Bubblesort und Selectionsort verschieben Elemente durch Vertauschungen; Mergesort kopiert Elemente in eine verschmolzene Ausgabe.

Stabilität und Speicher

Ein stabiles Sortierverfahren erhält die ursprüngliche Reihenfolge von Datensätzen mit gleichen Schlüsseln. Beginne mit Ana 85, Ben 92, Cara 85 in alphabetischer Reihenfolge. Eine stabile Sortierung nach absteigender Punktzahl ergibt Ben 92, Ana 85, Cara 85. Ana bleibt vor Cara. So kann eine spätere Sortierung nach Punktzahl innerhalb jeder Punktzahlgruppe eine frühere alphabetische Reihenfolge erhalten. Pythons eingebaute Sortierfunktion ist stabil.

Ein Sortierverfahren, das innerhalb der Liste arbeitet, ordnet die bestehende Liste mit nur wenigen zusätzlichen Variablen um, unabhängig von ihrer Länge. Die hier behandelten Verfahren Bubblesort und Selectionsort arbeiten innerhalb der Liste. Das übliche Mergesort benötigt zusätzlichen Speicher proportional zur Anzahl der Elemente. Stabilität und Speicher beschreiben verschiedene Eigenschaften: Ein Sortierverfahren kann innerhalb der Liste arbeiten und dennoch instabil sein.

Unordnung mit Inversionen messen

Eine Inversion ist ein Positionspaar, bei dem der Schlüssel eines früheren Elements größer ist als der eines späteren. In [5, 1, 4, 2, 8] sind die Inversionen (5, 1), (5, 4), (5, 2) und (4, 2): insgesamt vier. Die Paare müssen keine Nachbarn sein.

Eine sortierte Liste hat null Inversionen. Eine umgekehrt sortierte Liste aus n verschiedenen Elementen hat n(n−1)/2, also die größtmögliche Anzahl. Gleiche Schlüssel bilden nie eine Inversion: [3, 3, 1] hat zwei, eine für jede 3 vor der 1. Das Zählen von Inversionen hilft, die Anzahl der Vertauschungen bei Bubblesort zu erklären.

Wichtige Erkenntnisse

  • Eine korrekte Sortierung erhält jedes ursprüngliche Element und ordnet die Schlüssel.
  • Ein Sortierschlüssel bestimmt, welches Feld oder welcher Wert die Reihenfolge vorgibt.
  • Stabilität erhält die Reihenfolge von Datensätzen mit gleichen Schlüsseln.
  • Ein Sortierverfahren, das innerhalb der Liste arbeitet, benötigt nur eine feste Menge zusätzlichen Arbeitsspeichers.
  • Eine Inversion ist ein falsch angeordnetes Paar, auch wenn die Elemente keine Nachbarn sind.

2.2 Vollziehe Bubblesort nach und zähle die Rechenschritte

Bubblesort vergleicht benachbarte Elemente von links nach rechts. Ist das linke Element größer, vertauscht es das Paar. Jeder Gang durch die Liste ist ein Durchlauf. Ein großes Element kann während eines Durchlaufs wiederholt nach rechts wandern, bis das größte verbliebene Element seine endgültige Position erreicht.

Den ersten Durchlauf verfolgen

Beginne mit [5, 1, 4, 2, 8]:

  1. Vergleiche 5 und 1; vertausche sie zu [1, 5, 4, 2, 8].
  2. Vergleiche 5 und 4; vertausche sie zu [1, 4, 5, 2, 8].
  3. Vergleiche 5 und 2; vertausche sie zu [1, 4, 2, 5, 8].
  4. Vergleiche 5 und 8; lass sie unverändert.

Der Durchlauf führt vier Vergleiche und drei Vertauschungen aus. Das größte Element, 8, steht fest. Der Rest ist noch unsortiert: 4 steht vor 2. Ein Durchlauf garantiert die endgültige Position des Maximums, nicht die Reihenfolge aller Elemente.

Durchlauf 2 benötigt nur die ersten vier Positionen. Vergleiche 1 mit 4, vertausche dann 4 mit 2 und vergleiche anschließend 4 mit 5. Das ergibt nach drei weiteren Vergleichen und einer Vertauschung [1, 2, 4, 5, 8]. Durchlauf 3 vergleicht 1 mit 2 und 2 mit 4. Er nimmt keine Vertauschung vor und bestätigt damit, dass die Liste sortiert ist. Insgesamt: neun Vergleiche und vier Vertauschungen.

Jeden Durchlauf verkürzen und vorzeitig abbrechen
def bubble_sort(items):
    n = len(items)
    for p in range(n - 1):
        swapped = False
        for j in range(n - 1 - p):
            if items[j] > items[j + 1]:
                items[j], items[j + 1] = items[j + 1], items[j]
                swapped = True
        if not swapped:
            break

Die Durchlaufzählvariable p beginnt bei null. Der größte Wert von j ist n - 2 - p, sodass j + 1 innerhalb des unsortierten Teils bleibt. Setze swapped zu Beginn jedes Durchlaufs zurück; eine Vertauschung in einem früheren Durchlauf sagt nichts darüber aus, ob der aktuelle Durchlauf ein Element bewegt hat.

Nach jedem Durchlauf steht eine weitere Position rechts endgültig fest. Ein Durchlauf ohne Vertauschungen beweist, dass alle verglichenen Nachbarn geordnet sind. Auch das bereits feststehende Suffix ist geordnet, sodass der Algorithmus anhalten kann. Der bestätigende Durchlauf zählt dennoch zum Aufwand.

Besten und schlechtesten Fall vergleichen

Bei einer sortierten, nicht leeren Liste führt die Version mit vorzeitigem Abbruch n−1 Vergleiche und null Vertauschungen aus. Bei einer umgekehrt sortierten Liste verschiedener Elemente führt sie

(n−1)+(n−2)+⋯+1=n(n−1)2

Vergleiche und ebenso viele Vertauschungen aus. Fünf Elemente benötigen 10; 1.000 Elemente benötigen 499.500. Ohne vorzeitigen Abbruch würde das durchgerechnete Beispiel mit fünf Elementen auch den letzten Durchlauf mit einem Vergleich ausführen und auf 10 Vergleiche kommen.

Jede Vertauschung beseitigt genau eine Inversion. Die vier Inversionen der ursprünglichen Beispielliste erklären ihre vier Vertauschungen. Gleiche Nachbarn bleiben an ihrem Platz, weil die Prüfung > verwendet. Dadurch ist diese Version stabil und arbeitet innerhalb der Liste. Ersetzt du > durch >=, kann sich die Reihenfolge von Datensätzen mit gleichen Schlüsseln umkehren.

Die Position ist auch bei wenigen Inversionen wichtig. [5, 1, 2, 3, 4] benötigt vier Vertauschungen und einen zweiten Durchlauf zur Bestätigung der Reihenfolge, also sieben Vergleiche. [2, 3, 4, 5, 1] benötigt ebenfalls vier Vertauschungen, aber seine 1 kann pro Durchlauf nur einmal nach links wandern. Es benötigt alle vier Durchläufe und 10 Vergleiche.

Wichtige Erkenntnisse

  • Jeder Durchlauf platziert das größte verbliebene Element endgültig rechts.
  • Ein Durchlauf ohne Vertauschungen erlaubt einen vorzeitigen Abbruch.
  • Zähle den Durchlauf, der die Reihenfolge bestätigt, auch wenn er keine Vertauschungen vornimmt.
  • Im schlechtesten Fall gibt es n(n−1)/2 Vergleiche; eine sortierte Eingabe benötigt n−1.
  • Werden nur echt falsch angeordnete Nachbarn vertauscht, bleibt die Stabilität erhalten.
  • Die Anzahl der Vertauschungen entspricht der Anzahl der Inversionen in der Eingabe.

2.3 Vollziehe Selectionsort nach und zähle die Rechenschritte

Selectionsort baut links ein sortiertes Präfix auf. Jeder Durchlauf findet das kleinste Element im verbliebenen Suffix und tauscht es dann an die nächste Position des Präfixes. Die Suche findet die Position; die Vertauschung erfolgt nach der Suche.

Einen Index merken

Beginne an Position i mit smallest = i. Vergleiche jedes spätere Element mit items[smallest]. Aktualisiere smallest nur, wenn ein kleineres Element auftaucht. Tausche nach dem Ende der Suche items[i] und items[smallest] aus.

def selection_sort(items):
    n = len(items)
    for i in range(n - 1):
        smallest = i
        for j in range(i + 1, n):
            if items[j] < items[smallest]:
                smallest = j
        if smallest != i:
            items[i], items[smallest] = items[smallest], items[i]

Würdest du dir nur den kleinsten Wert merken, fehlte dir seine Position für den Austausch. Ein Suchbeginn bei Index 0 würde bereits platzierte Elemente erneut besuchen; die Suche im verbliebenen Teil beginnt unmittelbar nach i.

Die Durchläufe nachvollziehen

Beginne mit [29, 10, 14, 37, 13].

DurchlaufVerbliebenes MinimumListe nach dem PlatzierenVergleicheBewegende Vertauschungen
110[10, 29, 14, 37, 13]41
213[10, 13, 14, 37, 29]31
314[10, 13, 14, 37, 29]20
429[10, 13, 14, 29, 37]11

Das dritte Minimum steht bereits an seiner Position, sodass keine Werte bewegt werden. Nach vier Durchläufen muss das letzte Element das größte sein; es benötigt keinen eigenen Durchlauf. Es gibt 10 Vergleiche und drei Vertauschungen, die Elemente bewegen. Die Bedingung im Code überspringt den Austausch einer Position mit sich selbst; ohne diese Bedingung bleibt das Ergebnis unverändert.

Vergleiche und Vertauschungen haben unterschiedliche Kosten

Selectionsort führt immer n(n−1)/2 Elementvergleiche aus: Jeder Durchlauf muss das gesamte verbliebene Suffix prüfen, um dessen Minimum zu bestimmen. Insgesamt sind es 10 bei fünf Elementen oder 499.500 bei 1.000, selbst bei bereits sortierter Eingabe. Eine Suche, die den gemerkten Index nicht ändert, bestimmt das Minimum dieses Durchlaufs, garantiert aber nicht allgemein, dass das verbliebene Suffix geordnet ist.

Bei einer nicht leeren Liste gibt es pro Durchlauf höchstens eine Vertauschung, die Elemente bewegt, also insgesamt höchstens n−1. Eine leere Eingabe benötigt keine Durchläufe oder Vertauschungen. Bubblesort kann bei einer umgekehrt sortierten Liste verschiedener Elemente n(n−1)/2 Vertauschungen benötigen. Kostet das Verschieben großer Datensätze viel mehr als der Vergleich ihrer Schlüssel, kann die geringe Anzahl von Vertauschungen bei Selectionsort trotz der vielen Vergleiche wichtig sein. Wer bei jedem neuen Minimum während der Suche vertauscht, verliert diesen Vorteil.

Gleiche Schlüssel können ihre Reihenfolge ändern

Dieses Verfahren mit Vertauschungen arbeitet innerhalb der Liste, ist aber instabil. Bezeichne Datensätze mit gleichen Schlüsseln als 4a und 4b, damit ihre Identität sichtbar ist. Ausgehend von [4a, 4b, 1] tauscht der erste Durchlauf 4a und 1 aus und erzeugt [1, 4b, 4a]. Die gleichen Schlüssel haben ihre ursprüngliche Reihenfolge umgekehrt, obwohl der Algorithmus sie nie direkt als ungleich verglichen hat. Auch wenn während einer Suche das erste gefundene Minimum beibehalten wird, kann eine Vertauschung über größere Distanz einen Datensatz mit gleichem Schlüssel überholen.

Wichtige Erkenntnisse

  • Selectionsort sucht ein Minimum und vertauscht dann einmal nach der Suche.
  • Nach jedem Durchlauf wächst das sortierte Präfix um ein Element.
  • Die Anzahl seiner Vergleiche beträgt immer n(n−1)/2.
  • Bei nicht leerer Eingabe benötigt es höchstens n−1 Vertauschungen, die Elemente bewegen, und eine feste Menge zusätzlichen Speichers.
  • Die übliche Version mit Vertauschungen über größere Distanzen ist instabil.
3

Sortiere schneller mit Mergesort

Eine große Liste durch wiederholtes vollständiges Durchsuchen zu sortieren wird aufwendig. Mergesort verfolgt einen anderen Plan: Es teilt die Liste in kleinere Teile, sortiert diese und führt ihre Ergebnisse zusammen. Lerne zunächst, warum sich zwei sortierte Listen verschmelzen lassen, indem man nur ihre Kopfelemente betrachtet. Verfolge dann das rekursive Teilen und Verschmelzen und beachte den Aufwand auf jeder Ebene sowie den zusätzlichen Speicher für die Ausgabe.

3.1 Verschmelze zwei sortierte Listen zu einer Liste

Das Verschmelzen führt zwei bereits sortierte Listen zu einer sortierten Ausgabe zusammen. Setze einen Laufindex auf das erste noch nicht verwendete Element jeder Eingabe. Vergleiche diese beiden Kopfelemente, kopiere das kleinere und bewege nur dessen Laufindex weiter.

Das nächste kleinste Element wählen

Verschmelze [3, 27, 38, 43] mit [9, 10, 82]:

Vergleich der KopfelementeIn die Ausgabe kopierenBisherige Ausgabe
3 und 93[3]
27 und 99[3, 9]
27 und 1010[3, 9, 10]
27 und 8227[3, 9, 10, 27]
38 und 8238[3, 9, 10, 27, 38]
43 und 8243[3, 9, 10, 27, 38, 43]

Die linke Liste ist nun aufgebraucht. Kopiere die verbliebene 82 ohne weiteren Elementvergleich. Das Ergebnis ist [3, 9, 10, 27, 38, 43, 82] und benötigt sechs Vergleiche. Das Kopieren der Restliste gehört zum Algorithmus: Wer aufhört, sobald die Vergleiche enden, verliert Daten.

Warum kann das Verfahren Elemente hinter den Kopfelementen ignorieren? Jedes Kopfelement ist das kleinste verbliebene Element seiner Liste. Das kleinere Kopfelement ist daher insgesamt das kleinste verbliebene Element. Diese Überlegung gilt auch nach jeder Bewegung eines Laufindex, weil die nicht verwendeten Teile sortiert bleiben.

Den Code zum Verschmelzen lesen
def merge(left, right):
    result = []
    i = j = 0
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1
    result.extend(left[i:])
    result.extend(right[j:])
    return result

append fügt ein Element hinzu. Ein Ausschnitt wie left[i:] enthält die nicht verwendete Restliste und extend kopiert deren Elemente. Wenn die Schleife endet, kann höchstens eine nicht verwendete Restliste nicht leer sein. Ist eine Eingabe zu Beginn leer, führt die Schleife null Vergleiche aus und die andere Liste wird vollständig kopiert.

Vergleiche und Speicher zählen

Für zwei nicht leere Listen der Längen m und k sind höchstens m+k−1 Vergleiche der Kopfelemente nötig. Jeder Vergleich platziert ein Element und mindestens das letzte Element kann ohne Vergleich kopiert werden. Die kleinstmögliche Anzahl von Vergleichen beim Verschmelzen entspricht der Länge der kürzeren Liste: Das Verschmelzen von [1, 2, 3] mit [4, 5, 6] benötigt drei Vergleiche, bevor die linke Seite aufgebraucht ist.

Der gesamte Kopieraufwand wächst mit m+k, selbst wenn die Vergleiche früh enden, weil jedes Element in der Ausgabe erscheinen muss. Die neue Liste benötigt außerdem Platz für m+k Elemente. Vergleichsanzahl, Kopieraufwand und zusätzlicher Speicher messen verschiedene Teile desselben Vorgangs.

Gleiche Schlüssel und Eingabereihenfolge behandeln

Die Prüfung <= nimmt bei gleichen Schlüsseln das Element von links. Stammen die beiden Eingaben aus aufeinanderfolgenden Teilen einer ursprünglichen Liste, bleibt dadurch der frühere Datensatz vor dem späteren mit gleichem Schlüssel. Diese Regel für gleiche Schlüssel ist für stabiles Mergesort nötig.

Die Voraussetzung sortierter Eingaben ist unverzichtbar. Das Verschmelzen von [5, 1] mit [3] kopiert 3 und dann die Restliste [5, 1] und erzeugt [3, 5, 1]. Die Regel für Kopfelemente schlug fehl, weil 5 nicht der kleinste verbliebene Wert seiner Eingabe war.

Wichtige Erkenntnisse

  • Das Verschmelzen vergleicht die ersten nicht verwendeten Elemente zweier sortierter Eingaben.
  • Kopiere die nicht verwendete Restliste, wenn eine Seite aufgebraucht ist.
  • Zwei nicht leere Eingaben benötigen höchstens m+k−1 Vergleiche der Kopfelemente.
  • Bei gleichen Schlüsseln erhält die Wahl des linken Elements die Reihenfolge über die beiden Hälften hinweg.

3.2 Vollziehe Mergesort nach und erkläre, warum der Aufwand mit n log n wächst

Mergesort löst eine große Sortieraufgabe, indem es sie in kleinere Sortieraufgaben zerlegt. Das ist das Prinzip Teile und herrsche: Teile die Liste, sortiere jede Hälfte und verschmelze die sortierten Hälften.

Das Teilen beim Basisfall beenden

Eine Funktion ist rekursiv, wenn sie sich selbst aufruft. Mergesort ruft sich selbst für kürzere Listen auf. Sein Basisfall gibt eine Liste mit null oder einem Element unverändert zurück, da eine solche Liste bereits sortiert ist.

def merge_sort(items):
    if len(items) <= 1:
        return items
    mid = len(items) // 2
    left = merge_sort(items[:mid])
    right = merge_sort(items[mid:])
    return merge(left, right)

Die Ausschnitte teilen die Eingabe, ohne Elemente zu verlieren. Bei einer ungeraden Länge hat die rechte Seite ein Element mehr: [6, 2, 9, 4, 1, 7, 3] wird in [6, 2, 9] und [4, 1, 7, 3] geteilt. Beide Hälften sind kürzer, sodass die rekursiven Aufrufe schließlich den Basisfall erreichen. Ein Basisfall allein würde die Terminierung nicht sicherstellen, wenn ein Aufruf sich selbst immer wieder die ursprüngliche Liste übergäbe.

Die sortierte Liste wieder zusammensetzen

Vollziehe [38, 27, 43, 3, 9, 82, 10, 15] nach. Die Liste wird in zwei Hälften mit je vier Elementen geteilt, dann in vier Teile mit je zwei Elementen und schließlich in einzelne Elemente. Das Teilen ordnet die Werte nicht um. Die Ordnung entsteht beim Verschmelzen:

  1. Verschmelze einzelne Elemente zu [27, 38], [3, 43], [9, 82] und [10, 15]. Jedes Verschmelzen benötigt einen Vergleich: insgesamt vier.
  2. Verschmelze die Paare zu [3, 27, 38, 43] und [9, 10, 15, 82]. Jedes Verschmelzen benötigt drei Vergleiche: insgesamt sechs.
  3. Verschmelze diese Hälften zu [3, 9, 10, 15, 27, 38, 43, 82]. Das benötigt sieben Vergleiche.

Die vollständige Sortierung benötigt 4+6+7=17 Elementvergleiche. Zähle nicht nur das abschließende Verschmelzen: Die sortierten Hälften mussten zuerst erzeugt werden. Das obige Beispiel mit sieben Elementen wird nach dieser Teilungsregel mit 14 Vergleichen zu [1, 2, 3, 4, 6, 7, 9] sortiert.

Ebenen und Aufwand pro Ebene zählen

Bei acht Elementen entstehen nach drei Ebenen des Halbierens einzelne Elemente, denn 23=8. Allgemein gibt es etwa log⁡2n Verschmelzungsebenen. Auf einer vollständigen Ebene bearbeiten die Verschmelzungsvorgänge zusammen alle n Elemente. Jede Ebene leistet daher einen zu n proportionalen Aufwand, was zu einem Wachstum wie nlog⁡2n führt.

Bei acht Elementen ist nlog⁡2n=24 eine nützliche, grobe Schranke für die Vergleiche, nicht die genaue Anzahl. Die durchgerechnete Liste benötigte 17; eine bereits sortierte oder umgekehrt sortierte Liste mit acht Elementen benötigt 12. Die Eingabereihenfolge beeinflusst, wann beim Verschmelzen eine Seite aufgebraucht ist, aber jede Liste durchläuft weiterhin die Ebenen des Teilens und Verschmelzens. Bei dieser Version wächst die Anzahl der Vergleiche im besten wie im schlechtesten Fall weiterhin wie nlog⁡n.

Bei einer Million Elementen ergeben etwa 20 Ebenen als grobe obere Schätzung etwa 20 Millionen Vergleiche. Selectionsort benötigt etwa 500 Milliarden. Der Unterschied wächst mit der Eingabegröße schnell.

Den zusätzlichen Speicher für die Ausgabe einplanen

Das übliche listenbasierte Mergesort benötigt zusätzlichen Speicher proportional zu n. Die Wahl des linken Kopfelements bei gleichen Schlüsseln macht es stabil.

Wichtige Erkenntnisse

  • Mergesort sortiert rekursiv zwei kürzere Hälften und verschmilzt sie dann.
  • Listen mit null oder einem Element bilden den Basisfall.
  • Ungerade Längen werden in Hälften geteilt, die sich um ein Element unterscheiden.
  • Auf etwa log⁡2n Ebenen entsteht jeweils ein zu n proportionaler Aufwand.
  • Die genaue Anzahl der Vergleiche hängt von der Reihenfolge ab; die Wachstumsfamilie ist nlog⁡n.
  • Die übliche Version ist stabil, wenn bei gleichen Schlüsseln links zuerst gewählt wird, und benötigt proportionalen zusätzlichen Speicher.
4

Zähle Rechenschritte und vergleiche das Wachstum der Laufzeiten

Eine Stoppuhr zeigt, wie ein Programm bei einer Ausführung lief; eine Schrittzahl hilft zu erklären, was bei wachsender Eingabe geschieht. Wähle eine Operation zum Zählen, fasse wiederholte Arbeit in einer Formel zusammen und vergleiche Wachstumsmuster vom einzelnen Zugriff bis zum Ausprobieren jeder Auswahl. Nutze diese Muster, um Laufzeiten und Zeitbudgets abzuschätzen, und plane anschließend Messungen, mit denen sich die Prognosen an tatsächlichen Ausführungen prüfen lassen.

4.1 Zähle die Rechenschritte eines Algorithmus

Eine gemessene Laufzeit hängt vom Rechner und vom Programm ab. Eine Schrittzahl beschreibt den Aufwand des Algorithmus anhand einer gewählten wiederholten Operation. Die Eingabegröße, geschrieben n, ist die Anzahl der bearbeiteten Elemente.

Die Operation vor dem Zählen wählen

Beim Suchen und Sortieren sind Vergleiche zwischen Elementwerten meist eine sinnvolle Elementaroperation. Zähle Vertauschungen getrennt, wenn das Verschieben von Daten wichtig ist. Bei der binären Suche ist es zweckmäßig, Prüfungen eines mittleren Elements zu zählen. In der Python-Version prüft eine erfolglose Prüfung des mittleren Elements sowohl auf Gleichheit als auch darauf, ob es kleiner ist, und kann daher zwei Elementvergleiche umfassen.

VerfahrenZähleinheitAnzahl im schlechtesten Fall
Lineare SucheVergleiche eines Elements mit dem Suchwertn
Binäre Suche, nicht leere EingabePrüfungen eines mittleren Elements⌊log⁡2n⌋+1
BubblesortVergleiche benachbarter Elementen(n−1)/2
SelectionsortSchlüsselvergleichen(n−1)/2
MergesortVergleiche von KopfelementenHöchstens etwa nlog⁡2n

Diese Zahlen beschreiben wiederholte Operationen, keine Codezeilen. Eine Zeile innerhalb einer Schleife kann eine Million Mal ausgeführt werden; mehrere vorbereitende Zeilen werden möglicherweise jeweils einmal ausgeführt.

Fälle bei gleicher Größe unterscheiden

Der beste Fall benötigt unter den zulässigen Eingaben der Größe n die wenigsten Schritte. Der schlechteste Fall benötigt die meisten und bietet eine Garantie. Der durchschnittliche Fall bildet den Durchschnitt über eine angegebene Verteilung von Eingaben.

Bei einer nicht leeren Liste benötigt die lineare Suche einen Vergleich, wenn der Suchwert am Anfang steht, und n, wenn er am Ende steht oder fehlt. Der Durchschnitt für erfolgreiche Suchen beträgt (n+1)/2, wenn die erste Trefferposition mit gleicher Wahrscheinlichkeit jede Position sein kann. Der Begriff „Durchschnitt“ setzt diese Verteilung voraus; er bezeichnet nicht bei jedem Algorithmus die Mitte zwischen der besten und der schlechtesten Schrittzahl.

Schleifen in Schrittzahlen übersetzen

Ein Vergleich pro Element bei einem vollständigen Durchlauf ergibt n Vergleiche. Zwei vollständig verschachtelte Schleifen, die jeweils n Mal laufen, führen ihren gemeinsamen Rumpf n2 Mal aus. Ein anderes Muster verschachtelter Schleifen vergleicht jedes Paar nur einmal:

for i in range(n):
    for j in range(i + 1, n):
        compare(items[i], items[j])

Die erste Wiederholung der äußeren Schleife vergleicht ihr Element mit n−1 späteren Elementen. Die nächste vergleicht mit n−2 und die letzte mit keinem. Insgesamt ergibt sich

1+2+⋯+(n−1)=n(n−1)2.

Schreibe die Summe vorwärts und rückwärts auf. Jedes untereinanderstehende Paar ergibt zusammen n und es gibt n−1 solche Paare. Ihre Summe ist n(n−1), also das Doppelte der ursprünglichen Summe. Für fünf Elemente gilt 4+3+2+1=10; für 1.000 beträgt die Anzahl der Paare 499.500.

Wiederholtes Halbieren erkennen

Eine Schleife, die ihre verbleibende Arbeit halbiert, benötigt etwa log⁡2n Wiederholungen. Eine Million fällt nach 20 Halbierungen erstmals auf 1 oder weniger: 219=524.288 und 220=1.048.576 liegen unter beziehungsweise über einer Million. Das unterscheidet sich stark davon, jedes Mal nur ein Element zu entfernen.

Behalte für Wachstumsvergleiche den am schnellsten wachsenden Term. Die Anzahl der Paare ist n2/2−n/2. Bei n=1.000 betragen ihre Terme 500.000 und 500, sodass der quadratische Term das Wachstum bestimmt. Das Weglassen des kleineren Terms und des konstanten Faktors beschreibt die Wachstumsfamilie; es macht aus der genauen Anzahl von 499.500 keine genaue Anzahl von einer Million.

Wichtige Erkenntnisse

  • Benenne die gezählte Operation und drücke ihre Anzahl mithilfe der Eingabegröße aus.
  • Schrittzahlen im schlechtesten Fall bieten Garantien; Durchschnittswerte hängen von einer Eingabeverteilung ab.
  • Vollständige verschachtelte Durchläufe ergeben n2 Ausführungen des Schleifenrumpfs.
  • Wird jedes Paar verschiedener Elemente einmal verglichen, ergeben sich n(n−1)/2 Vergleiche.
  • Wiederholtes Halbieren erzeugt logarithmisches Wachstum.

4.2 Vergleiche, wie die Anzahl der Rechenschritte mit der Eingabegröße wächst

Eine Wachstumsrate beschreibt, wie sich der Aufwand bei größerer Eingabe verändert. Sie hilft, Algorithmen über die konkrete Größe eines einzelnen Ablaufs hinaus zu vergleichen.

Die üblichen Familien lesen
WachstumsfamilieBeispielWirkung einer Verdopplung der Eingabegröße
Konstant, 1Eine bekannte Array-Position lesenGleicher Aufwand
Logarithmisch, log⁡2nBinäre SucheEtwa eine zusätzliche Prüfung
Linear, nVollständiger DurchlaufDoppelter Aufwand
nlog⁡nMergesortEtwas mehr als das Doppelte
Quadratisch, n2SelectionsortEtwa das Vierfache
Exponentiell, 2nJede Auswahl von Elementen ausprobierenQuadriert die Anzahl

Bei exponentiellem Wachstum verdoppelt bereits ein zusätzliches Element die Anzahl: 2n+1=2×2n. Eine Verdopplung der Eingabe ist eine viel größere Änderung als das Hinzufügen eines Elements.

Größen anhand von Zahlen vergleichen

Für Eingaben mit 10, 100, 1.000 und einer Million Elementen beträgt log⁡2n etwa 3,3, 6,6, 10 und 20. Die entsprechenden Werte von nlog⁡2n betragen etwa 33, 664, 9.966 und 20 Millionen. Die quadratischen Werte sind 100, 10.000, eine Million und eine Billion.

Logarithmisches Wachstum ist nicht „die halbe Liste“. Bei einer Million Elementen benötigt wiederholtes Halbieren nur etwa 20 Stufen. Steigt die Eingabe von 1.000 auf 2.000, steigt nlog⁡2n von etwa 9.966 auf 21.932, also um den Faktor etwa 2,2. Auch der Logarithmus ändert sich, sodass die Anzahl etwas schneller als linear wächst.

Exponentieller Aufwand wird schnell groß. 210=1.024 und 220 ist etwa eine Million. Bei einer Milliarde Schritten pro Sekunde dauern 250 Schritte immer noch etwa 13 Tage. Ein weiteres Element verdoppelt diese Zeit.

Informelle O-Schreibweisen verwenden

Programmierer bezeichnen diese Familien üblicherweise mit O(1), O(log⁡n), O(n), O(nlog⁡n), O(n2) und O(2n). Hier bezeichnen sie die übliche Wachstumsfamilie im schlechtesten Fall. Lies O(n2) als „in der Größenordnung n Quadrat“. Die Schreibweise lässt konstante Faktoren und Terme niedrigerer Ordnung weg: n(n−1)/2 Vergleiche gehören zur quadratischen Familie.

Eine O-Schreibweise ist weder eine genaue Laufzeit noch eine Anzahl von Sekunden. Sie behauptet auch nicht, dass jede Eingabe die Schrittzahl des schlechtesten Falls benötigt. Bubblesort mit vorzeitigem Abbruch hat einen linearen besten, aber einen quadratischen schlechtesten Fall.

Den Schnittpunkt finden

Angenommen, Verfahren A benötigt 100n Schritte und Verfahren B benötigt n2. Bei 50 Elementen benötigt A 5.000 Schritte und B 2.500. Bei 100 benötigen beide 10.000. Bei 1.000 benötigt A 100.000 und B eine Million. Das langsamere Wachstum von A überwiegt schließlich seinen größeren konstanten Faktor.

Die Hardwaregeschwindigkeit verändert die absoluten Werte, ohne die Wachstumsfamilie zu ändern. Ein 100-mal schnellerer Computer erlaubt einem quadratischen Verfahren, in derselben Zeit nur 10-mal so viele Elemente zu bearbeiten, denn (10n)2=100n2. Ein lineares Verfahren könnte 100-mal so viele bearbeiten. Bei einer kleinen Aufgabe können Vorbereitung und Konstanten dominieren; bei großen Eingaben wird das Wachstum entscheidend.

Wichtige Erkenntnisse

  • Eine Verdopplung der Eingabe verdoppelt den linearen Aufwand ungefähr und vervierfacht den quadratischen.
  • Logarithmischer Aufwand steigt bei Verdopplung der Eingabe um etwa einen Schritt.
  • Mergesort verbindet linearen Aufwand pro Ebene mit einer logarithmischen Anzahl von Ebenen.
  • Ein zusätzliches Element verdoppelt eine Schrittzahl von 2n.
  • Wachstumsbezeichnungen lassen Konstanten weg; bei kleinen Eingaben bestimmen die tatsächlichen Schrittzahlen die Schnittpunkte.

4.3 Schätze Laufzeiten ab und miss sie

Eine bekannte Laufzeit und ein Wachstumsmuster ermöglichen eine Prognose für eine größere Aufgabe. Die Prognose ist eine Schätzung, weil die tatsächliche Zeit auch von Implementierung, Speicher, Hardware und anderen Aufgaben des Rechners abhängt.

Erst die Eingabe, dann die Zeit skalieren

Multipliziere bei linearem Aufwand die Zeit mit dem Verhältnis der Eingabegrößen. Dauert eine Suche über eine Million Elemente im schlechtesten Fall 3 Millisekunden, benötigen zehn Millionen Elemente unter vergleichbaren Bedingungen etwa 30 Millisekunden.

Quadriere bei quadratischem Aufwand das Verhältnis. Angenommen, Selectionsort benötigt 2 Sekunden für 50.000 Elemente. Die Verdopplung auf 100.000 Elemente ergibt

2×(100.00050.000)2=2×4=8

Sekunden. Eine Erhöhung auf 500.000 Elemente multipliziert die Eingabegröße mit 10, sodass die Zeitschätzung 2×102=200 Sekunden beträgt. Würdest du die Zeit mit 10 multiplizieren, würdest du den Algorithmus fälschlich als linear behandeln.

Verwende bei Wachstum der Größenordnung nlog⁡2n das Verhältnis der beiden vollständigen Ausdrücke. Die Verdopplung einer großen Eingabe kostet etwas mehr als das Doppelte, weil der Logarithmus zusammen mit der Elementzahl steigt.

Von einem Zeitbudget rückwärts rechnen

Nutze dieselbe quadratische Referenzlaufzeit: 2 Sekunden für 50.000 Elemente. Ein Budget von 32 Sekunden erlaubt das 16-Fache der Zeit. Die Eingabe kann um die Quadratwurzel aus 16 wachsen, also um den Faktor 4. Das ergibt etwa 200.000 Elemente. Prüfe die Richtung durch Einsetzen: Die vierfache Eingabe sagt die 16-fache Zeit voraus, also einen Anstieg von 2 auf 32 Sekunden.

Algorithmen bei großer Eingabe vergleichen

Bei einer Million Elementen führt Selectionsort 499.999.500.000 Vergleiche aus, etwa 500 Milliarden. Mergesort benötigt höchstens etwa 20 Millionen. Bei einer angenommenen Milliarde Vergleichen pro Sekunde entsprechen diese Zahlen etwa 500 Sekunden gegenüber 0,02 Sekunden, einem Unterschied um etwa den Faktor 25.000. Diese Rechnung nimmt gleiche Kosten pro Vergleich an, um die Wirkung des Algorithmus für sich zu betrachten; gemessene Programme benötigen auch Zeit für Verschiebungen und Speicherzugriffe.

Eine Wachstumsprognose prüfen

Miss dasselbe Programm bei mehreren Größen, die sich jeweils verdoppeln, etwa 10.000, 20.000 und 40.000 Elementen. Dividiere jede Zeit durch die vorherige. Verhältnisse nahe 2 deuten auf lineares Wachstum hin; etwas über 2 deutet auf nlog⁡n hin; nahe 4 deutet auf quadratisches Wachstum hin.

Halte Rechner und Messmethode gleich. Wiederhole die Durchläufe und verwende ausreichend große Eingaben, damit die Startzeit nicht dominiert. Vergleiche gleichartige Fälle: Eine Suche an der ersten Position bei einer Größe und eine erfolglose Suche bei einer anderen würden Eingabeeffekte mit dem Wachstum vermischen. Bei Bubblesort brauchen sortierte und umgekehrt sortierte Listen unterschiedliche Fallbezeichnungen.

Ergeben sich bei den sich verdoppelnden Größen 0,04, 0,16 und 0,64 Sekunden, sind beide Verhältnisse 4. Das stützt in diesem Bereich ein quadratisches Modell. Ein einzelnes schwankendes Verhältnis ist ein schwächerer Beleg als ein wiederkehrendes Muster. Schrittzahlen für einen bestimmten Ablauf können exakt sein; eine Prognose in Sekunden sollte „etwa“ enthalten und anhand von Messungen geprüft werden.

Wichtige Erkenntnisse

  • Lineare Zeit wächst mit dem Eingabeverhältnis, quadratische Zeit mit dessen Quadrat.
  • Berechne bei einem quadratischen Zeitbudget mit einer Quadratwurzel das Eingabeverhältnis.
  • Miss mehrere Größen mit vergleichbaren Eingabefällen und wiederholten Durchläufen.
  • Zeitverhältnisse deuten auf Wachstumsmuster hin; prognostizierte Sekunden bleiben Schätzungen.
5

Begründe die Korrektheit und wähle den passenden Algorithmus

Ein schneller Ablauf an einer Liste lässt zwei Fragen offen: Funktioniert der Algorithmus immer und passt er zu dieser Aufgabe? Beschreibe, was eine zulässige Eingabe und eine korrekte Ausgabe bedeuten, erkläre mithilfe einer Schleifeninvariante, warum das Verfahren seinen Fortschritt erhält, und zeige, warum es anhält. Wähle dann Tests, die Fehler an den Rändern aufdecken, und vergleiche Algorithmen anhand der tatsächlichen Anforderungen der Aufgabe an Zeit, Speicher, Stabilität und Datenzugriff.

5.1 Begründe, warum ein Algorithmus korrekt ist

Ein korrekter Algorithmus hält bei jeder zulässigen Eingabe an und erzeugt die geforderte Ausgabe. Eine Spezifikation nennt die Eingabebedingung und das zugesicherte Ergebnis. Bei der binären Suche ist die Vorbedingung die aufsteigend sortierte Reihenfolge. Die Nachbedingung ist ein passender Index oder genau dann -1, wenn der Suchwert fehlt.

Schritte durch eine Invariante verbinden

Eine Schleifeninvariante ist eine Aussage, die vor Beginn der Schleife gilt und bei jeder Wiederholung erhalten bleibt. Ein Korrektheitsargument prüft, ob sie zu Beginn gilt, erhalten bleibt und was sie beim Ende der Schleife aussagt. Ein separates Terminierungsargument zeigt, dass die Schleife schließlich endet.

Verwende für Selectionsort diese Invariante: Vor Durchlauf i enthalten die ersten i Positionen die i kleinsten Elemente in Reihenfolge.

  1. Beginn: Vor Durchlauf 0 ist das Präfix leer. Es erfüllt die Aussage bereits.
  2. Erhaltung: Der Durchlauf findet das kleinste verbliebene Element. Es als Nächstes zu platzieren erweitert das sortierte Präfix um eins; das Element ist mindestens so groß wie jedes zuvor platzierte Element.
  3. Ende: Nach höchstens n−1 Durchläufen bleibt nur das größte Element außerhalb des Präfixes. Die ganze Liste ist sortiert.

Jede Bewegung ist eine Vertauschung, sodass auch die Multimenge der Elemente unverändert bleibt. Eine geordnete Ausgabe allein würde die vollständige Sortierspezifikation nicht erfüllen.

Bubblesort nutzt eine Suffixinvariante: Nach k Durchläufen enthalten die letzten k Positionen die k größten Elemente in Reihenfolge. Der nächste Durchlauf bringt das größte unsortierte Element zu diesem Suffix. Ein Durchlauf ohne Vertauschungen stellt die Ordnung im gesamten verbliebenen Teil fest und erlaubt einen vorzeitigen Abbruch.

Ausgeschlossene Bereiche bei der binären Suche erklären

Verwende die Invariante: Kommt der Suchwert vor, liegt mindestens ein Vorkommen im Bereich von low bis high, einschließlich der Endpunkte. Anfangs umfasst dieser Bereich die ganze Liste. Ist der mittlere Wert zu klein, sind wegen der sortierten Reihenfolge alle Werte an mid und links davon zu klein. Das Setzen von low auf mid + 1 erhält jeden möglichen Treffer. Für die Aktualisierung auf high = mid - 1 gilt dieselbe Überlegung bei zu großen Werten.

Bei einem Treffer erfüllt die zurückgegebene Position unmittelbar die Nachbedingung. Wird das Suchintervall leer, schließt die Invariante einen Suchwert an jeder Stelle der Liste aus. Die Eingabe bleibt sortiert, weil die Suche sie nie verändert.

Zeigen, warum die Ausführung anhält

Eine abnehmende nicht negative ganzzahlige Größe beweist den Fortschritt zu einem Ende. Bei der binären Suche nimmt die Anzahl der infrage kommenden Positionen nach jedem Misserfolg strikt ab. Der geprüfte mittlere Index wird ausgeschlossen, sodass die Schleife nicht endlos denselben Bereich behalten kann. Bubblesort und Selectionsort führen bei nicht leerer Eingabe höchstens n−1 Durchläufe und bei leerer Eingabe keine Durchläufe aus.

Mergesort erreicht Listen mit null oder einem Element, weil jeder rekursive Aufruf eine kürzere Liste verwendet. Diese Basisfälle sind sortiert. Unter der Annahme, dass die kürzeren Aufrufe korrekt sortierte Hälften zurückgeben, nimmt das Verschmelzen wiederholt das kleinste verbliebene Element und erhält alle Elemente. So wird die Korrektheit bis zum ursprünglichen Aufruf zurückgetragen.

Tests für eine andere Aufgabe nutzen

Ein Test vergleicht ein tatsächliches mit einem erwarteten Ergebnis. Viele bestandene ausgewählte Tests stärken das Vertrauen, während eine einzige fehlschlagende zulässige Eingabe ein Gegenbeispiel ist, das die Korrektheit widerlegt. Ein allgemeines Invariantenargument deckt die unbegrenzte Familie möglicher Eingaben ab, die eine endliche Sammlung von Beispieltests ungeprüft lässt. Tests sind besonders nützlich, um zu prüfen, ob tatsächlicher Code das im Argument verwendete Verfahren implementiert.

Wichtige Erkenntnisse

  • Korrektheit verlangt für jede zulässige Eingabe das spezifizierte Ergebnis und Terminierung.
  • Eine Invariante muss zu Beginn gelten, jede Wiederholung überstehen und beim Verlassen der Schleife das Ergebnis begründen.
  • Ein Argument für eine Sortierung muss die Elemente erhalten und ihre Ordnung zeigen.
  • Eine strikt abnehmende nicht negative Größe begründet die Terminierung.
  • Eine einzige fehlschlagende zulässige Eingabe widerlegt die Korrektheit.

5.2 Teste Algorithmen anhand von Randfällen

Ein Randfall ist eine zulässige Eingabe nahe einem Rand, an dem Annahmen und Schleifengrenzen leicht falsch gewählt werden. Leite das erwartete Ergebnis vor der Ausführung des Codes aus der Spezifikation ab. Sonst kann eine fehlerhafte Programmausgabe unbemerkt zu deiner erwarteten Antwort werden.

Listen wählen, die Ränder prüfen

Teste leere Listen und Listen mit einem oder zwei Elementen; bereits sortierte und umgekehrt sortierte Listen; wiederholte und lauter gleiche Werte; negative Zahlen sowie ungerade und gerade Längen. Beziehe bei Suchen die erste und letzte Position sowie fehlende Suchwerte unterhalb, oberhalb und zwischen gespeicherten Werten ein.

Eine binäre Suche in einer leeren Liste sollte -1 zurückgeben, ohne auf ein Element zuzugreifen: low = 0 und high = -1 machen das anfängliche Suchintervall leer. Das Sortieren von [3, 3, 3] sollte drei Vorkommen von 3 zurückgeben. Eine Ausgabe von [3] wäre geordnet, würde aber die Elemente nicht erhalten.

Den kleinsten Fehlerfall nachvollziehen

Eine binäre Suche mit while low < high tritt bei [5] mit dem Suchwert 5 nicht in ihre Schleife ein. Die Korrektur lautet low <= high, da ein Intervall mit einer Position noch einen Kandidaten enthält. Dieser Test mit einem Element zeigt den Rand deutlicher als eine lange Liste.

Mit low = mid setzt die Suche nach 20 in [10, 20] den mittleren Index auf 0, sieht 10 und belässt low bei 0. Bei der nächsten Wiederholung ist das Suchintervall unverändert. Verwende low = mid + 1, um eine bereits geprüfte Position auszuschließen. Eine Liste mit zwei Elementen und dem Suchwert am Ende deckt diese Endlosschleife auf.

Bubblesort vergleicht items[j] mit items[j + 1]. Im ersten Durchlauf ist der letzte zulässige linke Index n - 2. Ein Fortsetzen bis n - 1 liest über die Liste hinaus und löst Pythons IndexError aus. Ein solcher Fehler um eine Position an einem Rand heißt Off-by-one-Fehler.

Beide Zusicherungen für die Ausgabe prüfen

Prüfe bei einer Sortierung die Reihenfolge benachbarter Elemente und die Anzahl jedes ursprünglichen Elements. Verwende gekennzeichnete Datensätze, um die Stabilität zu testen. Bei Ana 85, Ben 92, Cara 85 muss Ana vor Cara bleiben, wenn eine stabile Sortierung nach Punktzahl gleiche Punktzahlen gruppiert. Eine Prüfung nur der Punktzahlen würde eine Vertauschung dieser beiden Datensätze übersehen.

Erzeuge auch zufällige Listen. Vergleiche ihre Ergebnisse mit einer vertrauenswürdigen Implementierung wie Pythons sorted. Behalte Duplikate und verschiedene Längen in den erzeugten Eingaben bei. Schlägt ein Test fehl, verkleinere die Eingabe so, dass der Fehler erhalten bleibt, und vollziehe sie dann von Hand nach. Behalte das kleine Beispiel als Regressionstest, damit der behobene Fehler weiterhin erkennbar bleibt.

Den mittleren Index sicher berechnen

Pythons ganze Zahlen wachsen bei Bedarf, sodass (low + high) // 2 nicht überläuft. Manche Sprachen verwenden ganze Zahlen mit fester Bitbreite. Bei sehr großen nicht negativen Indizes kann ihre Summe den darstellbaren Bereich überschreiten. In Java springt das Ergebnis bei einem Ganzzahlüberlauf zurück; der Überlauf einer vorzeichenbehafteten ganzen Zahl in C ist undefiniertes Verhalten.

Berechne bei zulässigen Indizes und low <= high stattdessen low + (high - low) // 2. Die Differenz ist nicht negativ und das Ergebnis bleibt zwischen den Endpunkten. So wird derselbe abgerundete mittlere Index berechnet, ohne die möglicherweise überlaufende Summe zu bilden. Randwerttests und Überlegungen zur Zahlendarstellung der Sprache wirken hier zusammen.

Wichtige Erkenntnisse

  • Schreibe erwartete Ergebnisse vor der Ausführung von Tests auf.
  • Kleine Listen decken fehlende letzte Prüfungen, unveränderte Suchintervalle und ungültige Zugriffe auf Nachbarn auf.
  • Prüfe, ob Elemente erhalten bleiben und geordnet sind, sowie die Stabilität, wenn sie erforderlich ist.
  • Verkleinere zufällig gefundene Fehlerfälle und behalte sie als Regressionstests.
  • Die Berechnung des mittleren Index über die Differenz vermeidet Überlauf bei zulässigen nicht negativen Indizes fester Bitbreite.

5.3 Wähle einen zur Situation passenden Algorithmus

Ein Algorithmus passt zu einer Aufgabe, wenn seine Anforderungen und Kosten zu den Daten und der auszuführenden Arbeit passen. Berücksichtige die Eingabereihenfolge, den Zugriff auf Positionen, die Anzahl künftiger Operationen, zusätzlichen Speicher, Stabilität und die Kosten für das Verschieben von Datensätzen.

Die Verfahren vergleichen
VerfahrenZeit oder SchrittmusterZusätzlicher SpeicherStabil?
Lineare SucheBis zu n VergleicheFestKeine Sortiereigenschaft
Binäre SucheBis zu ⌊log⁡2n⌋+1 Prüfungen der MitteFestKeine Sortiereigenschaft
Bubblesort mit vorzeitigem Abbruchn−1 Vergleiche bei sortierter Eingabe; quadratischer schlechtester FallFestJa, bei Vertauschungen nur echt falsch geordneter Elemente
Selectionsortn(n−1)/2 Vergleiche; höchstens n−1 Vertauschungen, die Elemente bewegenFestNein, in der üblichen Form mit Vertauschungen
MergesortVergleichsanzahl wächst wie nlog⁡nProportional zu nJa, wenn bei gleichen Schlüsseln links zuerst gewählt wird

Die binäre Suche benötigt außerdem eine sortierte Reihenfolge und schnellen Zugriff auf die Mitte. Ein guter Vergleich bezieht diese Voraussetzungen ein; eine geringe Anzahl von Prüfungen allein lässt die Kosten für die Vorbereitung ungeeigneter Daten außer Acht.

Entscheiden, ob sich vorheriges Sortieren lohnt

Für eine Suche in einer Million unsortierter Elemente kostet die lineare Suche höchstens eine Million Vergleiche. Vorheriges Sortieren mit Mergesort kostet etwa 20 Millionen Vergleiche vor der ersten binären Suche, die dann höchstens 20 Prüfungen der Mitte benötigt. Die Vorbereitung übersteigt die Ersparnis bei dieser einen Suche bei Weitem.

Bei 100 Suchen in einer unveränderten Liste können wiederholte lineare Suchen 100 Millionen Vergleiche kosten. Einmaliges Sortieren und 100 binäre Suchen kosten etwa 20 Millionen Vergleiche plus 2.000 Prüfungen der Mitte. Die Vorbereitung wird wiederverwendet, wodurch der zweite Plan attraktiv wird. Unter diesem groben Kostenmodell liegt der Punkt, ab dem sich das Sortieren lohnt, bei etwa 20 Suchen. Die Schätzung hängt von vergleichbaren Operationskosten und vollständigen Durchläufen im schlechtesten Fall ab; sie ist kein allgemein gültiger Schwellenwert.

Reihenfolge, Verschiebung und Speicher abwägen

Bubblesort kann schnell fertig sein, wenn nur ein benachbartes Paar falsch steht. [1, 2, 4, 3, 5] benötigt eine Vertauschung im ersten Durchlauf und einen zweiten Durchlauf zur Bestätigung der Reihenfolge: sieben Vergleiche. „Nahezu sortiert“ garantiert aber nicht wenige Durchläufe. Ein kleiner Wert ganz rechts kann pro Durchlauf nur eine Position nach links wandern.

Die wenigen Vertauschungen von Selectionsort helfen, wenn Datensätze aufwendig zu verschieben sind. Selectionsort und Bubblesort benötigen beide nur eine feste Menge zusätzlichen Speichers. Mergesort verarbeitet große Listen mit viel langsamer wachsender Laufzeit, aber seine übliche listenbasierte Form benötigt Platz für etwa eine weitere Liste von Elementen.

Müssen Datensätze mit gleichen Schlüsseln ihre frühere Reihenfolge behalten, wähle ein stabiles Verfahren. Eine bereits nach Namen alphabetisch sortierte Liste kann stabil nach Note sortiert werden und innerhalb jeder Notengruppe alphabetisch bleiben. Das gewöhnliche Selectionsort kann diese Reihenfolge gleicher Schlüssel verändern.

Getestete Bibliotheksfunktionen nutzen

Echte Programme nutzen gewöhnlich die eingebaute Sortierfunktion der Sprache. Pythons stabile Sortierung verwendet ein adaptives Verfahren auf Grundlage des Verschmelzens, das üblicherweise Timsort heißt und von bereits vorhandener Ordnung in der Eingabe profitiert. sorted(items) gibt eine neue Liste zurück, während items.sort() die bestehende Liste verändert. Eine Funktion, die als Verhalten ihrer Programmierschnittstelle eine Liste selbst verändert, kann intern dennoch temporären Arbeitsspeicher verwenden; sie muss die oben für die einfachen Sortierverfahren verwendete Definition eines festen zusätzlichen Speicherbedarfs nicht erfüllen.

Bei einer Handvoll Elementen kann einfacher, klarer Code wichtiger sein als das Wachstum. Vergleiche bei großen Sammlungen das Verhalten im schlechtesten Fall und den Speicherbedarf zusammen mit den Eigenschaften, die die Aufgabe tatsächlich verlangt.

Wichtige Erkenntnisse

  • Beziehe beim Vergleich von Suchen in unsortierten Daten den Vorbereitungsaufwand ein.
  • Wiederholte Suchen können eine einmalige Sortierung lohnend machen.
  • Selectionsort begrenzt Vertauschungen; Mergesort begrenzt das Laufzeitwachstum, benötigt aber zusätzlichen Speicher.
  • Nutze ein stabiles Sortierverfahren, um die frühere Reihenfolge innerhalb von Gruppen gleicher Schlüssel zu erhalten.
  • Eingebaute Sortierfunktionen bieten getestete Implementierungen; bei kleinen Eingaben kann Einfachheit vorteilhaft sein.

Suchen, Sortieren und Effizienz: Beispiele

5 Interaktive Lektionen

1

Finde einen Suchwert, ohne die Positionen aus den Augen zu verlieren

13 Schritte
Vollziehe die lineare und die binäre Suche nach, zähle ihren Aufwand und prüfe die Ränder beider Suchverfahren.
  1. 1
    EinführungFinde einen Wert und gib seine Position an

    Eine Suche muss einen gespeicherten Wert von seiner Position unterscheiden. In [7, 3, 9, 3, 5] reichen die Positionen von 0 bis 4. Der Wert 3 erscheint an den Indizes 1 und 3.

    Wir prüfen zunächst Positionen der Reihe nach (lineare Suche) und nutzen dann die sortierte Reihenfolge, um Gruppen von Positionen auszuschließen (binäre Suche). Dabei zählen wir Vergleiche, um den Aufwand beider Verfahren zu sehen. Beide geben bei Erfolg einen Index und bei fehlendem Suchwert -1 zurück.

  2. 2
    ErklärungSchließe mit einem Misserfolg eine Position aus

    Die lineare Suche vergleicht den Suchwert von links nach rechts mit jedem Element. Ein Treffer beendet die Suche sofort; bei einem nicht passenden Element geht sie zur nächsten Position weiter.

    Eine unsortierte Liste bietet keinen Grund, spätere Elemente nach einem frühen Misserfolg auszuschließen. Deshalb gehört die Rückgabe „nicht gefunden“ hinter die Schleife, nachdem jede Position geprüft wurde.

  3. 3
    BeispielFinde die erste 3

    Suche in [7, 3, 9, 3, 5] nach 3.

    An Index 0 unterscheidet sich 7 von 3, also suche weiter. An Index 1 steht der Wert 3, gib also nach zwei Vergleichen 1 zurück.

    Die zweite 3 wird nicht mehr geprüft. Der zurückgegebene Index ist 1, die Anzahl der Vergleiche ist dagegen 2; diese Zahlen beschreiben unterschiedliche Teile des Ablaufs.

  4. 4
    HerausforderungVollziehe einen späteren Treffer nach

    Die lineare Suche prüft [19, 4, 11, 4, 8] auf 11. Welchen Index gibt sie zurück und wie viele Vergleiche führt sie aus?

    ---reveal---

    Sie gibt nach drei Vergleichen Index 2 zurück: 19, 4, dann 11. Eine Rückgabe bei Misserfolg nach dem ersten nicht passenden Element würde fälschlich bei 19 anhalten. Index 2 ist die dritte Position, weil die Positionen bei null beginnen.

  5. 5
    KernaussageLass den Suchwert den Abbruchzeitpunkt bestimmen

    Bei einer nicht leeren Liste mit n Elementen benötigt die lineare Suche bestenfalls einen Vergleich und schlechtestenfalls n. Eine leere Liste benötigt null.

    Kommt der Suchwert einmal vor und ist jede Position gleich wahrscheinlich, beträgt der Durchschnitt erfolgreicher Suchen (n+1)/2. Alle Vorkommen zu zählen ändert die Aufgabe: Selbst ein früher Treffer kann diesen vollständigen Durchlauf nicht beenden.

  6. 6
    AnalogieSchließe mithilfe der Reihenfolge eine Seite aus

    In einem Wörterbuch kannst du dich der Hälfte zuwenden, die das gesuchte Wort enthält. Die binäre Suche nutzt dieselbe Idee der Ordnung mit genauen Indexschranken.

    Ihre Vorbedingung sind sortierte Daten. Ist eine mittlere Zahl zu klein, ist jede frühere Zahl ebenfalls zu klein. Ohne Ordnung liefert ein Vergleich mit der Mitte keine solche Information über die anderen Positionen.

  7. 7
    ErklärungBehalte beide Endpunkte im Suchintervall

    Beginne mit low = 0 und high = n - 1. Berechne mid = (low + high) // 2, solange low <= high gilt.

    Gib mid zurück, wenn der Wert dort übereinstimmt. Ist sein Wert zu klein, setze low = mid + 1; ist er zu groß, setze high = mid - 1. Der geprüfte mittlere Index wird nach beiden Arten von Misserfolg ausgeschlossen, sodass jede Aktualisierung das Suchintervall verkleinert.

  8. 8
    BeispielPrüfe die Mitte und dann die rechte Hälfte

    Finde 64 in [3, 8, 12, 17, 23, 31, 42, 56, 64, 77, 85]. Die anfänglichen Schranken sind 0 und 10. Ihr abgerundeter mittlerer Index ist 5; dort steht 31.

    Da 31 kleiner als 64 ist, setze low = 6. Die verbliebenen Schranken 6 und 10 ergeben den mittleren Index 8. Sein Wert ist 64, gib also nach zwei Prüfungen mittlerer Elemente 8 zurück.

  9. 9
    BeispielVerfolge, wie ein fehlender Suchwert das Intervall leert

    Suche in derselben sortierten Liste nach 20. Die geprüften Indizes und Werte sind 5 → 31, 2 → 12, 3 → 17 und 4 → 23.

    Nach den Aktualisierungen gilt low = 4, high = 3. Es bleibt kein Kandidat, gib also -1 zurück. Die letzte Prüfung war wichtig: Gleiche Endpunkte unmittelbar davor bedeuteten einen Kandidaten und kein leeres Suchintervall.

  10. 10
    HerausforderungBerechne den mittleren Index nach jeder Aktualisierung neu

    Suche in [2, 7, 13, 21, 34, 55] nach 34. Schließe dabei beide Schranken ein und runde den mittleren Index ab. Welche Indizes werden geprüft?

    ---reveal---

    Prüfe zuerst Index 2, der 13 enthält. Setze low = 3, während high bei 5 bleibt; der nächste mittlere Index ist also 4. Dort steht 34: Gib nach zwei Prüfungen 4 zurück. Die Position nach 2 war nicht automatisch der nächste mittlere Index.

  11. 11
    TippPrüfe den letzten Kandidaten und schließe geprüfte aus

    low <= high prüft ein Intervall mit einer Position. Eine strikte <-Bedingung übersieht [5] bei der Suche nach 5.

    Verwende nach nicht passenden Elementen mid + 1 und mid - 1. Mit low = mid kann eine Suche nach 20 in [10, 20] den mittleren Index 0 endlos wiederholen. Stimmen Duplikate überein, gibt diese Version einen passenden Index zurück, ohne zu garantieren, dass es der erste ist.

  12. 12
    HerausforderungWähle eine Suche für die tatsächliche Eingabe

    Du hast eine unsortierte Liste und benötigst eine Suche, ohne Zeit für die Vorbereitung einer sortierten Kopie. Welches der behandelten Suchverfahren ist unmittelbar anwendbar und warum?

    ---reveal---

    Die lineare Suche ist anwendbar, weil jede Gleichheitsprüfung ohne jede Ordnung zulässig ist. Die binäre Suche benötigt eine sortierte Reihenfolge, um die ausgeschlossenen Bereiche zu begründen. Eine geringe Anzahl von Prüfungen der Mitte kann eine fehlende Vorbedingung nicht ausgleichen.

  13. 13
    ZusammenfassungNutze die richtige Grundlage für den Abbruch

    Die lineare Suche hält beim ersten Treffer oder nach einem vollständigen Durchlauf an. Die binäre Suche nutzt die sortierte Reihenfolge und schnellen Indexzugriff, um ein Suchintervall mit eingeschlossenen Endpunkten zu verkleinern.

    Halte den zurückgegebenen Index getrennt von der Schrittzahl fest. Die binäre Suche benötigt bei nicht leerer Eingabe höchstens ⌊log⁡2n⌋+1 Prüfungen der Mitte, aber jede Prüfung kann im Code mehr als einen Vergleich enthalten.

2

Stelle Ordnung durch Vertauschungen benachbarter und entfernter Elemente her

16 Schritte
Prüfe die Anforderungen an eine Sortierung, vollziehe dann Bubblesort und Selectionsort nach und vergleiche ihre Kosten.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungPräzisiere die Sortieraufgabe
  2. 2
    ErklärungErhalte Elemente und stelle Ordnung her
  3. 3
    BeispielErkenne, was Stabilität erhält
  4. 4
    HerausforderungPrüfe beide Sortierbedingungen
  5. 5
    ErklärungBefördere ein großes Element nach rechts
  6. 6
    BeispielVerfolge drei aufeinanderfolgende Vertauschungen
  7. 7
    BeispielZähle den bestätigenden Durchlauf
  8. 8
    HerausforderungVergleiche Vertauschungen und Vergleiche
  9. 9
    KernaussageZähle Inversionen, um Vertauschungen zu zählen
  10. 10
    ErklärungWähle ein Minimum aus, bevor du es verschiebst
  11. 11
    BeispielPlatziere die ersten beiden Minima
  12. 12
    BeispielBeende die Sortierung, ohne einen Wert mit sich selbst zu vertauschen
  13. 13
    HerausforderungFinde ein Minimum nach dem Präfix
  14. 14
    KernaussageEine Vertauschung über größere Distanz kann einen gleichen Schlüssel überholen
  15. 15
    HerausforderungWähle ein Verfahren für aufwendige Verschiebungen
  16. 16
    ZusammenfassungVerfolge den Bereich, den jedes Verfahren festlegt
3

Teile eine Liste und setze sie durch Verschmelzen wieder zusammen

13 Schritte
Verfolge das Verschmelzen, vollziehe dann ein vollständiges rekursives Mergesort nach und zähle seine Ebenen.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungNutze die bereits in kleineren Teilen vorhandene Ordnung
  2. 2
    ErklärungVergleiche nur die nicht verwendeten Kopfelemente
  3. 3
    BeispielVerschmelze die ersten Werte
  4. 4
    BeispielKopiere die Restliste nach dem Ende der Vergleiche
  5. 5
    HerausforderungSchließe das Verschmelzen und das Zählen ab
  6. 6
    ErklärungVerkleinere jedes rekursive Problem
  7. 7
    BeispielTeile acht Elemente in einzelne Elemente
  8. 8
    BeispielSetze Paare und Hälften wieder zusammen
  9. 9
    BeispielZähle jede Verschmelzungsebene
  10. 10
    HerausforderungBeziehe die Arbeit innerhalb der Hälften ein
  11. 11
    VerbindungErhalte die Reihenfolge gleicher Schlüssel beim Zusammensetzen
  12. 12
    HerausforderungWende das Verfahren auf eine große stabile Sortierung an
  13. 13
    ZusammenfassungZähle Elemente über die Ebenen hinweg
4

Leite aus wiederholter Arbeit eine Zeitschätzung ab

14 Schritte
Zähle Schleifenausführungen, vergleiche Wachstumsfamilien und schätze Laufzeiten und Zeitbudgets ab.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungFrag dich, wie viel Arbeit die nächste Größe benötigt
  2. 2
    ErklärungWähle, was als Schritt zählt
  3. 3
    BeispielZähle jedes Paar nur einmal
  4. 4
    HerausforderungLies die Schranken, bevor du das Wachstum benennst
  5. 5
    KernaussageGib den Fall zusammen mit der Schrittzahl an
  6. 6
    ErklärungProbiere den Verdopplungstest
  7. 7
    BeispielUnterscheide eine Wachstumsbezeichnung von einer genauen Anzahl
  8. 8
    HerausforderungFinde einen Schnittpunkt anhand genauer Modelle
  9. 9
    VerbindungErkenne die Grenze schnellerer Hardware
  10. 10
    BeispielSkaliere eine gemessene quadratische Laufzeit
  11. 11
    HerausforderungBerechne eine Eingabegröße aus einem Zeitbudget
  12. 12
    TippMiss vergleichbare Fälle wiederholt
  13. 13
    HerausforderungNutze beobachtete Verhältnisse für eine Prognose
  14. 14
    ZusammenfassungÜbernimm das Zählmodell in die Schätzung
5

Zeige, dass ein Algorithmus funktioniert und zur Aufgabe passt

15 Schritte
Nutze Invarianten, Terminierungsargumente, Randfalltests und Kostenvergleiche, um einen Algorithmus zu beurteilen.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungFrag nach einer Garantie und praktischer Eignung
  2. 2
    ErklärungFormuliere die Zusicherungen vor ihrem Beweis
  3. 3
    BeispielErweitere die Invariante von Selectionsort
  4. 4
    BeispielErhalte einen möglichen Treffer und verkleinere sein Suchintervall
  5. 5
    HerausforderungUnterscheide Erhaltung und Terminierung
  6. 6
    ErklärungSage Ergebnisse an den Rändern vor der Ausführung voraus
  7. 7
    BeispielDecke eine Endlosschleife mit einem Intervall aus zwei Elementen auf
  8. 8
    HerausforderungFinde die Schranke der Schleife für Nachbarn
  9. 9
    TippBehalte einen minimalen fehlschlagenden Test
  10. 10
    ErklärungBeziehe den Vorbereitungsaufwand ein
  11. 11
    BeispielVerwende die sortierte Liste für weitere Suchen
  12. 12
    HerausforderungBerechne, ob sich die Vorbereitung lohnt
  13. 13
    VerbindungBerücksichtige neben dem Laufzeitwachstum weitere Eigenschaften
  14. 14
    HerausforderungVerbinde Korrektheit mit einer praktischen Anforderung
  15. 15
    ZusammenfassungNutze Argumente, Tests und Kosten gemeinsam

Suchen, Sortieren und Effizienz: Übungsaufgaben

40 Übungsfragen in 4 Sets

Set 1: Finde Werte und vollziehe die Algorithmen nach10 Übungsfragen

Frage 1 von 10

Die lineare Suche durchsucht [12, 7, 18, 7] nach 7. Welchen Index gibt sie zurück?
  1. 0
  2. 1
  3. 2
  4. 3
Antwort zeigenAntwort ausblenden
Antwort: B
Der erste Treffer ist das zweite Element mit Index 1, weil die Indizierung bei null beginnt. Die lineare Suche hält dort an und erreicht die zweite 7 an Index 3 nicht. Die Rückgabe von 2 würde die Anzahl der geprüften Elemente mit der zurückgegebenen Position verwechseln.

Frage 2 von 10

Die binäre Suche verwendet bei [4, 9, 15, 22, 30, 41, 57] eingeschlossene Schranken und einen abgerundeten mittleren Index. Welche Indizes prüft sie bei der Suche nach 41?
  1. 3, 4, 5
  2. 3, 6, 5
  3. 4, 5
  4. 3, 5
Antwort zeigenAntwort ausblenden
Antwort: D
Der erste mittlere Index ist 3 und enthält 22. Da 41 größer ist, sind die verbleibenden Schranken 4 und 6. Deren mittlerer Index ist 5, wo 41 gefunden wird. Würde als Nächstes Index 4 geprüft, würde das verbleibende Suchintervall vom Anfang an durchsucht, statt seine Mitte zu wählen.

Frage 3 von 10

Eine Sortierfunktion erhält [6, 2, 6, 1]. Welche Ausgabe erfüllt die Spezifikation einer aufsteigenden Sortierung?
  1. [1, 2, 6, 6]
  2. [1, 2, 6]
  3. [1, 2, 2, 6]
  4. [6, 6, 2, 1]
Antwort zeigenAntwort ausblenden
Antwort: A
Die Ausgabe muss nicht absteigend sein und jedes ursprüngliche Vorkommen erhalten, einschließlich beider Vorkommen von 6. Die Liste [1, 2, 6] enthält geordnete Werte, verliert aber ein Element. Sortieren ordnet Daten um; es entfernt keine wiederholten Werte.

Frage 4 von 10

Welche Liste bleibt nach einem vollständigen Bubblesort-Durchlauf von links nach rechts über [8, 3, 6, 2] übrig?
  1. [3, 6, 8, 2]
  2. [2, 3, 6, 8]
  3. [3, 6, 2, 8]
  4. [3, 8, 2, 6]
Antwort zeigenAntwort ausblenden
Antwort: C
Bei den Vergleichen wird 8 mit 3, dann 8 mit 6 und schließlich 8 mit 2 vertauscht. Es bleibt [3, 6, 2, 8]. Der größte Wert steht nun rechts endgültig fest. Ein vollständig sortiertes Ergebnis würde voraussetzen, dass ein Durchlauf auch das verbleibende Präfix ordnet. Dieser Ablauf zeigt, dass das nicht stimmt.

Frage 5 von 10

Verschmelze [2, 11] mit [5, 14, 19]. Welche Elemente müssen nach dem Kopieren von 11 noch kopiert werden?
  1. 5 und 19
  2. 14 und 19
  3. nur 19
  4. 11 und 14
Antwort zeigenAntwort ausblenden
Antwort: B
Nach dem Kopieren von 2, 5 und 11 ist die linke Eingabe aufgebraucht und die rechte enthält noch 14 und 19. Beide müssen kopiert werden, um alle Elemente zu erhalten. Nur 19 zu kopieren würde 14 überspringen, obwohl keine weiteren Vergleiche von Kopfelementen nötig sind.

Frage 6 von 10

Ein Mergesort-Aufruf erhält [16]. Was sollte er zurückgeben?
  1. sofort [16]
  2. sofort []
  3. nach dem Verschmelzen [16, 16]
  4. nach dem Teilen []
Antwort zeigenAntwort ausblenden
Antwort: A
Eine Liste mit einem Element erfüllt bereits die Sortierbedingungen, sodass der Basisfall [16] unverändert zurückgibt. Eine leere Liste zurückzugeben würde das ursprüngliche Element verlieren. Eine weitere rekursive Teilung ist unnötig, weil das Problem seine Abbruchgröße bereits erreicht hat.

Frage 7 von 10

Ein Algorithmus vergleicht in einer Liste mit 7 Elementen jedes Paar verschiedener Positionen einmal. Wie viele Elementvergleiche führt er aus?
  1. 49
  2. 42
  3. 28
  4. 21
Antwort zeigenAntwort ausblenden
Antwort: D
Die aufeinanderfolgenden Elemente benötigen 6, 5, 4, 3, 2, 1 und 0 Vergleiche mit späteren Positionen, zusammen 21. Gleichwertig kannst du 7×6/2 verwenden. Eine Anzahl von 42 zählt jedes ungeordnete Paar zweimal, einmal aus jeder Richtung.

Frage 8 von 10

Ein Verfahren benötigt genau n2 Schritte. Wie verändert sich die Anzahl, wenn sich die Eingabegröße verdoppelt?
  1. Sie verdoppelt sich.
  2. Sie verdreifacht sich.
  3. Sie vervierfacht sich.
  4. Sie bleibt unverändert.
Antwort zeigenAntwort ausblenden
Antwort: C
Ersetzt man n durch 2n, ergibt sich (2n)2=4n2, sodass die Anzahl viermal so groß wird. Eine bloße Verdopplung der Schrittzahl würde lineares Wachstum beschreiben. Das Quadrat wirkt sowohl auf das Größenverhältnis als auch auf die ursprüngliche Eingabegröße.

Frage 9 von 10

Selectionsort hat die kleinsten vier Elemente geordnet an den Indizes 0–3 platziert. Warum erhält es diese Präfixeigenschaft, wenn es das Minimum ab Index 4 auswählt und an Index 4 tauscht?
  1. Das verbleibende Suffix ist bereits geordnet.
  2. Das fünfte Element bleibt bei jeder Suche unverändert.
  3. Das neue Element ist nicht kleiner als die vier platzierten.
  4. Die früheren Vertauschungen beseitigten jede Inversion.
Antwort zeigenAntwort ausblenden
Antwort: C
Das verbleibende Minimum ist mindestens so groß wie jedes bereits platzierte Element. Wird es angefügt, erweitert es also das geordnete Präfix der kleinsten Elemente. Ein vollständiger Durchlauf des Suffixes bestimmt dieses Minimum. Er stellt nicht fest, dass das gesamte Suffix bereits geordnet war; das wäre eine stärkere und unbegründete Aussage.

Frage 10 von 10

Eine binäre Suche mit eingeschlossenen Schranken verwendet versehentlich while low < high. Welcher kleinste nicht leere Test deckt einen übersehenen vorhandenen Suchwert auf?
  1. [13], Suchwert 13
  2. [13], Suchwert 8
  3. [8, 13], Suchwert 8
  4. [8, 13], Suchwert 20
Antwort zeigenAntwort ausblenden
Antwort: A
Bei einem Element sind beide Schranken gleich 0. Die falsche strikte Bedingung überspringt daher den einzigen Kandidaten und meldet beim Suchwert 13 einen Misserfolg. Ein fehlender Suchwert in derselben Liste kann trotzdem das richtige Ergebnis erhalten. Der Test benötigt einen vorhandenen Suchwert, um die fehlende letzte Prüfung aufzudecken.
Set 2: Zähle den Aufwand und wähle praktische Verfahren10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

Eine lineare Suche meldet einen fehlenden Suchwert in einer unsortierten Liste mit 9 Elementen. Wie viele Vergleiche zwischen Element und Suchwert führt sie aus?
  1. 0
  2. 1
  3. 8
  4. 9
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Die binäre Suche verwendet eingeschlossene Schranken und einen abgerundeten mittleren Index. Wie lauten bei [6, 12, 18, 25, 33, 46] die Schranken unmittelbar nach der ersten Prüfung des Suchwerts 30?
  1. low 2, high 5
  2. low 3, high 5
  3. low 0, high 1
  4. low 0, high 2
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

Bubblesort mit vorzeitigem Abbruch verwendet bei [1, 3, 2, 4] verkürzte Durchläufe. Wie viele Vergleiche führt es vor dem Abbruch aus?
  1. 3
  2. 4
  3. 5
  4. 6
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

Das übliche Selectionsort erhält 6 bereits sortierte Elemente. Wie viele Elementvergleiche führt es aus?
  1. 15
  2. 5
  3. 0
  4. 30
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

Beim Verschmelzen von [1, 8, 13] und [4, 9] werden nur Vergleiche zwischen Kopfelementen gezählt. Wie viele sind es?
  1. 2
  2. 3
  3. 4
  4. 5
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

Eine Schleife läuft n Mal. Bei jeder Wiederholung läuft eine zweite Schleife genau 4 Mal. Wie oft wird der innere Schleifenrumpf ausgeführt?
  1. n+4
  2. n2
  3. 4n
  4. 4n
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

Ein quadratisches Sortierverfahren benötigt 3 Sekunden für 12.000 Elemente. Wie lange sollten 36.000 Elemente unter vergleichbaren Bedingungen ungefähr dauern?
  1. 27 Sekunden
  2. 9 Sekunden
  3. 18 Sekunden
  4. 81 Sekunden
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

Ein Sortierverfahren erhält [4, 4, -2] und gibt [-2, 4] zurück. Welche Anforderung hat es verletzt?
  1. Aufsteigende Reihenfolge der Schlüssel
  2. Erhaltung jedes Vorkommens
  3. Rückgabe des kleinsten Werts zuerst
  4. Platzierung negativer Werte zuerst
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

Verwende für eine unveränderte unsortierte Sammlung diese Kostenschätzungen: Sortieren kostet 9.000 Einheiten, jede binäre Suche 12 Einheiten und jede lineare Suche 600 Einheiten. Welcher Plan kostet bei 20 Suchen weniger und um wie viel?
  1. Lineare Suchen, um 2.760 Einheiten
  2. Lineare Suchen, um 3.000 Einheiten
  3. Sortieren und binär suchen, um 3.000 Einheiten
  4. Sortieren und binär suchen, um 2.760 Einheiten
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

Eine Aufgabe darf nur eine feste Menge zusätzlichen Arbeitsspeichers nutzen und muss Vertauschungen minimieren. Welche Wahl erfüllt unter den behandelten Sortierverfahren diese Prioritäten am besten?
  1. Mergesort, bei gleichen Schlüsseln links zuerst
  2. Selectionsort, mit einer Vertauschung pro Durchlauf
  3. Bubblesort, mit einem Kennzeichen für vorzeitigen Abbruch
  4. Mergesort, mit einem einzigen abschließenden Verschmelzen
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Set 3: Erkläre die Ränder und vergleiche Zielkonflikte10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

Die binäre Suche verwendet bei [5, 11, 16, 24, 38, 47, 59, 70] eingeschlossene Schranken und abgerundete mittlere Indizes. Welche Indizes werden für den fehlenden Suchwert 41 geprüft?
  1. 3, 5, 4
  2. 3, 4, 5
  3. 4, 6, 5
  4. 3, 5, 6
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Datensätze treffen in der Reihenfolge Eli 72, Jo 65, Kai 72, Luz 65 ein. Welche Reihenfolge ergibt eine stabile Sortierung nach aufsteigender Punktzahl?
  1. Luz, Jo, Eli, Kai
  2. Jo, Luz, Kai, Eli
  3. Jo, Luz, Eli, Kai
  4. Eli, Kai, Jo, Luz
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

Wie lautet die Liste nach dem zweiten Selectionsort-Durchlauf über [18, 7, 12, 4, 9]?
  1. [4, 7, 9, 12, 18]
  2. [7, 4, 12, 18, 9]
  3. [4, 9, 12, 18, 7]
  4. [4, 7, 12, 18, 9]
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

Mergesort teilt eine Liste mit 32 Elementen in Hälften, bis einzelne Elemente übrig sind. Wie viele Verschmelzungsebenen setzen sie wieder zusammen?
  1. 4
  2. 5
  3. 6
  4. 16
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

Verfahren P benötigt 60n Schritte und Verfahren Q benötigt n2. Wann benötigt P bei positiven Eingabegrößen weniger Schritte?
  1. Wenn n>60
  2. Wenn n<60
  3. Wenn n≥60
  4. Wenn n≤60
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

Ein quadratischer Prozess benötigt 5 Sekunden für 8.000 Elemente. Wie viele Elemente erlaubt ein Budget von 45 Sekunden nach demselben Modell ungefähr?
  1. 24.000 Elemente nach Skalierung mit 9
  2. 72.000 Elemente nach Skalierung mit 9
  3. 16.000 Elemente nach Skalierung mit 2
  4. 24.000 Elemente nach Skalierung mit 3
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

Eine binäre Suche mit eingeschlossenen Schranken erhält jeden möglichen Treffer innerhalb ihres Suchintervalls, setzt aber nach einem zu kleinen mittleren Wert low = mid. Welcher Teil eines vollständigen Korrektheitsarguments kann scheitern?
  1. Die Vorbedingung zur Eingabereihenfolge
  2. Die Garantie, dass die Ausführung anhält
  3. Die Gleichheitsprüfung bei einem Treffer
  4. Die Erhaltung der ursprünglichen Elemente
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

Eine Liste ist bereits nach Ankunftszeit geordnet. Sie muss nun nach Priorität geordnet werden und dabei innerhalb gleicher Prioritäten die Ankunftsreihenfolge erhalten. Welche Sortiereigenschaft wird benötigt?
  1. Fester zusätzlicher Speicher
  2. Wenige bewegende Vertauschungen
  3. Stabilität bei gleichen Schlüsseln
  4. Eine quadratische Vergleichsschranke
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

Ein vollständiger Bubblesort-Durchlauf nimmt keine Vertauschungen vor. Was steht damit über die gesamte Liste einschließlich eines bereits feststehenden Suffixes fest?
  1. Sie ist sortiert.
  2. Ihre Werte sind verschieden.
  3. Sie hat ein Element.
  4. Ihre Schlüssel sind gleich.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

Ein stabiles Verschmelzen führt die linken Datensätze [2A, 6B] und die rechten Datensätze [2C, 5D] zusammen und vergleicht nur numerische Schlüssel. Welche Reihenfolge der Datensätze ergibt sich?
  1. 2C, 2A, 5D, 6B
  2. 2A, 5D, 2C, 6B
  3. 2A, 2C, 5D, 6B
  4. 2A, 2C, 6B, 5D
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Set 4: Analysiere Abläufe und begründe Entscheidungen10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

Eine übliche lineare Suche führt auf [14, 6, 21, 6] 4 Vergleiche aus. Welches Paar aus Suchwert und Ergebnis ist möglich, wenn sie beim ersten Treffer sofort anhält?
  1. Suchwert 6, Rückgabe 3
  2. Suchwert 21, Rückgabe 2
  3. Suchwert 8, Rückgabe -1
  4. Suchwert 14, Rückgabe 0
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Eine binäre Suche mit eingeschlossenen Schranken hat low = 6, high = 6 und das verbleibende Element entspricht dem Suchwert. Was tut die korrekte Schleife?
  1. Sie prüft Index 6 und gibt 6 zurück.
  2. Sie gibt -1 ohne Prüfung zurück.
  3. Sie setzt low vor der Prüfung auf 7.
  4. Sie prüft Index 5 und gibt 5 zurück.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

Wie viele Inversionen gibt es in [5, 3, 5, 2, 4, 1]?
  1. 10
  2. 11
  3. 12
  4. 15
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

Selectionsort verwendet beim Finden jedes Minimums ein striktes <. Wie lautet bei [7A, 3X, 7B, 2Y, 3Z] die endgültige Reihenfolge der Datensätze, wenn nur numerische Schlüssel verglichen werden?
  1. 2Y, 3Z, 3X, 7A, 7B
  2. 2Y, 3X, 3Z, 7B, 7A
  3. 2Y, 3Z, 3X, 7B, 7A
  4. 2Y, 3X, 3Z, 7A, 7B
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

Verwende Mergesort mit abgerundeten Halbierungen für [9, 1, 7, 3]. Wie viele Vergleiche führt die vollständige Sortierung aus, wenn nur Elementvergleiche beim Verschmelzen gezählt werden?
  1. 2
  2. 3
  3. 4
  4. 5
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

Ein Algorithmus vergleicht zunächst jedes Paar verschiedener Elemente einmal und durchläuft dann alle n Elemente einmal, wobei pro durchlaufenem Element ein Vergleich gezählt wird. Welche Formel gilt für die Gesamtzahl der Vergleiche?
  1. n(n−1)/2
  2. n(n+1)/2
  3. n2+n
  4. n(n−1)
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

Ein Prozess probiert jede Auswahl aus n unabhängigen Elementen aus, insgesamt 2n Auswahlen. Was geschieht mit dieser Anzahl, wenn ein weiteres Element hinzugefügt wird?
  1. Sie steigt um eins.
  2. Sie wird quadriert.
  3. Sie verdoppelt sich.
  4. Sie vervierfacht sich.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

Wiederholte Durchläufe bei sich verdoppelnden Eingabegrößen dauern etwa 0,06, 0,24 und 0,96 Sekunden. Welches Wachstumsmuster stützen diese Verhältnisse?
  1. Quadratisches Wachstum
  2. Lineares Wachstum
  3. Konstantes Wachstum
  4. Logarithmisches Wachstum
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

Ein Beweis zeigt, dass eine Sortierschleife anhält und jedes benachbarte Paar geordnet ist. Ihr Code überschreibt aber auch einige Einträge, ohne sie zu sichern. Welche zusätzliche Eigenschaft muss gezeigt werden, bevor die Sortierung als korrekt bezeichnet werden kann?
  1. Jeder Durchlauf benötigt weniger Vergleiche.
  2. Jedes ursprüngliche Element bleibt in seiner Anzahl erhalten.
  3. Jeder gleiche Schlüssel behält seine alte Position.
  4. Jede Ausführung nutzt festen zusätzlichen Speicher.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

Ein zufallsgesteuerter Test findet einen Sortierfehler bei einer langen Liste. Welcher nächste Schritt hilft am besten, den Fehler zu finden und seine Rückkehr zu verhindern?
  1. Die ganze Liste behalten und jede Position wiederholt nachvollziehen.
  2. Die Eingabe durch eine typische Liste ersetzen und ihr Ergebnis behalten.
  3. Weitere zufällige Listen erzeugen, bevor der erste Fehler untersucht wird.
  4. Die fehlschlagende Eingabe verkleinern und als Regressionstest behalten.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Hängst du bei deiner eigenen Aufgabe fest? Hausaufgabenhilfe

Schlüsselbegriffe

62 Schlüsselbegriffe, jeweils mit Definition

B

Basisfall
Ein Basisfall ist eine Eingabe, die ohne weiteren rekursiven Aufruf direkt bearbeitet wird und einen Abbruchpunkt für die Rekursion bietet.
Bei Mergesort werden sowohl eine leere Liste als auch eine Liste mit einem Element unverändert zurückgegeben, weil sie bereits sortiert sind.
Benachbarte Elemente
Benachbarte Elemente belegen benachbarte Listenpositionen, sodass sich ihre Indizes um genau eins unterscheiden, wenn beide Positionen existieren.
Bubblesort vergleicht items[j] mit items[j + 1], sodass seine Verschiebungen von benachbarten Paaren abhängen.
Bester Fall
Der beste Fall ist die zulässige Eingabesituation, die unter Eingaben gleicher Größe die wenigsten gezählten Operationen benötigt.
Eine lineare Suche, die ihren Suchwert an der ersten Position findet, führt bei einer nicht leeren Liste einen Vergleich aus.
Binäre Suche
Eine binäre Suche nutzt die sortierte Reihenfolge, um ein Suchintervall mit eingeschlossenen Endpunkten einzugrenzen, indem sie den Suchwert mit einem mittleren Element vergleicht.
Die Suche in einem sortierten Array mit etwa einer Million Elementen benötigt höchstens 20 Prüfungen mittlerer Elemente.

D

Direkter Zugriff
Direkter Zugriff bedeutet, ein Element über seinen Index zu erreichen, ohne frühere Elemente durchlaufen zu müssen, wie es ein Array oder eine Python-Liste erlaubt.
Das Folgen von Verweisen bis zur Mitte einer verketteten Liste erfordert einen zusätzlichen Durchlauf und schwächt den Vorteil der binären Suche.
Dominanter Term
Ein dominanter Term ist der am schnellsten wachsende Teil eines Ausdrucks für die Schrittzahl und bestimmt deren langfristiges Wachstum bei steigender Eingabegröße.
In n2/2−n/2 dominiert der quadratische Term, obwohl beide Terme die genaue Anzahl der Vergleiche beeinflussen.
Durchlauf
Ein Durchlauf ist ein Gang durch den aktiven Teil einer Liste, bei dem eine Folge von Vergleichen oder Platzierungen ausgeführt wird.
Ein Bubblesort-Durchlauf platziert das größte verbliebene Element endgültig, kann aber die früheren Positionen unsortiert lassen.
Durchschnittlicher Fall
Der durchschnittliche Fall beschreibt den durchschnittlichen Aufwand unter einer festgelegten Verteilung von Eingaben; sein Wert hängt daher davon ab, welche Eingaben auftreten.
Gleiche Wahrscheinlichkeiten für erfolgreiche Suchwertpositionen ergeben bei der linearen Suche durchschnittlich (n+1)/2 Vergleiche.

E

Eingabegröße
Die Eingabegröße misst, wie viele Daten ein Algorithmus erhält; für die Listenalgorithmen hier ist sie die Anzahl der Elemente, n.
Zwei gleich lange Listen haben dieselbe Eingabegröße, selbst wenn eine sortiert und die andere umgekehrt sortiert ist.
Elementaroperation
Eine Elementaroperation ist die wiederholte Handlung, die zum Zählen des Aufwands gewählt wird, etwa der Vergleich zweier Schlüssel oder die Prüfung eines mittleren Elements.
Eine Prüfung der Mitte bei der binären Suche kann zwei Elementvergleiche ausführen, sodass ihre Anzahl eine eigene Bezeichnung benötigt.
Exponentieller Aufwand
Bei exponentiellem Aufwand vervielfacht sich der Aufwand für jedes zusätzliche Element um einen festen Faktor; eine Anzahl von 2n verdoppelt sich bei einem zusätzlichen Element.
Das Ausprobieren jeder Auswahl aus 30 Elementen benötigt doppelt so viele Auswahlen wie das Ausprobieren jeder Auswahl aus 29.

G

Ganzzahlüberlauf
Ein Ganzzahlüberlauf tritt auf, wenn eine Rechnung den Bereich einer Ganzzahl mit fester Bitbreite überschreitet; die Wirkung hängt von Sprache und Operation ab.
Die Berechnung des mittleren Index über die Differenz vermeidet eine zu große Summe der Endpunkte, wenn die Indizes nicht negativ und zulässig sind.
Gegenbeispiel
Ein Gegenbeispiel ist eine zulässige Eingabe, deren beobachtetes Verhalten eine behauptete allgemeine Eigenschaft verletzt und damit die Behauptung widerlegt.
Eine einzige sortierte Liste mit zwei Elementen, die eine endlose Suche verursacht, widerlegt die Aussage, dass die Suche immer terminiert.

I

In-place-Sortierverfahren
Ein In-place-Sortierverfahren ordnet die bestehende Liste bei wachsender Eingabegröße mit nur einer festen Menge zusätzlichen Arbeitsspeichers um.
Bubblesort benötigt einige Zählvariablen und ein Vertauschungskennzeichen statt einer weiteren Liste proportional zur Eingabe.
Index
Ein Index ist eine nummerierte Position für den Zugriff auf ein Listenelement; Python-Indizes beginnen bei null und enden eins vor der Listenlänge.
In [8, 13, 21] steht an Index 2 die 21, obwohl sie beim alltäglichen Zählen das dritte Element ist.
Inversion
Eine Inversion ist ein Positionspaar, bei dem ein früheres Element einen größeren Schlüssel hat als ein späteres; gleiche Schlüssel tragen keine Inversion bei.
In [8, 3, 6] bildet 8 mit beiden späteren Werten eine Inversion, obwohl nur ein Paar benachbart ist.

K

Konstanter Aufwand
Konstanter Aufwand bedeutet, dass der gezählte Aufwand unabhängig von der Eingabegröße beschränkt bleibt, wie beim Lesen einer bekannten Array-Position.
Der Zugriff auf einen bestimmten Index benötigt keinen Durchlauf aller früheren Array-Elemente, wenn die Liste wächst.
Kopfelement
Ein Kopfelement beim Verschmelzen ist das erste nicht verwendete Element einer sortierten Eingabe und damit deren kleinstes verbliebenes Element.
Nachdem du das linke Kopfelement genommen hast, bewege nur den linken Laufindex weiter; das rechte Kopfelement wartet weiterhin auf den Vergleich.

L

Laufindex
Ein Laufindex verfolgt die nächste nicht verwendete Position in einer Eingabeliste, damit beim Verschmelzen das nächste Element verglichen oder kopiert werden kann.
Getrennte linke und rechte Laufindizes verhindern, dass beim Verschmelzen ein Element doppelt kopiert oder nach einem Vergleich übersprungen wird.
Laufzeitprognose
Eine Laufzeitprognose schätzt die Laufzeit bei einer anderen Größe, indem sie ein Wachstumsmodell auf eine gemessene oder vorgegebene Referenzlaufzeit anwendet.
Eine Verdreifachung der Eingabe multipliziert in einem quadratischen Modell die Referenzlaufzeit mit etwa neun, nicht mit drei.
Lineare Suche
Eine lineare Suche prüft Elemente vom Anfang an der Reihe nach und hält beim ersten Treffer an oder meldet nach der gesamten Liste das Fehlen des Suchwerts.
Das letzte Element einer Liste mit neun Elementen durch lineare Suche zu finden benötigt neun Vergleiche zwischen Element und Suchwert.
Linearer Aufwand
Linearer Aufwand bedeutet, dass der Aufwand direkt proportional zur Eingabegröße steigt, sodass eine Verdopplung der Elementzahl den Aufwand ungefähr verdoppelt.
Ein vollständiger Durchlauf mit einem Schlüsselvergleich pro Element führt 2.000 Vergleiche aus, wenn seine Eingabe auf 2.000 Elemente wächst.
Logarithmischer Aufwand
Logarithmischer Aufwand entsteht, wenn wiederholtes Verringern um einen festen Faktor dazu führt, dass jede Verdopplung der Eingabe nur einen festen Aufwand hinzufügt.
Wiederholtes Halbieren ergibt bei der binären Suche etwa eine zusätzliche Prüfung der Mitte, wann immer sich die Listengröße verdoppelt.

M

Mergesort
Mergesort sortiert rekursiv zwei kürzere Hälften und verschmilzt die sortierten Ergebnisse. Der Aufwand wächst proportional zu nlog⁡n.
Eine große Liste durchläuft mehrere Teilungsgrößen, bevor ihre sortierten Teile zu einer Ausgabe zusammengesetzt werden.
Mittlerer Index
Der mittlere Index ist die innerhalb eines Suchintervalls gewählte mittlere Position. Er wird abgerundet, wenn der Mittelwert der Endpunkte keine ganze Zahl ist.
Bei eingeschlossenen Schranken 2 und 7 wählt (2 + 7) // 2 Index 4 als nächsten mittleren Index.

N

Nachbedingung
Eine Nachbedingung gibt an, was für das Ergebnis eines Algorithmus gelten muss, wenn er bei einer Eingabe endet, die seine Vorbedingung erfüllt.
Eine Nachbedingung für das Sortieren umfasst sowohl geordnete Schlüssel als auch die Erhaltung der ursprünglichen Vorkommen.

O

Off-by-one-Fehler
Ein Off-by-one-Fehler führt dazu, dass eine Schleifen- oder Indexgrenze eine Position zu viel oder zu wenig einschließt und dadurch ein Treffer verpasst wird oder ein ungültiger Zugriff entsteht.
Die Verwendung von low < high für ein binäres Suchintervall mit eingeschlossenen Endpunkten überspringt einen letzten Kandidaten, wenn die Endpunkte gleich werden.

P

Permutation
Eine Permutation ist eine Umordnung derselben Elemente, bei der die Anzahl der Vorkommen jedes Wertes erhalten bleibt.
[2, 8, 2] und [2, 2, 8] sind Permutationen voneinander; [2, 8] verliert ein Vorkommen.

Q

Quadratischer Aufwand
Quadratischer Aufwand bedeutet, dass der Aufwand proportional zum Quadrat der Eingabegröße wächst und bei einer Verdopplung etwa viermal so groß wird.
Die paarartige Anzahl der Vergleiche von Selectionsort wächst quadratisch, obwohl die Anzahl seiner Vertauschungen viel langsamer wächst.

R

Randfall
Ein Randfall ist eine zulässige Eingabe an einem Rand des Verhaltens eines Algorithmus, an dem Schleifengrenzen oder besondere Behandlungen fehlschlagen können.
Eine leere Liste prüft, ob die binäre Suche ihre Schranken testet, bevor sie versucht, auf ein mittleres Element zuzugreifen.
Referenzlaufzeit
Eine Referenzlaufzeit ist eine bei bekannter Eingabegröße gemessene Laufzeit, die als Ausgangspunkt für eine größenabhängige Schätzung dient.
Eine Referenzlaufzeit von 4 Sekunden bei 20.000 Elementen kann eine quadratische Schätzung für einen größeren vergleichbaren Durchlauf ermöglichen.
Regressionstest
Ein Regressionstest behält eine Prüfung für zuvor korrektes oder repariertes Verhalten bei, damit spätere Änderungen einen erneut auftretenden Fehler aufdecken.
Behalte eine minimale Liste, die einst zum Verlust eines Duplikats führte, um zu prüfen, ob künftige Änderungen alle Vorkommen erhalten.
Rekursion
Rekursion löst ein Problem durch Aufrufe derselben Prozedur für kleinere Instanzen und verwendet eine Abbruchregel für einfache Fälle.
Mergesort ruft sich für jede kürzere Hälfte selbst auf, bis ein Aufruf höchstens ein Element erhält.
Rekursiver Fall
Ein rekursiver Fall führt das aktuelle Problem auf kleinere Instanzen zurück und nutzt deren Ergebnisse, um die Antwort zu bilden.
Der rekursive Fall von Mergesort sortiert zwei Hälften, bevor er deren zurückgegebene geordnete Listen verschmilzt.
Restliste
Eine Restliste ist der verbleibende Teil einer Liste ab einer gewählten Position, der direkt kopiert wird, wenn die andere Eingabe beim Verschmelzen aufgebraucht ist.
Ist eine Eingabe beim Verschmelzen aufgebraucht, während auf der anderen Seite [14, 20] verbleibt, werden beide Elemente der Restliste weiterhin benötigt.

S

Schlechtester Fall
Der schlechteste Fall ist die zulässige Eingabesituation, die unter Eingaben gleicher Größe die meisten gezählten Operationen benötigt.
Ein fehlender Suchwert zwingt die grundlegende lineare Suche, jede Position zu prüfen, und ergibt so ihre Anzahl im schlechtesten Fall.
Schleifeninvariante
Eine Schleifeninvariante ist eine Aussage, die vor Beginn der Schleife gilt und nach jeder Wiederholung erhalten bleibt und so ein Argument für das Ergebnis stützt.
Die Invariante von Selectionsort verbindet die Länge seines Präfixes mit den kleinsten Elementen, die bereits platziert wurden.
Schnittpunkt
Ein Schnittpunkt ist eine Eingabegröße, bei der zwei Kostenmodelle gleichauf liegen. Bei weiter wachsender Eingabe kann sich ihre Reihenfolge ändern.
Die Modelle 40n und n2 sind bei 40 Elementen gleichauf; das lineare Modell wird bei größeren positiven Eingaben günstiger.
Selectionsort
Selectionsort durchsucht wiederholt den unsortierten Teil nach seinem Minimum und tauscht dieses Element an die nächste Position eines sortierten Präfixes.
Ein Selectionsort-Durchlauf merkt sich den Index des kleinsten Elements, bevor er die eine mögliche Vertauschung ausführt, die Elemente bewegt.
Sortieren
Sortieren ordnet Elemente nach Schlüsseln um und erhält dabei jedes ursprüngliche Element und jedes wiederholte Vorkommen.
Ein aufsteigendes Ergebnis, das ein Duplikat verliert, ist keine korrekte Sortierung, selbst wenn alle Nachbarn geordnet sind.
Sortierfunktion
Eine Sortierfunktion ist eine getestete Sortierimplementierung einer Sprache oder Bibliothek mit dokumentiertem Verhalten, etwa zu Stabilität und Ausgabeform.
Pythons sorted erstellt eine neue Ergebnisliste, während list.sort() die bestehende Liste umordnet.
Sortierschlüssel
Ein Sortierschlüssel ist der Wert oder das Datensatzfeld, das die Reihenfolge bestimmt; der übrige Datensatz bleibt beim Verschieben des Elements damit verbunden.
Beim Sortieren von Stadtdatensätzen nach Einwohnerzahl wird jeder Stadtname zusammen mit seiner Einwohnerzahl verschoben.
Sortiertes Präfix
Ein sortiertes Präfix ist ein bereits geordneter Anfangsteil einer Liste; Selectionsort füllt ihn zuerst mit den kleinsten Elementen.
Nach drei Selectionsort-Durchläufen enthalten die ersten drei Positionen die drei kleinsten Elemente in Reihenfolge.
Spezifikation
Eine Spezifikation nennt die Anforderungen an zulässige Eingaben und das Ergebnis, das ein Algorithmus erzeugen muss, sodass die Korrektheit überprüfbar wird.
Eine Suchspezifikation unterscheidet einen passenden Index von einem besonderen Ergebnis, das nur verwendet wird, wenn kein Treffer existiert.
Stabiles Sortierverfahren
Ein stabiles Sortierverfahren erhält die ursprüngliche relative Reihenfolge von Datensätzen, deren Schlüssel beim Vergleich gleich sind, auch wenn andere Datensätze verschoben werden.
Eine stabile Sortierung nach Punktzahl erhält innerhalb jeder Punktzahlgruppe die alphabetische Reihenfolge zuvor alphabetisch geordneter Namen.
Suche
Eine Suche prüft, ob ein Suchwert in einer Sammlung vorkommt, und kann seine Position oder ein Ergebnis melden, das sein Fehlen anzeigt.
Die Suche in einer Liste von Datensatz-IDs kann die Position des gewünschten Datensatzes zurückgeben, ohne die Liste zu verändern.
Suchintervall
Ein Suchintervall ist der Bereich von Positionen, die einen Suchwert noch enthalten können, nachdem frühere Vergleiche den Rest ausgeschlossen haben.
Die Schranken 4 bis 7 umfassen vier mögliche Positionen und die Schranken 5 bis 4 beschreiben ein leeres Suchintervall.
Suchwert
Ein Suchwert ist der Wert, nach dem eine Suche sucht und der mit gespeicherten Elementen oder einem gewählten Feld jedes gespeicherten Datensatzes verglichen wird.
Bei einer Suche nach der ID 630 ist der Suchwert 630; die zurückgegebene Position ist eine andere Zahl.

T

Teile und herrsche
Teile und herrsche löst ein Problem, indem es in kleinere Probleme zerlegt wird, diese gelöst und ihre Ergebnisse zusammengeführt werden.
Mergesort führt sortierte Teilergebnisse der Hälften zusammen; das Teilen allein lässt die ursprüngliche Reihenfolge der Werte unverändert.
Terminierung
Terminierung bedeutet, dass die Ausführung schließlich anhält; eine abnehmende nicht negative ganzzahlige Größe kann sie für eine Schleife belegen.
Wird der geprüfte mittlere Index ausgeschlossen, nimmt die Anzahl der Kandidaten bei der binären Suche nach jedem Misserfolg strikt ab.

U

Unsortiertes Suffix
Ein unsortiertes Suffix ist der verbleibende Endteil, dessen interne Reihenfolge durch den Sortiervorgang noch nicht hergestellt wurde.
Selectionsort durchsucht nur das unsortierte Suffix, damit es ein bereits platziertes Minimum nicht erneut auswählt.

V

Verdopplungstest
Ein Verdopplungstest vergleicht die Kosten bei aufeinanderfolgend verdoppelten Eingabegrößen, um nach den Verhältnissen zu suchen, die Wachstumsfamilien zugeordnet sind.
Wiederholte Zeitverhältnisse nahe vier deuten über den gemessenen Größenbereich hinweg auf quadratisches Wachstum hin.
Verschmelzen
Das Verschmelzen führt zwei sortierte Listen zusammen, indem es wiederholt das kleinere nicht verwendete Kopfelement und anschließend eine verbleibende Restliste kopiert.
Das Verschmelzen von [3, 10] und [6, 12] ergibt [3, 6, 10, 12], ohne eine der Eingaben erneut zu sortieren.
Vertauschung
Eine Vertauschung tauscht zwei gespeicherte Elemente aus und erhält dabei beide ursprünglichen Werte, etwa durch einen gesicherten Wert oder eine gleichzeitige Zuweisung.
Ohne einen Wert zu sichern, können zwei aufeinanderfolgende Zuweisungen [2, 9] in [9, 9] verwandeln, statt die Werte zu vertauschen.
Vollständiger Durchlauf
Ein vollständiger Durchlauf prüft jedes Element einer Sammlung, wie es zum Zählen aller Treffer oder zum Finden des größten Wertes nötig ist.
Das Zählen jedes Vorkommens von 7 läuft nach dem ersten Treffer weiter, weil auch spätere Elemente 7 enthalten können.
Vorbedingung
Eine Vorbedingung ist eine Anforderung, die für eine Eingabe erfüllt sein muss, bevor das zugesicherte Verhalten eines Algorithmus garantiert ist.
Aufsteigende Reihenfolge ist eine Vorbedingung für die gewöhnliche binäre Suche, sodass bei unsortierter Eingabe ihre Begründung für das Verwerfen von Bereichen nicht gilt.
Vorbereitungsaufwand
Der Vorbereitungsaufwand ist die vor der Hauptoperation nötige Arbeit, etwa das Sortieren einer Liste, damit spätere binäre Suchen zulässig sind.
Bei einer einzigen Suche kann ein linearer Durchlauf günstiger sein, weil sein Vorgehen einen großen einmaligen Sortieraufwand vermeidet.
Vorzeitiger Abbruch
Ein vorzeitiger Abbruch beendet einen Algorithmus vor seinem maximal geplanten Aufwand, sobald eine geprüfte Bedingung das geforderte Ergebnis bestätigt.
Ein Bubblesort-Durchlauf ohne Vertauschung bestätigt die Ordnung; die Vergleiche dieses Durchlaufs zählen weiterhin zur Gesamtzahl.

W

Wachstumsrate
Eine Wachstumsrate beschreibt, wie sich der Aufwand eines Algorithmus mit der Eingabegröße verändert, und unterscheidet sein Wachstumsmuster von einer einzelnen Ausführung.
Eine geringe Zeit bei einer kleinen Größe lässt offen, wie schnell diese Zeit steigt, wenn die Datenmenge viel größer wird.

Z

Zeitbudget
Ein Zeitbudget ist die erlaubte Laufzeit, mit der sich zusammen mit einem Kostenmodell abschätzen lässt, wie groß eine verarbeitbare Eingabe sein kann.
Ein quadratischer Prozess kann die dreifache Eingabe verarbeiten, wenn die verfügbare Zeit um den Faktor neun steigt.
Zielkonflikt
Ein Zielkonflikt ist eine Entscheidungssituation, in der die Verbesserung einer nützlichen Eigenschaft eine andere beeinträchtigen kann, etwa wenn weniger Vergleiche mehr Speicher kosten.
Mergesort verbessert das Laufzeitwachstum bei großen Eingaben, benötigt aber gewöhnlich mehr temporären Speicher als Selectionsort.
Zufallsgesteuertes Testen
Zufallsgesteuertes Testen erzeugt unterschiedliche Eingaben und prüft Ergebnisse anhand einer Spezifikation oder eines vertrauenswürdigen Verfahrens, um unerwartete Fehler zu finden.
Der Vergleich vieler zufällig erzeugter Sortierergebnisse mit sorted kann einen Fall aufdecken, den handverlesene Tests übersehen haben.

Über diese Einheit

Von StudeliFehler melden

Erstelle deine eigenen Lernmaterialien

Mach aus deinen Notizen, Folien und Dokumenten Lernleitfäden, Übungsfragen, Karteikarten und 6 weitere Tools.

Jetzt starten