Keylearnings:
- Die O Notation zur Messung der Performance eines Algorithmus.
- Was ist Komplexität?
- Was ist Performance?
- Was ist konstante Komplexität?
- Was ist lineare Komplexität?
- Was ist quadratische Komplexität?
- Was ist logarithmische Komplexität?
- Die Rechenregeln der O Notation.
Usain Bolt 9,6 Sekunden beim Sprintrennen über 100m bei der Leichtathletik WM in Berlin.
Anders Fannemel 251m bei der Skiflug WM in Vikasund.
Aleksei Lochchev 264kg. Neuer Weltrekord im Gewichtheben!
Wie schnell, wie weit, wie hoch geht’s bei dir?
Eine Frage, die du dir auch bei deinem Code stellen musst.
Aber nach welchem Maß können wir die Leistung unseres Codes beurteilen?
Genau das möchte ich in diesem Artikel beantworten und dir zeigen wie du mit der sogenannten groß O Notation die Performance deines Codes quantitativ bestimmen kannst.
Was ist Komplexität?
Warum hält Usain Bolt den Weltrekord im 100m Sprint ohne den Hauch einer Chance bei einem Marathonlauf zu haben?
Weil ein Marathonläufer Ausdauer benötigt wohingegen die Leistung eines Sprinters stark von der Muskelkraft abhängt.
Für beide Läufertypen sind unterschiedliche Ressourcen von Bedeutung.
Muskelkraft und Ausdauer sind aber gegenläufig.
Ein Ausdauerläufer muss möglichst leicht sein und kann deshalb nicht so viel Muskelmasse aufbauen wie ein Sprinter.
Und genau so ist es auch in deinem Programmcode.
Deine Programme benötigen keine Muskelkraft oder Ausdauer, dafür aber Speicher, Rechenleistung und Netzwerkbandbreite.
Die Menge der in Anspruch genommenen Ressourcen nennt man Programmkomplexität.
Um die Leistung eines Programms beurteilen zu können, muss zunächst entschieden werden, welche Ressource günstig und welche teuer ist.
Ein leistungsstarkes Programm geht schonend mit den teuren Ressourcen um.
Heute leben wir in einer Zeit, in der Speicher in großen Mengen günstig zu haben ist, deshalb ist die Rechenleistung die Ressource, die wir in der Regel schonen wollen.
Ähnlich wie der Marathonläufer eine bessere Ausdauer auf Kosten der Muskelkraft trainiert, können wir die Rechenleistung auf Kosten des Speicherbedarfs erhöhen indem wir beispielsweise mehrfach benötigte Zwischenergebnisse einer Rechnung zwischenspeichern.
Performance und Zeitkomplexität
Oft wird von der Performance einer Software gesprochen. Doch was bedeutet das?
Hier die Definition:
Die Performance ist die Zeitdauer, die ein Programm benötigt um eine bestimmte Aufgabe zu lösen.
So reichen Google knapp 0,7Sekunden um 154.000.000 Ergebnisse zu dem Suchwort Wetter zu finden. Was einer excellenten Performance entspricht.
Anstatt von Performance spricht man häufig auch von der Zeitkomplexität.
Eine höhere Performance erreichen wir vor allem durch Programme, die schonend mit der Ressource Rechenleistung umgehen.
Dabei ist klar, dass die Suche nach der Stecknadel im Heuhaufen mehr Zeit in Anspruch nimmt als das Auffinden eines Wolkenkratzers in einer Plattenbau-Siedlung.
Ein sinnvolles Maß für die Performance muss also in jedem Fall die Menge der Daten, die unser Programm verarbeitet berücksichtigen.
Wir machen uns das Leben leicht!
In einem Programm werden unterschiedliche Operationen durchgehführt.
Es besteht aus Zuweisungen, arithmetischen Operationen und Vergleichen, die unterschiedlich schnell durchgeführt werden.
So ist ein Vergleich bespielsweise schneller ausführbar als eine arithmetische Operation.
Diese Unterschiede werden bei der groß O Notation vernachlässigt. Es ist egal, ob ein Programm vermehrt (aufwendige) arithmetische Operationen oder besonders viele (einfache) Vergleiche ausführt.
Bei der groß O Notation interessiert uns nicht einmal die Gesamtanzahl der auszuführenden Operationen. Alles was zählt ist der Anstieg der Zeitkomplexität in Abhängig von der Größe der Eingabedaten.
Das hat auch den Vorteil, dass wir den Einfluss der Hardware, auf der unser Programm läuft vernachlässigen können.
Worst case, average case oder best case Betrachtung?
Schauen wir uns folgende Methode an:
1: public static int konstantKomplex(int suchelement){ 2: int[] elemente = {4,6,8,2,5,10,11,14,13,19,15,3,34,23,9,7,47,39,21,99}; 3: for(int i = 0;i<elemente.length;i++){ 4: if(elemente[i] == suchelement){ 6: return i; 7: } 8: } 9: return -1; 10:}
Die Methode sucht in einem 20 elementigen Array nach dem im Parameter suchelement
gespeicherten Wert und liefert dessen Array-Position zurück. Im Fall, dass das gesuchte Element nicht im Array enthalten ist, wird der Wert -1 zurück geliefert.
Mit welcher Laufzeit ist im besten, mittleren und im schlechtesten Fall zu rechnen?
Die Zeitkomplexität unseres Suchproblems hängt davon ab, an welcher Position das Element, welches wir suchen im Array gespeichert ist.
Im besten Fall befindet sich das gesuchte Element an erster Position. In diesem Fall benötigen wir nämlich nur einen einzigen Vergleich und sind fertig. Somit lässt sich in unserem Beispiel der Wert 4
am leichtesten finden.
Unser Suchproblem ist von mittlerer Zeitkomplexität, wenn wir die 19
suchen. In diesem Fall müssen wir nämlich genau 10 Vergleiche durchführen. Also genau die Hälfte der vorhandenen Elemente durchlaufen.
Die schlechteste Performance weist unser Algorithmus auf, wenn wir ein Element suchen, das sich nicht im Array befindet. Dann muss nämlich die maximal mögliche Anzahl von 20 Vergleichen durchgeführt werden.
Auch wenn ich Anhänger einer optimistischen Lebensweise bin, müssen wir uns mit dem schlimmsten, den sogenannten worst case Szenario beschäftigen.
Denn genau das sind die Fälle, die den Server lahmlegen, den Anwender beim Support anrufen lassen und den Kunden zur Konkurrenz treiben.
Diese Vereinfachungen ermöglichen uns die Performance unseres Codes mit Hilfe der groß O Notation quantitativ zu bestimmen.
Dröseln wir das ganze mal anhand von einigen Beispielen auf.
Die wichtigsten Klassen der groß O Notation
Beginnen wir mit einem einfachen Beispiel!
Probleme konstanter Komplexität
public static int getZahl(int i){ int[] elemente = {4,6,8,2,5,10,11,14,13,19,15,3,34,23,9,7,47,39,21,99}; return elemente[i]; }
Diese Methode macht nichts weiter als den Wert an der Array-Postion i
zurück zuliefern.
Wie sieht es mit der Zeitkomplexität aus?
Um das Element an Position i
zu erhalten benötigen wir genau einen Zugriff.
Was passiert, wenn wir unsere Arraygröße von 20 auf 30 Elemente erweitern?
Genau nix! Wir benötigen immer noch genau einen Zugriff auf das Element i
.
Die Zeitkomplexität hängt also nicht von der Menge der betrachteten Daten ab. Deshalb sprechen wir in diesem Fall auch von einem Problem von konstanter Zeitkomplexität.
In der groß O Notation bezeichnen wir konstante Zeitkomplexität mit O(1).
Jetzt noch eine Quizfrage? Was ist die Komplexität des folgenden Codes?
System.out.println(getZahl(10)); System.out.println(getZahl(14));
Hier rufen wir unsere Methode zwei Mal hintereinander auf.
Was ist hier das Ergebnis der groß O Notation? Vielleicht O(2)?
Jepp! Allerdings ist O(1) = O(2) = O(2378754375). Das kannst du mir im Moment einfach glauben. Verstehen wirst du das in Kürze.
Bei Programmen von konstanter Zeitkomplexität ändert sich die Laufzeit des Programms bei zu nehmender Datenmenge also nicht.
Ein Programm, das bei einer Datenmengen von N=1
eine Laufzeit von einer Sekunde aufweist, benötigt auch bei einer Datenmenge von N = 10000
nur eine Sekunde.
Leider ist konstante Zeitkomplexität die Ausnahme.
Wenden wir uns der nächsten Komplexitätklasse zu!
Probleme mit linearer Komplexität
Das kennen wir schon!
Wir hatten in der Methode oben, in der wir in einem 20 elementigen Array nach einem bestimmten Wert gesucht haben festgestellt, dass wir im schlechtesten Fall 20 Vergleiche durchführen müssen.
Wie ändert sich die Situation, wenn wir das Array von 20 auf 30 Elemente erweitern?
Ganz genau! In diesem Fall benötigen wir im schlechtesten Fall 30 Vergleiche.
Die Komplexität unseres Problems wächst also linear mit der Datenmenge, weshalb wir von einem Problem mit linearer Komplexität sprechen.
Benötigt ein Programm von linearer Komplexität im schlechtesten für eine bestimmte Datenmenge 10 Sekunden, dann werden im worst case Szenario für die doppelte Datenmenge 20 Sekunden benötigt.
Mit Hilfe der groß O Notation ausgedrückt schreiben wir O(N).
Und wieder die selbe Quizfrage. Wie ändert sich die groß O Notation, wenn wir die Methode zweimal aufrufen?
Richtig!!! Es ist O(2N) und das ist das selbe wie O(N) oder O(10N).
Auf zur nächsten Komplexitätsklasse!
Probleme von quadratischer Komplexität!
Was ist die Komplexität folgenden Code-Schnipsel?
public static int quadratKomplex(int n){ 1: int sum = 0; 2: for(int i = 1; i<=n; i++){ 3: for(int j = 1;j<=n;j++){ 4: sum += i*j; 5: } 6: } 7: return sum; }
Was passiert hier?
Die Methode enthält zwei ineinander verschachtelte for Schleifen, die beide von 1 bis zum Parameter n laufen.
Mit jedem Durchlauf der Schleife in Zeile zwei, wird die Anweisung sum += i*j
n-mal in der inneren Schleife ausgeführt.
Insgesamt wird die Anweisung aus Zeile 4 also n*n = n2 mal ausgeführt und das Ergebnis der Methode ist die Summe aus den Produkten 1*1, 1*2…1*n,2*1,2*2..2*n,..n*n.
Diesen Aufwand nennt man quadratische Komplexität!
Und auch hier gilt wieder, wenn wir die Methode zweimal ausführen, so ist O(N2) = O(2*N2) = O(123*N2).
Wie verändert sich sich die Laufzeit bei Erhöhung von n
?
Quadratische Komplexität führt bei Verdopplung der Daten zu einer Vervierfachung, bei einer Verdreifachung zu einer Verneunfachung und bei einer Vervierfachung zu einer um den Faktor 16 größeren Laufzeit.
Wir können also festhalten, dass quadratische Komplexität unsere Ressourcen rasant zur Erschöpfung bringt.
Probleme von der Komplexität N*M
Sonderfall der quadratischen Komplexität ist die N*M Komplexität.
Ein Beispiel dieser Klasse erhalten wir durch eine einfache Modifikation der quadratKomplex
Methode von oben.
public static int nmKomplex(int n,int m){ int sum = 0; for(int i = 1; i<n; i++){ for(int j = 1;j<m;j++){ sum += i*j; } } return sum; }
In dieser Version haben die ineinander verschachtelten Schleifen unterschiedliche Endindizes.
Die Anweisung sum += i*j
wird n*m mal ausgeführt. Setzen wir n=m, so erhalten wir quadratische Komplexität.
Eine Verdopplung der Laufzeit entsteht, wenn wir entweder n oder m verdoppeln.
Ausgedrückt durch die O Notation schreiben wir O(N*M).
Probleme von logarithmischer Komplexität
Wenden wir uns der nächsten Komplexitätsklasse zu. Beginnen wir erneut mit einem Beispiel.
1: public static void logKomplex(int n){ 2: for(int i = 1;i<=n;i=i*2){ 3: System.out.println("Schleifenzähler: "+i); 4: } 5: }
Was ist die Komplexität dieser Methode?
Das besondere ist hier, dass wir in jedem Schleifendurchlauf die Zählervariable verdoppeln.
Überlegen wir uns wie oft die Programmausgabe in Zeile drei für n=10
erfolgt.
Hierfür müssen wir zunächst feststellen, wie viele Schleifendurchläufe stattfinden bis die Zählervariable i
einen Wert größer oder gleich n
annimmt.
Im ersten Schleifendurchlauf ist i=1
, im zweiten i=2
, im dritten i=4
und im vierten Durchlauf gilt i=8.
Der fünfte Schleifendurchlauf wird nicht durchgeführt, da dann i=16
also i>n
gilt.
Für n=10
finden also genau vier Schleifendurchläufe statt.
Wie können wir die Anzahl der Schleifendurchläufe formelmäßig angeben?
Schreiben wir die Werte der Zählervariable in einer etwas anderen Form.
Es ist i=1=20, i=2=21, i=4=22, i=8=23 und i=16=24.
Und genau diese Beobachtung können wir ausnutzen. Denn der Exponent zur Basis 2 können wir mir Hilfe des Logarithmus zur Basis zwei berechnen. So ist z.B. log(16) = 4 (Basis 2!).
In unserem Beispiel terminiert die for
Schleife sobald 2k > n für ein k gilt wobei k für die Anzahl der Schleifen-Durchläufe steht.
Nach unseren Vorüberlegungen gilt für die Anzahl der Schleifendurchläufe also k = log(n).
Hierbei haben wir allerdings eines zu beachten!
Die Anzahl der Schleifendurchläufe kann nur Ganzzahlig sein! Der Wertebereich des Logarithmus ist aber auf den reellen Zahlen definiert, daher ist das Ergebnis unserer Formel immer auf die nächste ganze Zahl aufzurunden.
Überprüfen wir die Formel für n=10
. Wir hatten bereits festgestellt, dass in diesem Fall vier Schleifendurchläufe stattfinden.
Und tatsächlich gilt log(10) = 3,321 was nach Aufrundung genau 4 ergibt.
Die Anzahl der Schleifendurchläufe nimmt also mit der Erhöhung von n
logarithmisch zu. In der O Notation ausgedrückt schreiben wir O(log(n)) und sprechen von logarithmischer Komplexität.
Interessant an dieser Klasse ist, dass die Logarithmusfunktion für große Werte nur noch geringfügig ansteigt und sich daher die Performance für große n
und sehr große n
nur noch geringfügig unterscheidet.
Die Rechenregeln der O Notation
Die O Notation ist also ein Größenmaß, an dem sich ablesen lässt wie sich die Performance bei zu nehmender Verarbeitungsmenge verändert.
Da bei kleinen Datenmengen die Performance-Frage uninteressant ist, nehmen wir die Verarbeitungsmenge N
als sehr groß an.
In der Theorie gibt es keine Einschränkung, weshalb wir einen mathematischen Grenzprozess durchführen und N
gegen unendlich gehen lassen.
Und hiermit lassen sich auch die von uns in den Beispielen gemachten Vereinfachungen erklären weshalb z.B. O(2N) = O(N) gilt.
Die Grenzwerte der Ausdrücke N, 2N, 56N..424N sind, wenn wir N gegen unendlich streben lassen alle gleich und zwar unendlich. Aus diesem Grund sind Konstanten bei der O Notation vernachlässigbar.
In der Praxis hat das den großen Vorteil, dass wir eine Funktion, deren Komplexität wir kennen, mehrfach aufrufen können ohne die O Notation zu verändern.
Aus der Tatsache, dass wir eine Grenzwertbetrachtung machen ergibt sich eine weitere wichtige Konsequenz.
Schauen wir uns mal folgenden Codeschnipsel an:
Was ist die Komplexität dieses Codes?
1: public static void asympDemo(int n){ 2: int sum = 0; 3: for(int i = 1;i<=n;i++){ 4: for(int j = 1;j<=n;j++){ 5: sum += i*j; 6: } 7: } 8: for(int i = 1;i<=n;i++){ 9: sum += i; 10: } 11:}
In den Zeilen drei bis sieben wird die Anweisung sum += i*j;
innerhalb zweier ineinander verschachtelter for-Schleifen
, die jeweils von 1
bis n
laufen N² mal ausgeführt.
Zum Abschluss (Zeile 8-10) wird noch die Anweisung sum += 1
n-mal ausgeführt
Insgesamt finden also N2+N Operationen statt.
Und da wir bei der O Notation eine Grenzwertbetrachtung machen, ist nur der Term mit der höchsten Potenz ausschlaggebend.
In unserem Fall können wir den linearen Term also vernachlässigen und wir erhalten O(N2).
Unsere Methode ist somit von quadratischer Komplexität.
Insgesamt können wir also zwei Rechenregeln für die O Notation festhalten:
- Konstanten können vernachlässigt werden. Es gilt O(cN) = O(N) und O(N+C) = O(N).
- Nur die jeweils größte Potenz einer Verabeitungsmenge spielt eine Rolle. Es ist O(Nm+Nk) = O(Nm), falls m>k.
Fazit: Die O Notation ist ein Werkzeug um die Performance von Programmen unabhängig von der zugrundeliegenden Hardware zu bewerten wodurch ein objektiver Vergleich von verschiedenen Algorithmen möglich wird. Zu beachten ist hier allerdings das die O Notation eine Worst-Case Betrachtung darstellt und daher die durchschnittliche Laufzeit eines Algorithmus in der Praxis deutlich besser sein kann.
Hast du Fragen? Dann ab damit in die Kommentare!
Hat dir der Artikel gefallen? Dann folge uns doch am besten gleich auf Facebook!
Lukas
5. Januar 2018 at 20:33Klasse erklärt – danke!
Kim Peter
17. Januar 2018 at 12:20Hi Lukas, sehr gerne! Viele Grüße Kim
Nikolas
23. März 2018 at 9:23Super Artikel, danke!
Kim Peter
23. März 2018 at 13:17Gerne!
Jürg
22. Januar 2018 at 19:41Hi Kim.
Danke für den tollen Artikel! Deine Seite macht spass.
Grüsse
Jürg
Kim Peter
27. Januar 2018 at 8:35Hi Jürg, ich danke dir! Viele Grüße Kim
Robin
29. Januar 2018 at 19:43Hey, super erklärt für die Klausur morgen. Ich danke dir!!!
LG Robin
Kim Peter
23. Februar 2018 at 21:28Vielen Dank für die Rückmeldung!
Vincent
19. Februar 2018 at 21:10Sehr präzise und einfach zu verstehende Erklärung, danke dir!!
Kim Peter
23. Februar 2018 at 21:25Gerne! Danke dir.
Becky
9. März 2018 at 9:53Bessere Erklärung gibt es nicht. Ich bin wirklich froh, Ihre Seite entdeckt zu haben :-).
Kim Peter
9. März 2018 at 21:20Vielen Dank für deine Rückmeldung. Ich freue mich sehr darüber! Viele Grüße Kim
Sercan
12. März 2018 at 0:21Ich glaube du hast bei logKomplex eine kleine Denkfehler eingebaut. Die for-schleife beginnt mit der Zahl 1 – 2 – 4 – 8 und terminiert beim 5. mit 16. Es wird nichtsdestotrotz vier mal in die Schleife reingesprungen, aber die For-Schleife verändert die Zählvariable immer nach dem ersten Durchlauf, daher sind die von dir vermuteten Ausgaben (2-4-8-12 <- da müsste dir es eig. schon auffallen), falsch. Vielleicht kannst du es ja korrigieren, damit es andere nicht verwirrt.
Grüße Sercan
Kim Peter
12. März 2018 at 7:05Hallo Sercan, danke für den Hinweis. Ich habe es korrigiert. Viele Grüße Kim
Abdulhasib
27. April 2018 at 18:44Die Erklärung ist aber großartig. ausführlich und einfach.
Vielen Dank!
Abdulhasib
Kim Peter
29. April 2018 at 16:18Ich danke dir!
Dagan
14. Juli 2018 at 13:54Hi,
könntest du noch ein Beitrag zum Thema Speicherplatzbedarf in Codes verfassen?
Kim Peter
8. September 2018 at 19:36Hi Dagan, ich werde sehen was ich tun kann.
Raufu
21. Juli 2018 at 6:36Hallo Kim,
Hast du auch ein Artikel zum Master Theorem?
Kim Peter
8. September 2018 at 19:34Hallo Raufu, aktuell leider nicht. Ehrlich gesagt erinnere ich mich auch nur noch dunkel an dieses Theorem. Viele Grüße Kim
Momo
2. August 2018 at 9:47Hey Kim, bin im 2. Semester Wirtschafts Informatik und deine Artikel helfen mir immer sehr! Teile deine Seite auch gerne mit Freunden, weil du die Themen nicht so „platt“ darstellst, wie sie manchmal sind.
Mach weiter so 🙂
Kim Peter
8. September 2018 at 19:33Hallo Momo, ich danke dir sehr!
Peter
2. September 2018 at 20:43Guter Artikel Danke! Nur das Video ist nicht mehr verfügbar
Kim Peter
8. September 2018 at 19:30Hallo Peter, vielen Dank! Ich habe den Link zu dem Video entfernt.
TSM_Alg | Andreas' Blog
21. September 2018 at 13:13[…] complexity Zeitkomplexität codeadventurer.de codeadventurer.de: Die O Notation. Wie schnell ist dein Code? How to analyse time complexity: Count your steps Time complexity of recursive functions [Master […]
Joel
1. Oktober 2018 at 16:50Hallo Kim. Super Artikel. Ich bin vielleicht etwas blöde aber ich komm nicht drauf, wie du O(n^2) und O(log n) ermittelst. Bei O(n^2) schreibst du 1*1, 1*2… 2*1, 2*2… 2*n, n*n. Ich weiss z. B. nicht, wie gross ein Array ist, und ob es vergrössert wird. Das sollte ja die Komplexität nicht verändern, wohl aber die Laufzeit. Wie kommst du mit oben beschriebenem Weg jetzt auf O(n^2) für mich ist das so: 1*1… *Magie* n*n
Kim Peter
4. Oktober 2018 at 7:33Hallo Joel, 1*1, 1*2… 2*1, 2*2… 2*n, n*n entspricht den Werte welche i und j in dem Ausdruck sum = i*j annehmen. Enstcheidend für die quadratische Komplexität ist, dass wir eine verschachtelte Schleife haben, bei der die Anzahl der Durchläufe sowohl in der Inneren als auch in der äußeren Schleife von dem Parameter n abhängt. Viele Grüße Kim
Elvire Fosso
25. Oktober 2018 at 14:33sehr hilfreich
Klasse sehr gut erklärt!!
Kim Peter
27. Oktober 2018 at 16:35Vielen Dank!
Ez Ez
22. Januar 2019 at 12:28Hat geholfen, danke
Kim Peter
22. Januar 2019 at 12:30Super! Das freut mich!
Flo
9. Februar 2019 at 16:47Was kann bei logarithmischer Komplexität vernachlässigt werden?
Wäre bspw
for(int a=1;a<=n;a++){
for(int i = 1;i<=n;i=i*2){
System.out.println("Schleifenzähler: "+i);
}
}
O(n*log(n)), oder nur O(log(n))?
Kim Peter
9. Februar 2019 at 19:40Hallo Flo, da es sich bei deinem Beispiel um eine verschachtelte Schleife handelt, ist die Komplexität O(n*log(n)). Viele Grüße Kim
Jennifer
18. Februar 2019 at 15:35Hammer Erklärung! Große Hilfe für die kommende Prüfung, danke!
Kim Peter
18. Februar 2019 at 20:02Hallo Jennifer, vielen Dank. Ich wünsche dir viel Erfolg für deine Prüfung. Viele Grüße Kim
Lukas
29. März 2019 at 21:22Hallo Kim;
Vielen Dank für die Erläuterungen, die Sie uns zum Thema Algorithmus gegeben haben. Ich habe 3 Fragen und würde mich freuen, wenn Sie mir helfen können.
1-Warum ist es meist nur theoretisch und nicht praktisch möglich Probleme der Komplexitätsklasse O(2n) durch ein Computerprogramm zu lösen
2-Wie verändert sich die Laufzeit eines Programms der Komplexitätsklasse O(2n) tendenziell, wenn die Menge der zu verarbeitenden Daten verdoppelt wird?
3-Warum kann ein Problem der Komplexitätsklasse O(n2) nicht mit einem Algorithmus der Komplexitätsklasse O(n) gelöst werden?
Danke Im Voraus:)
Lukas
Kim Peter
2. April 2019 at 7:33Hallo Lukas,
zunächst was allgemeines. Aus meiner Sicht gilt O(2n) = O(n). Meinst du vielleicht n^2 anstatt n2?
1.) Für große n laufen Algorithmen von linearer natürlich auch recht lange. Im wesentlichen bestehen Programme dieser Komplexität aus einer Schleife, die von 1 bis n läuft. Daher ist die Frage, welche Praxis relevanten Probleme von linearer Komplexität sind.
2.) Aus meiner Sicht steigt es um n.
3.) Komplexitätsklassen sind disjunkt. Ein Problem kann also nicht gleichzeitig n O(n) als auch in O(n^2) liegen.
Viele Grüße
Kim
ayhan
11. April 2019 at 11:28Hallo Kim, vielen Dank für den Artikel. Hat mir weitergeholfen. Eine Frage hätte ich doch. Wie kann man Aussagen über Laufzeitkomplexität mache? Die Laufzeit von xy beträgt mindestens O(n^2)? Vielen Dank im voraus.
Kim Peter
28. April 2019 at 16:46Hallo Ayhan, ich bin mir nicht sicher, ob ich deine Frage verstehe. Grundsätzlich hat n^2 immer etwas mit verschachtelten Schleifen zu tun. Viele Grüße Kim
Nils
12. April 2019 at 20:03Studiere medieninfo zweites Semester und saß heute den halben Tag daran zu verstehen, was der Prof. uns eigentlich sagen möchte, dann lese ich deinen Text und zack-schwuppdiwupp… geschnallt! Deshalb lasse ich Dankeschön hier.
Kim Peter
28. April 2019 at 16:41Hallo Nils, super das freut mich! Viele Grüße kim
Lukas
27. April 2019 at 14:22Hallo Lukas,
ja ich meine n^2 .
Ich habe nicht genug Worte, um mich bei dir zu bedanken. Vielen Dank für alles. Als ich deinen Artikel noch einmal las, habe ich endlich das Kapitel von O-Notation, Komplexitätsklassen verstanden.
Ich danke dir vielmals.
Lukas 🙂
Kim Peter
28. April 2019 at 16:29Super! Freue mich, dass du weitergekommen bist. Viele Grüße Kim
Erik
29. August 2019 at 19:29Top Kim! Mach weiter so! Sehr guter Artikel!
Grüße aus der Schweiz 🙂
Kim Peter
30. August 2019 at 6:10Vielen Dank Erik!
zizi
1. Mai 2020 at 19:47Hi Kim,
deutsch Sprache ist meine zweite Sprache und du hast sehr gut erklärt, nach der Vorlesung habe ich viele Seite durchgelesen aber soll ich dir sagen du hast PERFEKT erklärt. Danke dir
Kim Peter
1. Mai 2020 at 21:29Hallo Zizi, danke dir! Freue mich wenn ich weiterhelfen kann. Viele Grüße Kim
Zizi
11. Mai 2020 at 20:27Hi Kim,
hast du einen Artikel genau wie Laufzeit, über Speicherbedarf von Algorithmen?
Kim Peter
19. Mai 2020 at 18:29Hallo Zizi, nein leider nicht. Viele Grüße Ki
Maria
3. Mai 2020 at 16:06Hallo Kim,
ich finde die Erklärung einfach klasse, es ist wirklich einfach zu verstehen und hat mir viel geholfen. Bin aber trotzdem zu einer Aufgabe gekommen, wo ich gar nicht mehr weiß wie ich damit umgehen soll. Bei mit handelt es sich um verschachtelten Schleifen, die von einander abhängig sind, vielleicht kannst du mir helfen.Es sieht dann so aus:
for(int i=1; i<=n; i++)
for(int j=1; j<=i;j++)
b=b*j
ich verstehe schon dass die außere schreife n-Mal durchlauft. Was ist jetzt aber mit der innere? Sie wird sich doch jedes Mal, nach der Ausführung der erster ändern und i+1, i+2,i+3,… -mal laufen? So denke ich, aber komme doch nicht zu einer Lösung
Kim Peter
3. Mai 2020 at 19:07Hallo Maria, die innere Schleife und somit auch die Anweisung b = b*j wird 1 + 2 + 3 + 4 + 5…..+n mal durchlaufen. Diese Reihe kann mittels einer Formel beschrieben werden. Google hierfür einfach mal nach Gaußsche Summenformel. ;-). Die Rechenregeln für die O Notation auf diese Formel angewendet liefert dir die Lösung. Ich hoffe das hilft. Viele Grüße Kim
Choose a style: