it-swarm.com.de

Was ist eine einfache englische Erklärung der "Big O" -Notation?

Ich würde möglichst wenig formale Definition und einfache Mathematik vorziehen.

4686
Arec Barrwin

Kurz gesagt, dies ist mit ziemlicher Sicherheit eine Verwechslung von Big O-Notation (obere Schranke) und Theta-Notation "Θ" (zweiseitige Schranke). Nach meiner Erfahrung ist dies eigentlich typisch für Diskussionen in einem nicht-akademischen Umfeld. Wir entschuldigen uns für die entstandene Verwirrung.


Die Big O-Komplexität kann mit diesem Diagramm dargestellt werden:

Big O Analysis

Die einfachste Definition, die ich für die Big-O-Notation geben kann, ist folgende:

Die Big-O-Notation ist eine relative Darstellung der Komplexität eines Algorithmus.

Es gibt einige wichtige und bewusst ausgewählte Wörter in diesem Satz:

  • relativ: Sie können nur Äpfel mit Äpfeln vergleichen. Sie können einen Algorithmus zur arithmetischen Multiplikation nicht mit einem Algorithmus vergleichen, der eine Liste von ganzen Zahlen sortiert. Ein Vergleich von zwei Algorithmen für arithmetische Operationen (eine Multiplikation, eine Addition) ergibt jedoch etwas Bedeutendes.
  • Darstellung: Big-O (in seiner einfachsten Form) reduziert den Vergleich zwischen Algorithmen auf eine einzige Variable. Diese Variable wird basierend auf Beobachtungen oder Annahmen ausgewählt. Beispielsweise werden Sortieralgorithmen typischerweise auf der Grundlage von Vergleichsoperationen verglichen (Vergleichen von zwei Knoten, um ihre relative Reihenfolge zu bestimmen). Dies setzt voraus, dass der Vergleich teuer ist. Aber was ist, wenn der Vergleich billig und das Tauschen teuer ist? Es ändert den Vergleich; und
  • Komplexität: Wenn ich eine Sekunde brauche, um 10.000 Elemente zu sortieren, wie lange brauche ich, um eine Million zu sortieren? Komplexität ist in diesem Fall ein relatives Maß für etwas anderes.

Kommen Sie zurück und lesen Sie das Obige noch einmal, wenn Sie den Rest gelesen haben.

Das beste Beispiel für Big-O ist das Rechnen. Nehmen Sie zwei Nummern (123456 und 789012). Die Grundrechenarten, die wir in der Schule gelernt haben, waren:

  • zusatz;
  • subtraktion;
  • multiplikation; und
  • einteilung.

Jedes davon ist eine Operation oder ein Problem. Eine Methode zur Lösung dieser Probleme wird als Algorithmus bezeichnet.

Addition ist die einfachste. Sie richten die Zahlen (rechts) aus und fügen die Ziffern in eine Spalte ein, in der die letzte Zahl dieser Addition im Ergebnis steht. Der Zehner-Teil dieser Zahl wird in die nächste Spalte übertragen.

Angenommen, die Addition dieser Zahlen ist die teuerste Operation in diesem Algorithmus. Es liegt auf der Hand, dass wir zum Addieren dieser beiden Zahlen 6 Ziffern addieren müssen (und möglicherweise eine 7 tragen). Wenn wir zwei 100-stellige Zahlen addieren, müssen wir 100 Additionen durchführen. Wenn wir zwei 10.000-stellige Zahlen addieren, müssen wir 10.000 Additionen durchführen.

Sehen Sie das Muster? Die Komplexität (ist die Anzahl der Operationen) ist direkt proportional zur Anzahl der Ziffern n in der größere Anzahl. Wir nennen dies O (n) oder lineare Komplexität .

Die Subtraktion ist ähnlich (mit der Ausnahme, dass Sie möglicherweise etwas ausleihen müssen, anstatt etwas zu tragen).

Multiplikation ist anders. Sie stellen die Zahlen in einer Reihe auf, nehmen die erste Ziffer der unteren Ziffer und multiplizieren sie der Reihe nach mit jeder Ziffer der oberen Ziffer und so weiter durch jede Ziffer. Um also unsere zwei 6-stelligen Zahlen zu multiplizieren, müssen wir 36 Multiplikationen durchführen. Möglicherweise müssen bis zu 10 oder 11 Spalten hinzugefügt werden, um das Endergebnis zu erhalten.

Wenn wir zwei 100-stellige Zahlen haben, müssen wir 10.000 Multiplikationen und 200 Additionen durchführen. Für zwei einstellige Zahlen von einer Million brauchen wir eine Billion (1012) Multiplikationen und zwei Millionen Additionen.

Da der Algorithmus mit n - im Quadrat skaliert, ist dies O (n2) oder quadratische Komplexität . Dies ist ein guter Zeitpunkt, um ein weiteres wichtiges Konzept vorzustellen:

Wir kümmern uns nur um den wichtigsten Teil der Komplexität.

Der Kluge hat vielleicht erkannt, dass wir die Anzahl der Operationen folgendermaßen ausdrücken können: n2 + 2n. Wie Sie jedoch in unserem Beispiel mit zwei Zahlen von jeweils einer Million Stellen gesehen haben, wird der zweite Term (2n) unbedeutend (er macht zu diesem Zeitpunkt 0,0002% der Gesamtoperationen aus).

Man kann feststellen, dass wir hier das Worst-Case-Szenario angenommen haben. Wenn Sie 6-stellige Zahlen multiplizieren, wenn eine von ihnen 4-stellig und die andere 6-stellig ist, haben Sie nur 24 Multiplikationen. Dennoch berechnen wir das Worst-Case-Szenario für dieses 'n', d. H. Wenn beide 6-stellige Zahlen sind. Daher handelt es sich bei der Big-O-Notation um das Worst-Case-Szenario eines Algorithmus

Das Telefonbuch

Das nächstbeste Beispiel, an das ich denken kann, ist das Telefonbuch, normalerweise White Pages oder ähnliches, aber es wird von Land zu Land unterschiedlich sein. Aber ich spreche von dem, der die Leute nach Nachnamen und dann nach Initialen oder Vornamen, möglicherweise nach Adresse und dann nach Telefonnummern auflistet.

Wenn Sie einen Computer anweisen würden, die Telefonnummer für "John Smith" in einem Telefonbuch mit 1.000.000 Namen nachzuschlagen, was würden Sie dann tun? Was würden Sie tun, wenn Sie die Tatsache ignorieren, dass Sie erraten könnten, wie weit die S-Phase begonnen hat (nehmen wir an, Sie können nicht)?

Eine typische Implementierung könnte darin bestehen, sich zur Mitte zu öffnen, die 500.000 zu nehmenth und vergleiche es mit "Smith". Wenn es "Smith, John" ist, haben wir echt Glück gehabt. Viel wahrscheinlicher ist, dass "John Smith" vor oder nach diesem Namen steht. Wenn es danach ist, teilen wir die letzte Hälfte des Telefonbuchs in zwei Hälften und wiederholen. Wenn es vorher ist, teilen wir die erste Hälfte des Telefonbuchs in zwei Hälften und wiederholen. Und so weiter.

Dies wird als binäre Suche bezeichnet und wird täglich beim Programmieren verwendet, unabhängig davon, ob Sie dies realisieren oder nicht.

Wenn Sie also einen Namen in einem Telefonbuch mit einer Million Namen suchen möchten, können Sie tatsächlich jeden Namen finden, indem Sie dies höchstens 20 Mal tun. Beim Vergleich von Suchalgorithmen stellen wir fest, dass dieser Vergleich unser 'n' ist.

  • Für ein Telefonbuch mit 3 Namen sind (höchstens) 2 Vergleiche erforderlich.
  • Für 7 dauert es höchstens 3.
  • Für 15 dauert es 4.
  • Für 1.000.000 braucht es 20.

Das ist erstaunlich gut, nicht wahr?

In Big-O-Begriffen ist dies O (log n) oder logarithmische Komplexität . Nun könnte der fragliche Logarithmus ln (Basis e), log sein10, log2 oder eine andere Basis. Es ist egal, es ist immer noch O (log n) genau wie O (2n2) und O (100n2) sind immer noch beide O (n2).

Es lohnt sich an dieser Stelle zu erklären, dass mit Big O drei Fälle mit einem Algorithmus bestimmt werden können:

  • Bester Fall: In der Telefonbuchsuche ist der beste Fall, dass wir den Namen in einem Vergleich finden. Dies ist O (1) oder konstante Komplexität ;
  • Erwarteter Fall: Wie oben erläutert, ist dies O (log n); und
  • Schlimmster Fall: Dies ist auch O (log n).

Normalerweise kümmern wir uns nicht um den besten Fall. Wir interessieren uns für den erwarteten und den schlimmsten Fall. Manchmal ist das eine oder andere wichtiger.

Zurück zum Telefonbuch.

Was ist, wenn Sie eine Telefonnummer haben und einen Namen suchen möchten? Die Polizei hat ein Reverse-Telefonbuch, aber solche Nachschlageversuche werden der Öffentlichkeit verweigert. Oder sind Sie? Technisch gesehen können Sie eine Nummer in einem normalen Telefonbuch umkehren. Wie?

Sie beginnen beim Vornamen und vergleichen die Nummer. Wenn es ein Match ist, großartig, wenn nicht, geht es weiter mit dem nächsten. Sie müssen dies auf diese Weise tun, da das Telefonbuch ungeordnet ist (auf jeden Fall nach Telefonnummer).

So finden Sie einen Namen anhand der Telefonnummer (Reverse Lookup):

  • Bester Fall: O (1);
  • Erwarteter Fall: O(n) (für 500.000); und
  • Schlimmster Fall: O(n) (für 1.000.000).

Der reisende Verkäufer

Dies ist ein sehr bekanntes Problem in der Informatik und verdient eine Erwähnung. In diesem Problem haben Sie N Städte. Jede dieser Städte ist durch eine Straße von einer bestimmten Entfernung mit einer oder mehreren anderen Städten verbunden. Das Problem des Handlungsreisenden besteht darin, die kürzeste Tour zu finden, die jede Stadt besucht.

Hört sich einfach an? Denk nochmal.

Wenn Sie 3 Städte A, B und C mit Straßen zwischen allen Paaren haben, können Sie gehen:

  • A → B → C
  • A → C → B
  • B → C → A
  • B → A → C
  • C → A → B
  • C → B → A

Nun, eigentlich gibt es weniger als das, weil einige davon gleichwertig sind (A → B → C und C → B → A sind gleichwertig, zum Beispiel, weil sie die gleichen Straßen benutzen, nur in umgekehrter Richtung).

Tatsächlich gibt es 3 Möglichkeiten.

  • Nehmen Sie dies zu 4 Städten und Sie haben (iirc) 12 Möglichkeiten.
  • Mit 5 ist es 60.
  • 6 wird 360.

Dies ist eine Funktion einer mathematischen Operation, die als Fakultät bezeichnet wird. Grundsätzlich gilt:

  • 5! = 5 × 4 × 3 × 2 × 1 = 120
  • 6! = 6 × 5 × 4 × 3 × 2 × 1 = 720
  • 7! = 7 × 6 × 5 × 4 × 3 × 2 × 1 = 5040
  • 25! = 25 × 24 ×… × 2 × 1 = 15.511.210.043.330.985.984.000.000
  • 50! = 50 × 49 ×… × 2 × 1 = 3,04140932 × 1064

Das Big-O des Travelling Salesman-Problems ist also O (n!) oder faktorielle oder kombinatorische Komplexität .

Wenn Sie 200 Städte erreichen, ist im Universum nicht mehr genug Zeit, um das Problem mit herkömmlichen Computern zu lösen.

Etwas zum Nachdenken.

Polynomzeit

Ein weiterer Punkt, den ich kurz erwähnen wollte, ist, dass jeder Algorithmus eine Komplexität von O (nein) soll polynomielle Komplexität haben oder ist lösbar in polynomieller Zeit .

O (n), O (n2) usw. sind alle Polynomzeiten. Einige Probleme können in der Polynomzeit nicht gelöst werden. Aus diesem Grund werden bestimmte Dinge in der Welt benutzt. Public Key Cryptography ist ein Paradebeispiel. Es ist rechnerisch schwierig, zwei Primfaktoren einer sehr großen Zahl zu finden. Wenn dies nicht der Fall wäre, könnten wir die von uns verwendeten öffentlichen Schlüsselsysteme nicht verwenden.

Wie auch immer, das ist es für meine (hoffentlich einfache englische) Erklärung von Big O (überarbeitet).

6433
cletus

Es zeigt, wie ein Algorithmus skaliert. 

Auf2) : bekannt als quadratische Komplexität

  • 1 Artikel: 1 Sekunde
  • 10 Gegenstände: 100 Sekunden
  • 100 Elemente: 10000 Sekunden

Beachten Sie, dass sich die Anzahl der Elemente um den Faktor 10 erhöht, die Zeit jedoch um den Faktor 10 erhöht2. Im Grunde ist n = 10 und so O (n2) gibt uns den Skalierungsfaktor n2 Welches ist 102.

O(n) : bekannt als lineare Komplexität

  • 1 Artikel: 1 Sekunde 
  • 10 Gegenstände: 10 Sekunden
  • 100 Elemente: 100 Sekunden

Diesmal erhöht sich die Anzahl der Elemente um den Faktor 10 und damit auch die Zeit. n = 10 und so ist der Skalierungsfaktor von O (n) 10.

O(1) : bekannt als Konstante Komplexität

  • 1 Artikel: 1 Sekunde
  • 10 Elemente: 1 Sekunde
  • 100 Elemente: 1 Sekunde

Die Anzahl der Elemente steigt immer noch um den Faktor 10, der Skalierungsfaktor von O(1) ist jedoch immer 1.

O (log n) : bekannt als logarithmische Komplexität

  • 1 Artikel: 1 Sekunde
  • 10 Gegenstände: 2 Sekunden
  • 100 Elemente: 3 Sekunden
  • 1000 Gegenstände: 4 Sekunden
  • 10000 Gegenstände: 5 Sekunden

Die Anzahl der Berechnungen wird nur um ein Protokoll des Eingabewerts erhöht. Wenn in diesem Fall angenommen wird, dass jede Berechnung 1 Sekunde dauert, ist das Protokoll der Eingabe n die erforderliche Zeit, also log n.

Das ist der Kern davon. Sie reduzieren die Mathematik, so dass es nicht genau n sein kann2 oder was auch immer sie sagen, das ist der dominierende Faktor bei der Skalierung.

686
Ray Hidayat

Die Big-O-Notation (auch als "asymptotische Wachstumsnotation" bezeichnet) ist wie Funktionen "aussehen", wenn Sie konstante Faktoren und ähnliches in der Nähe des Ursprungs ignorieren . Wir verwenden es, um darüber zu sprechen , wie das Ding skaliert .


Grundlagen

für "ausreichend" große Eingaben ...

  • f(x) ∈ O(upperbound) bedeutet f "wächst nicht schneller als" upperbound
  • f(x) ∈ Ɵ(justlikethis) mean f "wächst genau wie" justlikethis
  • f(x) ∈ Ω(lowerbound) bedeutet f "wächst nicht langsamer als" lowerbound

die Big-O-Notation kümmert sich nicht um konstante Faktoren: Die Funktion 9x² soll "genau so wachsen wie" 10x². Weder kümmert sich big-O asymptotic Notation um non-asymptotic Zeug ("Zeug in der Nähe des Ursprungs" oder "Was passiert, wenn das Problemgröße ist klein "): Die Funktion 10x² soll" genau so wachsen wie "10x² - x + 2.

Warum sollten Sie die kleineren Teile der Gleichung ignorieren? Weil sie durch die großen Teile der Gleichung völlig in den Schatten gestellt werden, wenn man immer größere Maßstäbe betrachtet. ihr Beitrag wird unwichtig und irrelevant. (Siehe Beispielabschnitt.)

Anders ausgedrückt, es dreht sich alles um das Verhältnis , wenn Sie bis ins Unendliche gehen. Wenn Sie die tatsächliche Zeit durch O(...) dividieren, erhalten Sie einen konstanten Faktor für die Begrenzung großer Eingaben. Intuitiv ist dies sinnvoll: Funktionen "skalieren" sich, wenn Du kannst eins multiplizieren, um das andere zu erhalten. Das heißt, wenn wir sagen ...

actualAlgorithmTime(N) ∈ O(bound(N))
                                       e.g. "time to mergesort N elements 
                                             is O(N log(N))"

... das bedeutet, dass für "groß genug" Problemgrößen N (wenn wir Sachen in der Nähe ignorieren den Ursprung) gibt es eine Konstante (zB 2.5, vollständig gebildet), so dass:

actualAlgorithmTime(N)                 e.g. "mergesort_duration(N)       "
────────────────────── < constant            ───────────────────── < 2.5 
       bound(N)                                    N log(N)         

Es gibt viele Möglichkeiten der Konstante; oft ist die "beste" Wahl als "konstanter Faktor" des Algorithmus bekannt ... aber wir ignorieren sie oft so, als würden wir nicht-größte Begriffe ignorieren (siehe Abschnitt "Konstante Faktoren", warum sie normalerweise keine Rolle spielen). Sie können sich die obige Gleichung auch als eine Grenze vorstellen, die besagt: " Im schlimmsten Fall wird die Zeit, die benötigt wird, niemals schlechter sein als ungefähr N*log(N), innerhalb eines Faktors von 2,5 (ein konstanter Faktor, den wir nicht berücksichtigen) ist mir egal) ".

Im Allgemeinen ist O(...) am nützlichsten, da es uns oft um Worst-Case-Verhalten geht. Wenn f(x) etwas "Schlechtes" wie Prozessor- oder Speichernutzung darstellt, bedeutet "f(x) ∈ O(upperbound)" "upperbound ist das Worst-Case-Szenario für Prozessor-/Speichernutzung".


Bewerbungen

Als rein mathematisches Konstrukt beschränkt sich die Big-O-Notation nicht darauf, über Verarbeitungszeit und Speicher zu sprechen. Sie können es verwenden, um die Asymptotik von Objekten zu diskutieren, bei denen Skalierung von Bedeutung ist, z. B .:

  • die Anzahl möglicher Handshakes unter N Personen auf einer Party (Ɵ(N²), speziell N(N-1)/2, aber wichtig ist, dass es "skaliert wie" )
  • probabilistisch erwartete Anzahl von Menschen, die etwas virales Marketing als Funktion der Zeit gesehen haben
  • wie die Website-Latenz mit der Anzahl der Verarbeitungseinheiten in einer CPU, einer GPU oder einem Computercluster skaliert
  • wie die Wärmeabgabe auf der CPU in Abhängigkeit von der Anzahl der Transistoren, der Spannung usw. ansteigt.
  • wie viel Zeit ein Algorithmus für die Ausführung benötigt, hängt von der Eingabegröße ab
  • wie viel Speicherplatz ein Algorithmus benötigt, hängt von der Eingabegröße ab

Beispiel

Im obigen Handshake-Beispiel schüttelt jeder in einem Raum die Hand aller anderen. In diesem Beispiel #handshakes ∈ Ɵ(N²). Warum?

Sichern Sie sich ein bisschen: Die Anzahl der Handshakes ist genau n-choose-2 oder N*(N-1)/2 (jede von N Personen schüttelt die Hände von N-1 anderen Personen, aber diese Handshakes werden doppelt gezählt, dividieren Sie dies durch 2):

everyone handshakes everyone else. Image credit and license per wikipedia/wikimedia commons "complete graph" article.adjacency matrix

Bei einer sehr großen Anzahl von Personen wird der lineare Ausdruck N jedoch in den Schatten gestellt und trägt effektiv 0 zum Verhältnis bei (in der Grafik: Der Anteil leerer Kästchen in der Diagonale an der Gesamtzahl der Kästchen wird mit zunehmender Teilnehmerzahl kleiner größer). Daher ist das Skalierungsverhalten order N², oder die Anzahl der Handshakes "wächst wie N²".

#handshakes(N)
────────────── ≈ 1/2
     N²

Es ist, als ob die leeren Kästchen auf der Diagonale des Diagramms (N * (N-1)/2 Häkchen) nicht einmal da wären (N2 Häkchen asymptotisch).

(vorübergehender Exkurs von "Plain English" :) Wenn Sie dies selbst beweisen möchten, können Sie eine einfache Algebra für das Verhältnis durchführen, um es in mehrere Terme aufzuteilen. (lim bedeutet "berücksichtigt im Grenzwert von". Ignoriere es einfach, wenn du es nicht gesehen hast, es ist nur die Notation für "und N ist wirklich wirklich groß"):

    N²/2 - N/2         (N²)/2   N/2         1/2
lim ────────── = lim ( ────── - ─── ) = lim ─── = 1/2
N→∞     N²       N→∞     N²     N²      N→∞  1
                               ┕━━━┙
             this is 0 in the limit of N→∞:
             graph it, or plug in a really large number for N

tl; dr: Die Anzahl der Handshakes 'sieht so sehr nach' x² aus, dass wir, wenn wir das Verhältnis # handshakes/x² aufschreiben würden, die Tatsache, dass wir es nicht brauchen genau x²-Handshakes werden für eine willkürlich lange Zeit nicht einmal in der Dezimalzahl angezeigt.

z.B. für x = 1 Million, Verhältnis # Handshakes/x²: 0,499999 ...


Bauintuition

So können wir Aussagen treffen wie ...

Msgstr "Für ausreichend große Eingangsgröße = N, egal was der konstante Faktor ist, wenn I double die Eingabegröße ...

  • ... Ich verdopple die Zeit, die ein O(N) ("lineare Zeit") - Algorithmus benötigt. "

    N → (2N) = 2 (N)

  • ... Ich habe die Zeit, die ein O (N²) -Algorithmus ("quadratische Zeit") benötigt, doppelt quadriert (vervierfacht). " (z. B. dauert ein 100x so großes Problem 100² = 10000x so lange ... möglicherweise nicht nachhaltig)

    → (2N) ² = 4 ()

  • ... Ich habe die Zeit, die ein O (N³) ("kubische Zeit") Algorithmus benötigt, doppelt gewürfelt (Oktupel). " (z. B. ein 100x so großes Problem dauert 100³ = 1000000x so lang ... sehr nicht nachhaltig)

    cN³ → c (2N) ³ = 8 ( cN³ )

  • ... Ich addiere einen festen Betrag zu der Zeit, die ein O(log(N)) ("logarithmische Zeit") - Algorithmus benötigt. " (billig!)

    c log (N) → c log (2N) = (c log (2)) + ( c log (N) ) = (fester Betrag) + ( c log (N) )

  • ... Ich ändere nicht die Zeit, die ein O(1) ("konstante Zeit") - Algorithmus benötigt. " (das günstigste!)

    c * 1 c * 1

  • ... Ich "verdopple" (im Grunde genommen) die Zeit, die ein O (N log (N)) - Algorithmus benötigt. " (ziemlich häufig)

    es ist weniger als O (N1.000001), die Sie möglicherweise grundsätzlich linear nennen

  • Ich verlängere auf lächerliche Weise die Zeit a O (2N) ("exponentielle Zeit") benötigt den Algorithmus. " (Sie würden die Zeit verdoppeln (oder verdreifachen usw.), indem Sie das Problem nur um eine Einheit erhöhen)

    2N → 22N = (4N) ............ anders ausgedrückt ...... 2N → 2N + 1 = 2N21 = 2 2N

[für die mathematisch geneigten, können Sie für kleinere Nebenbemerkungen mit der Maus über die Spoiler fahren]

(mit gutschrift auf https://stackoverflow.com/a/487292/711085 )

(Technisch könnte der konstante Faktor in einigen esoterischeren Beispielen von Bedeutung sein, aber ich habe die obigen Aussagen gemacht (z. B. in log (N)), sodass dies nicht der Fall ist.)

Dies sind die grundlegenden Wachstumsregeln, die von Programmierern und angewandten Informatikern als Bezugspunkte verwendet werden. Sie sehen diese die ganze Zeit. (Man könnte also technisch denken: "Durch Verdoppeln der Eingabe wird ein O (√N) -Algorithmus um das 1,414-fache langsamer." Es ist jedoch besser, dies als "schlechter als logarithmisch, aber besser als linear" zu betrachten.)


Konstante Faktoren

Normalerweise ist es uns egal, welche spezifischen konstanten Faktoren vorliegen, da sie die Art und Weise, wie die Funktion wächst, nicht beeinflussen. Beispielsweise können zwei Algorithmen O(N) Zeit in Anspruch nehmen, aber einer ist möglicherweise doppelt so langsam wie der andere. Es ist uns normalerweise egal, es sei denn, der Faktor ist sehr groß, da die Optimierung ein heikles Geschäft ist ( Wann ist die Optimierung verfrüht? ); Auch das bloße Auswählen eines Algorithmus mit einem besseren Big-O verbessert die Leistung häufig um Größenordnungen.

Einige asymptotisch überlegene Algorithmen (z. B. eine nicht vergleichbare O(N log(log(N)))-Sortierung) können einen so großen konstanten Faktor (z. B. 100000*N log(log(N))) oder einen relativ großen Overhead wie O(N log(log(N))) mit einem verborgenen + 100*N aufweisen, dass es sich selten lohnt, selbst einen zu verwenden "Große Daten".


Warum O(N) manchmal das Beste ist, was Sie tun können, d. H. Warum wir Datenstrukturen benötigen

O(N)-Algorithmen sind in gewisser Hinsicht die "besten" Algorithmen, wenn Sie alle Ihre Daten lesen müssen. Das Lesen einer Datenmenge ist eine O(N)-Operation. Das Laden in den Speicher ist normalerweise O(N) (oder schneller, wenn Sie Hardwareunterstützung haben, oder gar keine Zeit, wenn Sie die Daten bereits gelesen haben). Wenn Sie jedoch bei jedem Datenelement (oder sogar bei jedem anderen Datenelement) look berühren, benötigt Ihr Algorithmus O(N) Zeit, um dieses Suchen durchzuführen. Unabhängig davon, wie lange Ihr tatsächlicher Algorithmus dauert, ist er mindestens O(N), da er diese Zeit damit verbracht hat, alle Daten zu untersuchen.

Gleiches gilt für den Akt des Schreibens . Alle Algorithmen, die N Dinge ausgeben, benötigen N Zeit, da die Ausgabe mindestens so lang ist (z. B. ist das Ausdrucken aller Permutationen (Möglichkeiten zum Neuanordnen) eines Satzes von N Spielkarten faktoriell: O(N!)).

Dies motiviert die Verwendung von Datenstrukturen : Eine Datenstruktur erfordert nur ein einziges Lesen der Daten (normalerweise O(N) time) sowie eine beliebige Menge an Vorverarbeitung (z. B. O(N) oder O(N log(N)) oder O(N²)), die wir versuchen, klein zu halten. Danach dauert das Ändern der Datenstruktur (Einfügen/Löschen/usw.) und das Ausführen von Abfragen zu den Daten nur sehr wenig, z. B. O(1) oder O(log(N)). Anschließend führen Sie eine große Anzahl von Abfragen durch! Im Allgemeinen gilt: Je mehr Arbeit Sie bereit sind, umso weniger Arbeit müssen Sie später erledigen.

Angenommen, Sie hatten die Breiten- und Längengradkoordinaten von Millionen von Straßensegmenten und wollten alle Straßenkreuzungen finden.

  • Naive Methode: Wenn Sie die Koordinaten einer Straßenkreuzung hätten und nahe gelegene Straßen untersuchen wollten, müssten Sie jedes Mal die Millionen von Segmenten durchgehen und jedes auf Angrenzung prüfen.
  • Wenn Sie dies nur einmal tun müssten, wäre es kein Problem, die naive Methode O(N) nur einmal ausführen zu müssen, aber wenn Sie dies mehrmals tun möchten (in diesem Fall N einmal Für jedes Segment müssten wir O(N²) arbeiten, oder 1000000² = 1000000000000 Operationen. Nicht gut (ein moderner Computer kann ungefähr eine Milliarde Operationen pro Sekunde ausführen).
  • Wenn wir eine einfache Struktur verwenden, die als Hash-Tabelle bezeichnet wird (eine Instant-Speed-Lookup-Tabelle, auch als Hashmap oder Dictionary bezeichnet), zahlen wir einen geringen Aufwand, indem wir alles in O(N)-Zeit vorverarbeiten. Danach dauert es im Durchschnitt nur noch eine konstante Zeit, um etwas anhand seines Schlüssels nachzuschlagen (in diesem Fall sind unsere Schlüssel die Breiten - und Längenkoordinaten, gerundet in ein Gitter; wir suchen in den benachbarten Gitterbereichen, von denen es nur 9 gibt, was a ist) Konstante).
  • Unsere Aufgabe ging von einer unmöglichen O(N²) zu einer überschaubaren O(N), und alles, was wir tun mussten, war geringe Kosten für die Erstellung eines Hash-Tisches zu bezahlen.
  • Analogie : Die Analogie in diesem speziellen Fall ist ein Puzzle: Wir haben eine Datenstruktur erstellt, die einige Eigenschaften der Daten ausnutzt. Wenn unsere Straßensegmente wie Puzzleteile sind, gruppieren wir sie nach Farbe und Muster. Dies wird dann ausgenutzt, um spätere zusätzliche Arbeiten zu vermeiden (Vergleich von Puzzleteilen gleicher Farbe untereinander und nicht mit jedem einzelnen Puzzleteil).

Die Moral der Geschichte: Eine Datenstruktur beschleunigt die Abläufe. Mit noch fortschrittlicheren Datenstrukturen können Sie Operationen auf unglaublich clevere Weise kombinieren, verzögern oder sogar ignorieren. Unterschiedliche Probleme hätten unterschiedliche Analogien, aber sie würden alle die Organisation der Daten in einer Weise beinhalten, die eine Struktur ausnutzt, die uns am Herzen liegt, oder die wir künstlich für die Buchhaltung auferlegt haben. Wir arbeiten im Voraus (im Grunde planen und organisieren) und jetzt sind wiederholte Aufgaben viel einfacher!


Praktisches Beispiel: Visualisierung von Wachstumsordnungen beim Codieren

Die asymptotische Notation ist in ihrem Kern völlig unabhängig von der Programmierung. Die asymptotische Notation ist ein mathematischer Rahmen zum Überlegen, wie sich die Dinge skalieren lassen, und kann in vielen verschiedenen Bereichen verwendet werden. Das heißt ... auf diese Weise können Sie asymptotische Notation auf die Codierung anwenden.

Die Grundlagen: Wann immer wir mit jedem Element in einer Sammlung der Größe A interagieren (wie einem Array, einer Menge, allen Schlüsseln einer Karte usw.) oder A-Iterationen einer Schleife ausführen, ist dies ein multiplikativer Faktor der Größe A Warum sage ich "einen multiplikativen Faktor"? - weil Schleifen und Funktionen (fast per Definition) eine multiplikative Laufzeit haben: die Anzahl der Iterationen, die Anzahl der in der Schleife durchgeführten Arbeiten (oder für Funktionen: die Anzahl der Aufrufe von Funktion, Zeiten der Arbeit in der Funktion). (Dies gilt, wenn wir nichts Besonderes tun, wie z. B. Schleifen überspringen oder die Schleife vorzeitig verlassen oder den Steuerungsfluss in der Funktion anhand von Argumenten ändern, was sehr häufig vorkommt.) Hier einige Beispiele für Visualisierungstechniken mit zugehörigem Pseudocode.

(Hier stehen die xs für zeitlich konstante Arbeitseinheiten, Prozessoranweisungen, Interpreter-Opcodes usw.)

for(i=0; i<A; i++)        // A * ...
    some O(1) operation     // 1

--> A*1 --> O(A) time

visualization:

|<------ A ------->|
1 2 3 4 5 x x ... x

other languages, multiplying orders of growth:
  javascript, O(A) time and space
    someListOfSizeA.map((x,i) => [x,i])               
  python, O(rows*cols) time and space
    [[r*c for c in range(cols)] for r in range(rows)]

Beispiel 2:

for every x in listOfSizeA:   // A * (...
    some O(1) operation         // 1
    some O(B) operation         // B
    for every y in listOfSizeC: // C * (...
        some O(1) operation       // 1))

--> O(A*(1 + B + C))
    O(A*(B+C))        (1 is dwarfed)

visualization:

|<------ A ------->|
1 x x x x x x ... x

2 x x x x x x ... x ^
3 x x x x x x ... x |
4 x x x x x x ... x |
5 x x x x x x ... x B  <-- A*B
x x x x x x x ... x |
................... |
x x x x x x x ... x v

x x x x x x x ... x ^
x x x x x x x ... x |
x x x x x x x ... x |
x x x x x x x ... x C  <-- A*C
x x x x x x x ... x |
................... |
x x x x x x x ... x v

Beispiel 3:

function nSquaredFunction(n) {
    total = 0
    for i in 1..n:        // N *
        for j in 1..n:      // N *
            total += i*k      // 1
    return total
}
// O(n^2)

function nCubedFunction(a) {
    for i in 1..n:                // A *
        print(nSquaredFunction(a))  // A^2
}
// O(a^3)

Wenn wir etwas etwas kompliziertes machen, können Sie sich vielleicht noch visuell vorstellen, was los ist:

for x in range(A):
    for y in range(1..x):
        simpleOperation(x*y)

x x x x x x x x x x |
x x x x x x x x x   |
x x x x x x x x     |
x x x x x x x       |
x x x x x x         |
x x x x x           |
x x x x             |
x x x               |
x x                 |
x___________________|

Hier kommt es auf den kleinsten erkennbaren Umriss an. Ein Dreieck ist eine zweidimensionale Form (0,5 A ^ 2), genau wie ein Quadrat eine zweidimensionale Form (A ^ 2) ist. Der konstante Faktor zwei bleibt hier im asymptotischen Verhältnis zwischen den beiden, wir ignorieren ihn jedoch wie alle Faktoren ... (Es gibt einige unglückliche Nuancen bei dieser Technik, auf die ich hier nicht näher eingehen möchte; sie kann Sie irreführen.)

Dies bedeutet natürlich nicht, dass Schleifen und Funktionen schlecht sind. im Gegenteil, sie sind die Bausteine ​​moderner Programmiersprachen und wir lieben sie. Wir können jedoch sehen, dass die Art und Weise, wie wir Schleifen und Funktionen und Bedingungen zusammen mit unseren Daten (Kontrollfluss usw.) weben, die zeitliche und räumliche Nutzung unseres Programms nachahmt! Wenn die Nutzung von Zeit und Raum zu einem Problem wird, greifen wir auf Klugheit zurück und finden einen einfachen Algorithmus oder eine Datenstruktur, die wir nicht in Betracht gezogen haben, um die Reihenfolge des Wachstums irgendwie zu verringern. Trotzdem können diese Visualisierungstechniken (obwohl sie nicht immer funktionieren) Ihnen eine naive Vermutung für die Worst-Case-Laufzeit geben.

Hier ist eine andere Sache, die wir visuell erkennen können:

<----------------------------- N ----------------------------->
x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x
x x x x x x x x x x x x x x x x
x x x x x x x x
x x x x
x x
x

Wir können dies einfach neu anordnen und sehen, dass es O (N) ist:

<----------------------------- N ----------------------------->
x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x
x x x x x x x x x x x x x x x x|x x x x x x x x|x x x x|x x|x

Oder Sie protokollieren (N) Durchgänge der Daten für die Gesamtzeit von O (N * log (N)):

   <----------------------------- N ----------------------------->
 ^  x x x x x x x x x x x x x x x x|x x x x x x x x x x x x x x x x
 |  x x x x x x x x|x x x x x x x x|x x x x x x x x|x x x x x x x x
lgN x x x x|x x x x|x x x x|x x x x|x x x x|x x x x|x x x x|x x x x
 |  x x|x x|x x|x x|x x|x x|x x|x x|x x|x x|x x|x x|x x|x x|x x|x x
 v  x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x

Unabhängig, aber noch einmal erwähnenswert: Wenn wir einen Hash ausführen (z. B. ein Dictionary/Hashtable-Lookup), ist dies ein Faktor von O (1). Das geht ziemlich schnell.

[myDictionary.has(x) for x in listOfSizeA]
 \----- O(1) ------/    

--> A*1 --> O(A)

Wenn wir etwas sehr Kompliziertes tun, wie zum Beispiel eine rekursive Funktion oder einen Divide-and-Conquer-Algorithmus, sie können den Hauptsatz (funktioniert normalerweise) oder in lächerlichen Fällen den Akra-Bazzi-Satz (funktioniert fast immer) verwenden. Sie sehen die Laufzeit Ihres Algorithmus in Wikipedia nach.

Aber Programmierer denken nicht so, weil Algorithmus-Intuition irgendwann zur zweiten Natur wird. Sie werden anfangen, etwas Ineffizientes zu programmieren und sofort denken: "Tue ich etwas , das grob ineffizient ist? ". Wenn die Antwort "Ja" ist UND Sie davon ausgehen, dass es wirklich wichtig ist, können Sie einen Schritt zurücktreten und sich verschiedene Tricks überlegen, um die Dinge schneller laufen zu lassen (die Antwort lautet fast immer "Verwende eine Hash-Tabelle", selten "Verwende einen Baum", und sehr selten etwas etwas komplizierteres).


Amortisierte und durchschnittliche Komplexität

Es gibt auch das Konzept des "abgeschriebenen" und/oder "durchschnittlichen Falls" (beachten Sie, dass diese unterschiedlich sind).

Durchschnittlicher Fall : Dies ist nicht mehr als die Verwendung der Big-O-Notation für den erwarteten Wert einer Funktion anstelle der Funktion selbst. In dem üblichen Fall, in dem Sie alle Eingaben für gleich wahrscheinlich halten, ist der Durchschnittsfall nur der Durchschnitt der Laufzeit. Zum Beispiel mit Quicksort, obwohl der schlimmste Fall für einige wirklich schlechte Eingaben O(N^2) ist, ist der Durchschnittsfall der übliche O(N log(N)) (die wirklich schlechten Eingaben sind in der Anzahl sehr klein, so dass wir sie im Durchschnittsfall nicht bemerken ).

Amortisierter Worst-Case : Einige Datenstrukturen weisen möglicherweise eine große Worst-Case-Komplexität auf, aber wenn Sie viele dieser Vorgänge ausführen, ist dies der Durchschnitt Die Menge an Arbeit, die Sie leisten, ist besser als im schlimmsten Fall. Beispielsweise können Sie eine Datenstruktur haben, die normalerweise eine konstante O(1)-Zeit benötigt. Gelegentlich kommt es jedoch zu Schluckauf und es dauert O(N) Zeit für einen zufälligen Vorgang, da möglicherweise eine Buchhaltung oder eine Müllabfuhr erforderlich ist oder so N weitere Operationen. Die Worst-Case-Kosten betragen immer noch O(N) pro Operation, aber die amortisierten Kosten über viele Läufe betragen O(N)/N = O(1) pro Operation. Da die großen Operationen ausreichend selten sind, kann davon ausgegangen werden, dass sich die enorme Menge an Gelegenheitsarbeiten als konstanter Faktor in den Rest der Arbeit einfügt. Wir sagen, die Arbeit wird über eine ausreichend große Anzahl von Anrufen "amortisiert", so dass sie asymptotisch verschwindet.

Die Analogie zur amortisierten Analyse:

Du fährst ein Auto. Gelegentlich müssen Sie 10 Minuten zur Tankstelle gehen und dann 1 Minute damit verbringen, den Tank mit Benzin aufzufüllen. Wenn Sie dies jedes Mal tun würden, wenn Sie mit Ihrem Auto irgendwo hingefahren sind (10 Minuten zur Tankstelle fahren, ein paar Sekunden damit verbringen, einen Bruchteil einer Gallone zu tanken), wäre dies sehr ineffizient. Wenn Sie jedoch alle paar Tage den Tank auffüllen, werden die 11 Minuten, die Sie mit dem Fahren zur Tankstelle verbracht haben, über eine ausreichend große Anzahl von Fahrten "amortisiert", sodass Sie sie ignorieren und so tun können, als wären alle Ihre Fahrten möglicherweise 5% länger.

Vergleich zwischen Average-Case und Amortized Worst-Case:

  • Durchschnittsfall: Wir machen einige Annahmen über unsere Eingaben; wenn unsere Eingaben unterschiedliche Wahrscheinlichkeiten haben, haben unsere Ausgaben/Laufzeiten unterschiedliche Wahrscheinlichkeiten (von denen wir den Durchschnitt nehmen). Normalerweise gehen wir davon aus, dass alle Eingaben gleich wahrscheinlich sind (einheitliche Wahrscheinlichkeit), aber wenn die Eingaben in der realen Welt nicht unseren Annahmen von "Durchschnittseingaben" entsprechen, sind die Berechnungen für Durchschnittseingaben/Laufzeit möglicherweise bedeutungslos. Wenn Sie jedoch mit gleichmäßig zufälligen Eingaben rechnen, ist dies nützlich, um darüber nachzudenken!
  • Amortisierter Worst-Case: Wenn Sie eine amortisierte Worst-Case-Datenstruktur verwenden, wird die Leistung garantiert innerhalb des amortisierten Worst-Case liegen ... schließlich (auch wenn die Eingaben von einem bösen Dämon ausgewählt werden, der alles weiß und es versucht schraub dich rüber). In der Regel verwenden wir diese Methode, um Algorithmen zu analysieren, die bei unerwartet großen Schluckaufsignalen eine sehr abgehackte Leistung aufweisen, aber im Laufe der Zeit genau so gut wie andere Algorithmen sind. (Wenn Ihre Datenstruktur jedoch keine Obergrenze für viel herausragende Arbeit hat, die sie aufzuschieben bereit ist, könnte ein böser Angreifer Sie möglicherweise zwingen, die maximale Menge an aufgeschobener Arbeit auf einmal nachzuholen.

Wenn Sie jedoch einigermaßen besorgt über einen Angreifer sind, gibt es neben der Amortisation und dem Durchschnittsfall noch viele andere algorithmische Angriffsvektoren, um die Sie sich Sorgen machen müssen.)

Sowohl der Durchschnittsfall als auch die Amortisation sind unglaublich nützliche Tools zum Überlegen und Entwerfen unter Berücksichtigung der Skalierung.

(Siehe Differenz zwischen durchschnittlichem Fall und amortisierter Analyse bei Interesse an diesem Unterthema.)


Mehrdimensionales Big-O

Meistens merken die Leute nicht, dass es mehr als eine Variable gibt. In einem Suchalgorithmus für Zeichenfolgen kann Ihr Algorithmus beispielsweise O([length of text] + [length of query]) dauern, d. H., Er ist in zwei Variablen wie O(N+M) linear. Andere eher naive Algorithmen können O([length of text]*[length of query]) oder O(N*M) sein. Das Ignorieren mehrerer Variablen ist eines der häufigsten Probleme, die ich in der Algorithmusanalyse sehe, und kann Sie beim Entwerfen eines Algorithmus behindern.


Die ganze Geschichte

Denken Sie daran, dass Big-O nicht die ganze Geschichte ist. Sie können einige Algorithmen drastisch beschleunigen, indem Sie Caching verwenden, sie für den Cache unberücksichtigt lassen, Engpässe vermeiden, indem Sie mit RAM anstelle von Festplatten arbeiten, Parallelisierung verwenden oder Vorarbeit leisten - diese Techniken sind häufig unabhängig von der "Big-O" -Notation der Wachstumsordnung, obwohl Sie die Anzahl der Kerne häufig in der Big-O-Notation paralleler Algorithmen sehen.

Bedenken Sie auch, dass Sie sich aufgrund der versteckten Einschränkungen Ihres Programms möglicherweise nicht wirklich für asymptotisches Verhalten interessieren. Möglicherweise arbeiten Sie mit einer begrenzten Anzahl von Werten. Beispiel:

  • Wenn Sie so etwas wie 5 Elemente sortieren, möchten Sie nicht die schnelle O(N log(N))-Quicksortierung verwenden. Sie möchten die Einfügesortierung verwenden, die bei kleinen Eingaben eine gute Leistung erbringt. Diese Situationen treten häufig bei Divide-and-Conquer-Algorithmen auf, bei denen Sie das Problem in immer kleinere Teilprobleme aufteilen, z. B. rekursives Sortieren, schnelle Fourier-Transformationen oder Matrixmultiplikation.
  • Wenn einige Werte aufgrund einer versteckten Tatsache effektiv begrenzt sind (z. B. ist der durchschnittliche menschliche Name bei etwa 40 Buchstaben weich begrenzt, und das menschliche Alter ist bei etwa 150 weich begrenzt). Sie können Ihrer Eingabe auch Grenzen setzen, um Terme effektiv konstant zu halten.

In der Praxis kann sogar bei Algorithmen mit gleicher oder ähnlicher asymptotischer Leistung deren relativer Wert durch andere Faktoren bestimmt werden, z. B .: andere Leistungsfaktoren (Quicksort und Mergesort sind beide O(N log(N)), Quicksort nutzt jedoch die Vorteile von CPU-Caches); Nichterfüllungserwägungen, wie einfache Implementierung; ob eine Bibliothek verfügbar ist und wie seriös und gepflegt die Bibliothek ist.

Programme werden auch langsamer auf einem 500-MHz-Computer als auf einem 2-GHz-Computer ausgeführt. Wir betrachten dies nicht wirklich als Teil der Ressourcengrenzen, da wir an die Skalierung in Bezug auf Maschinenressourcen (z. B. pro Taktzyklus) denken, nicht pro reelle Sekunde. Es gibt jedoch ähnliche Dinge, die die Leistung "heimlich" beeinflussen können, z. B. ob Sie unter Emulation arbeiten oder ob der Compiler den Code optimiert hat oder nicht. Dies kann dazu führen, dass einige grundlegende Vorgänge länger dauern (sogar relativ zueinander) oder einige Vorgänge sogar asymptotisch beschleunigen oder verlangsamen (sogar relativ zueinander). Der Effekt kann zwischen verschiedenen Implementierungen und/oder Umgebungen klein oder groß sein. Wechseln Sie die Sprache oder die Maschine, um diese kleine Mehrarbeit zu erledigen? Das hängt von hundert anderen Gründen ab (Notwendigkeit, Fähigkeiten, Mitarbeiter, Programmiererproduktivität, Geldwert Ihrer Zeit, Vertrautheit, Problemumgehungen, warum nicht Baugruppe oder GPU usw.), die möglicherweise wichtiger sind als die Leistung.

Die oben genannten Punkte werden wie die Programmiersprache fast nie als Teil des konstanten Faktors betrachtet (und sollten es auch nicht sein). dennoch sollte man sich dessen bewusst sein, weil manchmal (wenn auch selten) sie Dinge beeinflussen können. In cpython beispielsweise ist die Implementierung der systemeigenen Prioritätswarteschlange asymptotisch nicht optimal (O(log(N)) anstelle von O(1) für die Auswahl von Einfügung oder find-min). Verwenden Sie eine andere Implementierung? Wahrscheinlich nicht, da die C-Implementierung wahrscheinlich schneller ist und wahrscheinlich an anderer Stelle ähnliche Probleme auftreten. Es gibt Kompromisse; manchmal sind sie wichtig und manchmal nicht.


( edit : Hier endet die Erklärung "Plain English".)

Math addenda

Der Vollständigkeit halber lautet die genaue Definition der Big-O-Notation wie folgt: f(x) ∈ O(g(x)) bedeutet, dass "f asymptotisch durch const * g begrenzt ist": Ignoriert man alles unterhalb eines endlichen Wertes von x, existiert eine Konstante, so dass |f(x)| ≤ const * |g(x)| existiert. (Die anderen Symbole lauten wie folgt: genau wie O bedeutet ≤, Ω bedeutet ≥. Es gibt Varianten in Kleinbuchstaben: o bedeutet <und ω bedeutet>.) f(x) ∈ Ɵ(g(x)) bedeutet sowohl f(x) ∈ O(g(x)) als auch f(x) ∈ Ω(g(x)) (obere und untere Grenze von g): Es gibt einige Konstanten, so dass f immer im "Band" zwischen const1*g(x) und const2*g(x) liegt. Es ist die stärkste asymptotische Aussage, die Sie machen können, und entspricht in etwa ==. (Entschuldigung, ich habe mich aus Gründen der Klarheit entschieden, die Erwähnung der Absolutwertsymbole bis jetzt zu verschieben. Insbesondere, weil ich in der Informatik noch nie negative Werte gesehen habe.)

Die Leute werden oft = O(...) verwenden, was vielleicht die korrektere 'comp-sci'-Notation ist und deren Verwendung völlig legitim ist. "f = O (...)" wird gelesen "f ist Ordnung .../f ist xxx-begrenzt durch ..." und wird als "f ist ein Ausdruck, dessen Asymptotik ..." angesehen. Mir wurde beigebracht, die strengere ∈ O(...) zu verwenden. bedeutet "ist ein Element von" (immer noch wie zuvor gelesen). O(N²) ist eigentlich eine - Äquivalenzklasse , das heißt, es ist eine Menge von Dingen, die wir für gleich halten. In diesem speziellen Fall enthält O(N²) Elemente wie {2 N², 3 N², 1/2 N², 2 N² + log(N), - N² + N^1.9, ...} und ist unendlich groß, aber es ist immer noch eine Menge . Die = -Notation ist möglicherweise die gebräuchlichere und wird sogar in Veröffentlichungen von weltbekannten Informatikern verwendet. Darüber hinaus ist es häufig der Fall, dass Menschen in einer ungezwungenen Umgebung O(...) sagen, wenn sie Ɵ(...) meinen. Dies ist technisch wahr, da die Menge der Dinge Ɵ(exactlyThis) eine Teilmenge von O(noGreaterThanThis) ist und es einfacher ist, sie zu tippen. ;-)

383
ninjagecko

EDIT: Kurzer Hinweis, dies ist mit ziemlicher Sicherheit verwirrend Big O-Notation (das ist eine Obergrenze) mit der Theta-Notation (das ist sowohl eine Ober- als auch eine Untergrenze). Nach meiner Erfahrung ist dies eigentlich typisch für Diskussionen in einem nicht-akademischen Umfeld. Wir entschuldigen uns für die entstandene Verwirrung.

In einem Satz: Wie lange dauert es mit zunehmender Größe Ihres Auftrags, bis er abgeschlossen ist?

Offensichtlich wird nur "Größe" als Eingabe und "Zeitaufwand" als Ausgabe verwendet - die gleiche Idee gilt, wenn Sie über die Speichernutzung usw. sprechen möchten.

Hier ist ein Beispiel, wo wir N T-Shirts haben, die wir trocknen wollen. Wir werden annehmen , dass es unglaublich schnell ist, sie in die trocknende Position zu bringen (d. H. Die menschliche Interaktion ist vernachlässigbar). Das ist im wirklichen Leben natürlich nicht der Fall ...

  • Verwendung einer Wäscheleine im Freien: Wenn Sie einen unendlich großen Garten haben, trocknet das Waschen in O(1) Zeit. So viel Sie davon haben, es wird die gleiche Sonne und frische Luft bekommen, so dass die Größe die Trocknungszeit nicht beeinflusst.

  • Verwendung eines Wäschetrockners: Sie geben 10 Hemden in jede Ladung und eine Stunde später sind sie fertig. (Ignorieren Sie die tatsächlichen Zahlen hier - sie sind irrelevant.) Daher dauert das Trocknen von 50 Hemden ungefähr fünfmal so lange wie das Trocknen von 10 Hemden.

  • Alles in einen Trockenschrank stellen: Wenn wir alles auf einen großen Stapel legen und nur die allgemeine Wärme einwirken lassen, wird es lange dauern, bis die mittleren Hemden trocken sind. Ich würde das Detail nicht gerne erraten, aber ich vermute, dass dies mindestens O (N ^ 2) ist - wenn Sie die Waschmenge erhöhen, erhöht sich die Trocknungszeit schneller.

Ein wichtiger Aspekt der "Big O" -Notation ist, dass nicht angibt, welcher Algorithmus für eine bestimmte Größe schneller ist . Nehmen Sie eine Hash-Tabelle (String-Schlüssel, Integer-Wert) gegen ein Array von Paaren (String, Integer). Ist es schneller, einen Schlüssel in der Hash-Tabelle oder ein Element im Array anhand einer Zeichenfolge zu finden? (dh für das Array: "Finde das erste Element, bei dem der String-Teil mit dem angegebenen Schlüssel übereinstimmt.") Hashtables werden im Allgemeinen amortisiert (~ = "im Durchschnitt") O(1) - sobald sie gesetzt sind Nach oben sollte es ungefähr genauso lange dauern, bis ein Eintrag in einer 100-Einträge-Tabelle wie in einer 1.000.000-Einträge-Tabelle gefunden wurde. Das Suchen eines Elements in einem Array (basierend auf dem Inhalt und nicht auf dem Index) ist linear, d. H. O(N) - im Durchschnitt müssen Sie sich die Hälfte der Einträge ansehen.

Ist eine Hash-Tabelle dadurch schneller als ein Array für Lookups? Nicht unbedingt. Wenn Sie eine sehr kleine Sammlung von Einträgen haben, ist ein Array möglicherweise schneller - Sie können möglicherweise alle Zeichenfolgen in der Zeit überprüfen, die erforderlich ist, um nur den Hashcode der gesuchten Zeichenfolge zu berechnen. Wenn der Datensatz jedoch größer wird, übertrifft die Hash-Tabelle möglicherweise das Array.

241
Jon Skeet

Big O beschreibt eine Obergrenze für das Wachstumsverhalten einer Funktion, beispielsweise die Laufzeit eines Programms, wenn die Eingaben groß werden.

Beispiele:

  • O (n): Wenn ich die Eingangsgröße verdopple, verdoppelt sich die Laufzeit

  • Auf2): Wenn die Eingangsgröße die Laufzeitvervierfachung verdoppelt

  • O (log n): Wenn sich die Eingangsgröße verdoppelt, erhöht sich die Laufzeit um eins

  • O (2n): Wenn die Eingabegröße um eins zunimmt, verdoppelt sich die Laufzeit

Die Eingabegröße ist normalerweise der Platz in Bits, der zur Darstellung der Eingabe benötigt wird.

121
starblue

Die große O-Notation wird am häufigsten von Programmierern als ungefähres Maß dafür verwendet, wie lange eine Berechnung (Algorithmus) dauern wird, ausgedrückt als Funktion der Größe des Eingabesets. 

Big O ist nützlich, um zu vergleichen, wie gut zwei Algorithmen mit zunehmender Anzahl von Eingängen skaliert werden können. 

Genauer gesagt wird Big O-Notation verwendet, um das asymptotische Verhalten einer Funktion auszudrücken. Das heißt, wie sich die Funktion verhält, wenn sie sich unendlich nähert. 

In vielen Fällen fällt das "O" eines Algorithmus in einen der folgenden Fälle:

  • O(1) - Die Zeit bis zum Abschluss ist unabhängig von der Größe des Eingangssatzes gleich. Ein Beispiel ist der Zugriff auf ein Array-Element über den Index.
  • O (Log N) - Die Zeit bis zum Abschluss steigt in etwa mit log2 (n). Beispielsweise benötigen 1024 Elemente ungefähr doppelt so lange wie 32 Elemente, da Log2 (1024) = 10 und Log2 (32) = 5 sind. Ein Beispiel ist das Auffinden eines Elements in einem binärer Suchbaum (BST). 
  • O(N) - Die Zeit bis zum Abschluss skaliert linear mit der Größe des Eingangssatzes. Wenn Sie also die Anzahl der Elemente im Eingabesatz verdoppeln, dauert der Algorithmus ungefähr doppelt so lange. Ein Beispiel ist das Zählen der Anzahl der Elemente in einer verknüpften Liste. 
  • O (N Log N) - Die Zeit bis zum Abschluss wird um die Anzahl der Elemente multipliziert mit dem Ergebnis von Log2 (N). Ein Beispiel dafür ist Heap-Sortierung und Schnelle Sortierung
  • O (N ^ 2) - Die Zeit bis zum Abschluss entspricht in etwa dem Quadrat der Anzahl der Elemente. Ein Beispiel dafür ist Blasensortierung .
  • O (N!) - Zeit bis zum Abschluss ist die Fakultät des Eingangssatzes. Ein Beispiel dafür ist die Brute-Force-Lösung für reisende Händler

Big O ignoriert Faktoren, die nicht in sinnvoller Weise zur Wachstumskurve einer Funktion beitragen, wenn die Eingangsgröße gegen Unendlich zunimmt. Das bedeutet, dass Konstanten, die zur Funktion hinzugefügt oder mit dieser Funktion multipliziert werden, einfach ignoriert werden. 

99
cdiggins

Big O ist nur eine Möglichkeit, sich auf eine übliche Weise "auszudrücken": "Wie viel Zeit/Platz braucht es, um meinen Code auszuführen?".

Sie sehen oft O (n), O (n2), O(nlogn) und so weiter, all dies sind nur Wege, um zu zeigen; Wie verändert sich ein Algorithmus?

O (n) bedeutet, dass Big O n ist, und jetzt denken Sie vielleicht: "Was ist n !?" Nun, "n" ist die Anzahl der Elemente. Imaging, das Sie nach einem Objekt in einem Array suchen möchten. Sie müssten sich jedes Element ansehen und als "Sind Sie das richtige Element/Element?" Im schlimmsten Fall befindet sich das Element am letzten Index, was bedeutet, dass es so lange gedauert hat, wie Elemente in der Liste vorhanden sind. Um generisch zu sein, sagen wir "oh hey, n ist eine gerechte Menge von Werten!" .

Dann verstehen Sie vielleicht, was "n."2"bedeutet, aber um noch genauer zu sein: Spielen Sie mit dem Gedanken, dass Sie einen einfachen, einfachsten Sortieralgorithmus haben: Bubblesort. Dieser Algorithmus muss für jedes Element die gesamte Liste durchsehen.

Meine Liste

  1. 1
  2. 6
  3. 3

Der Fluss hier wäre:

  • Vergleiche 1 und 6, welche ist am größten? Ok 6 ist in der richtigen Position und bewegt sich vorwärts!
  • Vergleiche 6 und 3, oh, 3 ist weniger! Verschieben wir das Ok die Liste hat sich geändert, wir müssen jetzt von vorne beginnen!

Dies ist O n2 da Sie sich alle Elemente in der Liste ansehen müssen, gibt es "n" Elemente. Für jedes Element betrachten Sie alle Elemente noch einmal. Zum Vergleich ist dies auch "n". Für jedes Element sehen Sie "n" mal, was n * n = n bedeutet2

Ich hoffe, das ist so einfach, wie Sie es wünschen.

Aber denken Sie daran, Big O ist nur eine Möglichkeit, sich in Zeit und Raum zu versetzen.

78
Filip Ekberg

Big O beschreibt die grundlegende Skalierung eines Algorithmus.

Es gibt viele Informationen, die Big O Ihnen nicht über einen bestimmten Algorithmus sagt. Es schneidet bis auf die Knochen und gibt nur Informationen über die Skalierungsnatur eines Algorithmus, insbesondere darüber, wie sich die Ressource (Denkzeit oder Speicher) eines Algorithmus als Reaktion auf die "Eingangsgröße" skaliert.

Betrachten Sie den Unterschied zwischen einer Dampfmaschine und einer Rakete. Dabei handelt es sich nicht nur um verschiedene Varianten desselben (z. B. eines Prius-Motors im Vergleich zu einem Lamborghini-Motor), sondern es handelt sich im Grunde um dramatisch unterschiedliche Arten von Antriebssystemen. Eine Dampfmaschine ist zwar schneller als eine Spielzeugrakete, aber kein Dampfkolbenmotor kann die Geschwindigkeiten eines Orbitalstartfahrzeugs erreichen. Dies liegt daran, dass diese Systeme unterschiedliche Skalierungseigenschaften in Bezug auf das Verhältnis des erforderlichen Kraftstoffs ("Ressourcennutzung") aufweisen, um eine vorgegebene Geschwindigkeit ("Eingangsgröße") zu erreichen.

Warum ist das so wichtig? Denn Software befasst sich mit Problemen, die sich in der Größe um bis zu einer Billion Größe unterscheiden können. Betrachten Sie das für einen Moment. Das Verhältnis zwischen der erforderlichen Geschwindigkeit zum Reisen zum Mond und der Gehgeschwindigkeit des Menschen beträgt weniger als 10.000: 1, und das ist absolut klein im Vergleich zu den möglichen Eingabegrößen der Software. Und da Software unter Umständen einen astronomischen Bereich für die Eingabegrößen hat, besteht die Möglichkeit, dass ein Algorithmus die Komplexität des Big-O-Algorithmus hat. Dies ist eine grundlegende Skalierung, die alle Implementierungsdetails übertrifft.

Betrachten Sie das kanonische Sortierbeispiel. Blasensortierung ist O (n2), während die Zusammenführungssorte O (n log n) ist. Nehmen wir an, Sie haben zwei Sortieranwendungen, Anwendung A, die Blasensortierung verwendet, und Anwendung B, die Merge-Sortierung verwendet, und bei Eingabegrößen von etwa 30 Elementen ist Anwendung A 1.000-fach schneller als Anwendung B beim Sortieren. Wenn Sie nie mehr als 30 Elemente sortieren müssen, ist es offensichtlich, dass Sie die Anwendung A bevorzugen sollten, da sie bei diesen Eingabegrößen wesentlich schneller ist. Wenn Sie jedoch feststellen, dass Sie möglicherweise zehn Millionen Elemente sortieren müssen, ist zu erwarten, dass die Anwendung B tatsächlich Tausende von Zeiten schneller ist als die Anwendung A, und zwar aufgrund der Skalierung jedes Algorithmus.

53
Wedge

Hier ist das einfache englische Bestiarium, das ich normalerweise zum Erklären der gängigen Varianten von Big-O benutze

Bevorzugen Sie in allen Fällen Algorithmen, die weiter oben in der Liste stehen, denjenigen, die sich in der Liste befinden. Die Kosten für den Wechsel zu einer teureren Komplexitätsklasse variieren jedoch erheblich.

O (1):

Kein Wachstum. Unabhängig davon, wie groß das Problem ist, können Sie es in der gleichen Zeit lösen. Dies ist ein bisschen analog zum Rundfunk, bei dem für die Übertragung über eine bestimmte Entfernung dieselbe Energiemenge erforderlich ist, unabhängig von der Anzahl der Personen, die innerhalb des Sendebereichs liegen.

O (log n):

Diese Komplexität ist die gleiche wie O(1) , nur dass sie etwas schlechter ist. Für alle praktischen Zwecke können Sie dies als sehr große konstante Skalierung betrachten. Der Unterschied in der Arbeit zwischen der Verarbeitung von eintausend und einer Milliarde Artikeln beträgt nur den Faktor sechs.

O (n):

Die Kosten für die Lösung des Problems sind proportional zur Größe des Problems. Wenn sich Ihr Problem verdoppelt, verdoppelt sich der Preis der Lösung. Da die meisten Probleme auf irgendeine Weise in den Computer eingescannt werden müssen, wie Dateneingabe, Lesen von Festplatten oder Netzwerkverkehr, ist dies im Allgemeinen ein erschwinglicher Skalierungsfaktor.

O (n log n):

Diese Komplexität ist sehr ähnlich zu O (n) . Für alle praktischen Zwecke sind die beiden gleichwertig. Diese Komplexität wird im Allgemeinen noch als skalierbar betrachtet. Durch Anpassen der Annahmen können einige O (n log n) Algorithmen in O (n) Algorithmen umgewandelt werden. Durch die Begrenzung der Schlüsselgröße wird beispielsweise die Sortierung von O (n log n) nach O (n) reduziert.

O (n2):

Wächst als Quadrat, wobei n die Länge der Seite eines Quadrats ist. Dies ist die gleiche Wachstumsrate wie der "Netzwerkeffekt", bei dem jeder in einem Netzwerk möglicherweise alle anderen im Netzwerk kennt. Wachstum ist teuer. Die meisten skalierbaren Lösungen können Algorithmen mit dieser Komplexität nicht ohne bedeutende Gymnastik verwenden. Dies gilt im Allgemeinen für alle anderen Polynomkomplexitäten - O (nk) - auch.

O (2n):

Skaliert nicht Sie haben keine Hoffnung, ein nicht unbedeutendes Problem zu lösen. Nützlich, um zu wissen, was zu vermeiden ist, und für Experten, um angenäherte Algorithmen in O zu finden (nk) .

37
Andrew Prock

Big O ist ein Maß dafür, wie viel Zeit/Raum ein Algorithmus im Verhältnis zur Größe seiner Eingabe verwendet. 

Wenn ein Algorithmus O(n) ist, erhöht sich die Zeit/der Abstand mit der gleichen Geschwindigkeit wie seine Eingabe.

Wenn ein Algorithmus O ist (n2) dann erhöht sich die Zeit/der Raum um die Rate seiner Eingabe im Quadrat.

und so weiter.

35
Brownie

Es ist sehr schwierig, die Geschwindigkeit von Softwareprogrammen zu messen, und wenn wir es versuchen, können die Antworten sehr komplex sein und mit Ausnahmen und Sonderfällen gefüllt sein. Dies ist ein großes Problem, da alle diese Ausnahmen und Sonderfälle ablenkend und wenig hilfreich sind, wenn wir zwei verschiedene Programme miteinander vergleichen möchten, um herauszufinden, welches das "schnellste" ist.

Infolge dieser wenig hilfreichen Komplexität wird versucht, die Geschwindigkeit von Softwareprogrammen anhand der kleinsten und am wenigsten komplexen (mathematischen) Ausdrücke zu beschreiben. Diese Ausdrücke sind sehr grobe Annäherungen: Obwohl sie mit etwas Glück die "Essenz" davon erfassen, ob eine Software schnell oder langsam ist.

Da es sich um Annäherungen handelt, verwenden wir den Buchstaben "O" (Big Oh) in dem Ausdruck als Konvention, um dem Leser zu signalisieren, dass wir eine grobe Vereinfachung machen. (Und um sicherzustellen, dass niemand irrtümlich glaubt, dass der Ausdruck in irgendeiner Weise korrekt ist).

Wenn Sie das "Oh" als "in der Reihenfolge von" oder "ungefähr" lesen, werden Sie nicht zu weit gehen. (Ich denke, die Wahl des Big-Oh war vielleicht ein Versuch des Humors).

Das einzige, was diese "Big-Oh" -Ausdrücke versuchen zu tun, ist zu beschreiben, wie sehr sich die Software verlangsamt, wenn wir die Datenmenge erhöhen, die die Software verarbeiten muss. Wenn wir die zu verarbeitende Datenmenge verdoppeln, braucht die Software doppelt so lange, um ihre Arbeit zu beenden? Zehnmal so lang? In der Praxis gibt es eine sehr begrenzte Anzahl von Ausdrücken mit großem Ohm, auf die Sie stoßen werden und über die Sie sich Gedanken machen müssen:

Die gute:

  • O(1) Konstante : Das Programm benötigt dieselbe Zeit, um ausgeführt zu werden, egal wie groß die Eingabe ist.
  • O(log n) Logarithmic : Die Programmlaufzeit erhöht sich nur langsam, auch wenn die Größe der Eingabe stark zunimmt.

Das Schlechte:

  • O(n) Linear : Die Programmlaufzeit erhöht sich proportional zur Größe der Eingabe.
  • O(n^k) Polynom : - Die Verarbeitungszeit wird als Polynomfunktion schneller und schneller, da die Größe der Eingabe zunimmt.

... und das Hässliche:

  • O(k^n) Exponential Die Programmlaufzeit steigt sehr schnell an, selbst wenn das Problem nur mäßig zunimmt. Nur kleine Datensätze können mit exponentiellen Algorithmen verarbeitet werden.
  • O(n!) Factorial Die Programmlaufzeit wird länger sein, als Sie es sich leisten können, auf etwas anderes als die kleinsten und trivialsten Datensätze zu warten.
31
William Payne

Was ist eine einfache englische Erklärung für Big O? Mit so wenig formaler Definition wie möglich und einfacher Mathematik.

Eine einfache englische Erklärung der Need für Big-O-Notation:

Wenn wir programmieren, versuchen wir, ein Problem zu lösen. Was wir programmieren, wird als Algorithmus bezeichnet. Dank der großen O-Notation können wir die Leistung unserer Algorithmen im schlechteren Fall standardisiert vergleichen. Hardwarespezifikationen variieren mit der Zeit, und Verbesserungen der Hardware können die Ausführungszeit eines Algorithmus reduzieren. Der Austausch der Hardware bedeutet jedoch nicht, dass unser Algorithmus im Laufe der Zeit verbessert oder verbessert wird, da unser Algorithmus immer noch derselbe ist. Um verschiedene Algorithmen vergleichen zu können und um festzustellen, ob einer besser ist oder nicht, verwenden wir die Big O-Notation.

Eine einfache englische Erklärung von Was Big O-Notation ist:

Nicht alle Algorithmen laufen in derselben Zeitspanne und können je nach Anzahl der Elemente in der Eingabe variieren, die wir n nennen. Auf dieser Grundlage betrachten wir die Analyse des schlimmsten Falls oder eine Obergrenze der Laufzeit, da n immer größer wird. Wir müssen wissen, was n ist, weil viele der Big-O-Notationen darauf verweisen.

31
James Oravec

Eine einfache unkomplizierte Antwort kann sein:

Big O steht für die schlechteste mögliche Zeit/Raum für diesen Algorithmus. Der Algorithmus wird niemals mehr Raum/Zeit über dieser Grenze benötigen. Big O steht für Zeit/Raum-Komplexität im Extremfall.

27
AlienOnEarth

Ok, meine 2 Cent.

Big-O, ist Steigerungsrate von Ressourcen, die vom Programm verbraucht werden, z. Größe der Probleminstanz

Ressource: Könnte die Gesamt-CPU-Zeit sein, könnte maximal RAM sein. Bezieht sich standardmäßig auf die CPU-Zeit.

Sagen Sie, das Problem ist "Finden Sie die Summe", 

int Sum(int*arr,int size){
      int sum=0;
      while(size-->0) 
         sum+=arr[size]; 

      return sum;
}

problem-instance = {5,10,15} ==> problem-instance-size = 3, iterations-in-loop = 3

problem-instance = {5,10,15,20,25} ==> problem-instance-size = 5 iterations-in-loop = 5

Zur Eingabe der Größe "n" wächst das Programm mit einer Geschwindigkeit von "n" Iterationen im Array. Daher ist Big-O N als O (n)

Angenommen, das Problem ist "Finde die Kombination", 

    void Combination(int*arr,int size)
    { int outer=size,inner=size;
      while(outer -->0) {
        inner=size;
        while(inner -->0)
          cout<<arr[outer]<<"-"<<arr[inner]<<endl;
      }
    }

problem-instance = {5,10,15} ==> problem-instance-size = 3, Gesamtiterationen = 3 * 3 = 9

probleminstanz = {5,10,15,20,25} ==> Probleminstanzgröße = 5, Gesamtiterationen = 5 * 5 = 25

Zur Eingabe der Größe "n" wächst das Programm mit einer Geschwindigkeit von "n * n" Iterationen im Array. Daher ist Big-O N2 ausgedrückt als O (n2)

27
Ajeet Ganga

Big-O-Notation ist eine Möglichkeit, die Obergrenze eines Algorithmus in Bezug auf Raum oder Laufzeit zu beschreiben. N ist die Anzahl der Elemente in dem Problem (d. H. Größe eines Arrays, Anzahl der Knoten in einem Baum usw.). Wir sind daran interessiert, die Laufzeit zu beschreiben, wenn n groß wird.

Wenn wir sagen, dass ein Algorithmus O(f(n)) ist, sagen wir, dass die Laufzeit (oder der erforderliche Platz) für diesen Algorithmus immer niedriger ist als einige konstante Zeiten f (n).

Zu sagen, dass die binäre Suche eine Laufzeit von O(logn) hat, bedeutet, dass es eine Konstante c gibt, die Sie mit log (n) multiplizieren können, die immer größer ist als die Laufzeit der binären Suche. In diesem Fall haben Sie immer einen konstanten Faktor für log (n) Vergleiche.

Mit anderen Worten, wobei g(n) die Laufzeit Ihres Algorithmus ist, sagen wir, dass g(n) = O(f(n)), wenn g(n) <= c * f (n) wenn n> k, wobei c und k einige Konstanten sind.

24
John C Earls

" Was ist eine einfache englische Erklärung von Big O? Mit so wenig formaler Definition wie möglich und einfacher Mathematik. "

Eine so schöne einfache und kurze Frage scheint mindestens eine ebenso kurze Antwort zu verdienen, wie sie ein Schüler während des Tutoriums erhalten könnte.

Die Big-O-Notation gibt einfach an, wie viel Zeit * ein Algorithmus in Bezug auf nur die Menge der Eingabedaten ausführen kann **.

(* in einem wunderbaren einheitenlosen Zeitgefühl!)
(** worauf es ankommt, denn die Menschen werden immer mehr wollen , ob sie heute leben oder Morgen)

Nun, was ist so wunderbar an der Big O-Notation, wenn es das ist, was es tut?

  • In der Praxis ist die Big-O-Analyse so nützlich und wichtig , weil Big-O den Fokus genau auf den eigenen Algorithmus legt Komplexität und vollständig ignoriert alles, was nur eine Proportionalitätskonstante ist - wie eine JavaScript-Engine, die Geschwindigkeit einer CPU, Ihre Internetverbindung und all die Dinge, die schnell so lächerlich veraltet werden wie ein Model T. Big O konzentriert sich auf Leistung nur so, wie es für die Menschen in der Gegenwart oder in der Zukunft gleichermaßen wichtig ist.

  • Big O-Notation beleuchtet auch direkt das wichtigste Prinzip der Computerprogrammierung/-technik, das alle guten Programmierer zum Nachdenken und Träumen anregt: Der einzige Weg, über den langsamen Fortschritt der Technologie hinaus Ergebnisse zu erzielen, ist erfinde einen besseren Algorithmus .

23
Joseph Myers

Beispiel eines Algorithmus (Java):

// given a list of integers L, and an integer K
public boolean simple_search(List<Integer> L, Integer K)
{
    // for each integer i in list L
    for (Integer i : L)
    {
        // if i is equal to K
        if (i == K)
        {
            return true;
        }
    }

    return false;
}

Beschreibung des Algorithmus:

  • Dieser Algorithmus sucht eine Liste, Element für Element, Suche nach einem Schlüssel,

  • Iteration für jedes Element in der Liste. Wenn es sich um den Schlüssel handelt, wird True zurückgegeben.

  • Wenn die Schleife beendet ist, ohne den Schlüssel zu finden, geben Sie False zurück.

Big-O-Notation steht für die Obergrenze der Komplexität (Zeit, Raum, ..)

So finden Sie die Big-O-Zeitkomplexität:

  • Berechnen Sie, wie viel Zeit (in Bezug auf die Eingabegröße) der ungünstigste Fall benötigt:

  • Worst-Case: Der Schlüssel existiert nicht in der Liste.

  • Zeit (Worst-Case) = 4n + 1

  • Zeit: O (4n + 1) = O(n) | In Big-O werden Konstanten vernachlässigt

  • O (n) ~ linear

Es gibt auch Big-Omega, die die Komplexität des Best-Case darstellen:

  • Best-Case: Der Schlüssel ist der erste Artikel.

  • Zeit (Bester Fall) = 4

  • Zeit: Ω (4) = O(1) ~ Instant\Constant

20
Khaled.K

Big O

f (x) = O ( g (x)) wenn x zu a geht (zum Beispiel a = + ∞) bedeutet, dass es eine Funktion k gibt, so dass:

  1. f (x) = k (x) g (x)

  2. k ist in irgendeiner Nachbarschaft von a begrenzt (wenn a = + ∞, bedeutet dies, dass es Zahlen N und M gibt, so dass für jedes x> N | k (x) | <M).

Mit anderen Worten bedeutet im Klartext: f (x) = O ( g (x)) x → a dass in einer Nachbarschaft von a f in das Produkt von g und einer begrenzten Funktion zerfällt.

Kleines o

Hier ist übrigens zum Vergleich die Definition von klein o.

f (x) = o ( g (x)) wenn x zu a geht, bedeutet dies, dass es eine Funktion k gibt, so dass :

  1. f (x) = k (x) g (x)

  2. k (x) geht auf 0, wenn x auf a geht.

Beispiele

  • sin x = O(x) wenn x → 0.

  • sin x = O(1) wenn x → + ∞,

  • x2 + x = O(x) wenn x → 0,

  • x2 + x = O (x2) wenn x → + ∞,

  • ln (x) = o(x) = O(x) wenn x → + ∞.

Achtung! Die Notation mit dem Gleichheitszeichen "=" verwendet eine "falsche Gleichheit": es ist wahr, dass o(g(x)) = O (g (x)), aber falsch, dass O(g(x)) = o (g (x)). Ebenso ist es in Ordnung, "ln (x) = o(x), wenn x → + ∞" zu schreiben, aber die Formel "o (x) = ln (x)" würde keinen Sinn ergeben.

Weitere Beispiele

  • O (1) = O(n) = O (n2) wenn n → + ∞ (aber nicht umgekehrt, ist die Gleichheit "falsch"),

  • O (n) + O (n2) = O (n2) wenn n → + ∞

  • O (O (n2)) = O (n2) wenn n → + ∞

  • Auf2)Auf3) = O (n5) wenn n → + ∞


Hier ist der Wikipedia-Artikel: https://en.wikipedia.org/wiki/Big_O_notation

18
Alexey

Die Big-O-Notation beschreibt, wie schnell ein Algorithmus bei einer beliebigen Anzahl von Eingabeparametern abläuft, die wir "n" nennen. Dies ist in der Informatik nützlich, da verschiedene Maschinen mit unterschiedlichen Geschwindigkeiten arbeiten und es einfach nicht aussagekräftig ist, dass ein Algorithmus 5 Sekunden dauert, da ich möglicherweise ein System mit einem 4,5-GHz-Octo-Core-Prozessor ausführte Ein 15 Jahre altes 800-MHz-System, das unabhängig vom Algorithmus länger dauern kann. Anstatt festzulegen, wie schnell ein Algorithmus in Bezug auf die Zeit ausgeführt wird, sagen wir, wie schnell er in Bezug auf die Anzahl der Eingabeparameter oder "n" läuft. Durch die Beschreibung von Algorithmen auf diese Weise können wir die Geschwindigkeiten von Algorithmen vergleichen, ohne die Geschwindigkeit des Computers selbst berücksichtigen zu müssen.

17
Brian

Ich bin mir nicht sicher, ob ich weiter zum Thema beitrage, aber ich dachte immer, ich würde es teilen: Ich habe einmal gefunden, dass dieser Blog-Post einige hilfreiche (wenn auch sehr grundlegende) Erklärungen und Beispiele zu Big O hat: 

An Beispielen hat dies geholfen, die nackten Grundlagen in meinen schildpattartigen Schädel zu bringen. Ich denke, es ist eine ziemlich absteigende 10-minütige Lektüre, um Sie in die richtige Richtung zu bringen. 

11
Priidu Neemre

Sie möchten wissen, was es alles von Big O zu wissen gibt? Ich auch.

Um von Big O zu sprechen, werde ich Wörter verwenden, die nur einen Schlag enthalten. Ein Ton pro Wort. Kleine Wörter sind schnell. Sie kennen diese Wörter und ich auch. Wir werden Wörter mit einem einzigen Klang verwenden. Sie sind klein. Ich bin sicher, Sie werden alle Wörter kennen, die wir verwenden werden!

Lassen Sie uns und Sie über Arbeit sprechen. Die meiste Zeit mag ich keine Arbeit. Magst du die Arbeit? Es mag sein, dass Sie das tun, aber ich bin mir sicher, dass ich es nicht tue.

Ich gehe nicht gerne zur Arbeit. Ich mag es nicht, Zeit bei der Arbeit zu verbringen. Wenn es nach mir ginge, würde ich gerne spielen und lustige Dinge machen. Fühlst du dich genauso wie ich?

Jetzt muss ich manchmal zur Arbeit gehen. Es ist traurig, aber wahr. Wenn ich also bei der Arbeit bin, habe ich die Regel: Ich versuche weniger zu arbeiten. So nahe an keiner Arbeit wie ich kann. Dann geh ich spielen!

Hier also die große Neuigkeit: Das große O kann mir helfen, keine Arbeit zu machen! Ich kann mehr von der Zeit spielen, wenn ich großes O kenne. Weniger Arbeit, mehr Spiel! Das ist es, was mir das große O hilft.

Jetzt habe ich etwas Arbeit. Ich habe diese Liste: eins, zwei, drei, vier, fünf, sechs. Ich muss alle Dinge in diese Liste aufnehmen. 

Wow, ich hasse Arbeit. Aber ich muss das tun. Also los gehts.

Eins plus zwei ist drei ... plus drei ist sechs ... und vier sind ... ich weiß es nicht. Ich habe mich verlaufen. Es ist mir zu schwer in meinem Kopf zu tun. Diese Art von Arbeit interessiert mich nicht.

Also lasst uns die Arbeit nicht machen. Lass dich und ich einfach darüber nachdenken, wie schwer es ist. Wie viel Arbeit müsste ich tun, um sechs Zahlen hinzuzufügen?

Okay, lass uns nachsehen. Ich muss eins und zwei hinzufügen, und dann drei zu drei und dann zu vier ... Alles in allem zähle ich sechs addiert. Ich muss sechs Zusätze machen, um das zu lösen.

Hier kommt großes O, um uns zu sagen, wie schwer diese Mathematik ist.

Big O sagt: Wir müssen sechs Dinge hinzufügen, um das zu lösen. Eine hinzufügen für jedes Ding von eins bis sechs. Sechs kleine Arbeiten ... jedes Stück ist eins.

Nun, ich werde die Arbeit nicht tun, um sie jetzt hinzuzufügen. Aber ich weiß, wie schwer es sein würde. Es wären sechs Zusätze.

Oh nein, jetzt habe ich mehr Arbeit. Sheesh Wer macht so was ?!

Jetzt bitten sie mich, eins bis zehn hinzuzufügen! Warum sollte ich das tun? Ich wollte nicht eins zu sechs hinzufügen. Von eins bis zehn hinzufügen ... na ja, das wäre noch schwieriger!

Wie viel schwieriger wäre es? Wie viel mehr Arbeit müsste ich tun? Brauche ich mehr oder weniger Schritte?

Nun, ich denke, ich müsste zehn Zusätze machen ... einen für jede Sache von eins bis zehn. Zehn ist mehr als sechs. Ich müsste viel mehr arbeiten, um eins bis zehn hinzuzufügen, als eins bis sechs!

Ich möchte jetzt nicht hinzufügen. Ich möchte nur darüber nachdenken, wie schwer es sein könnte, so viel hinzuzufügen. Und ich hoffe, so schnell ich kann zu spielen.

Um eins bis sechs hinzuzufügen, ist das etwas Arbeit. Aber sehen Sie, um eins zu zehn hinzuzufügen, ist das mehr Arbeit?

Big O ist dein Freund und meins. Big O hilft uns dabei zu überlegen, wie viel Arbeit wir machen müssen, damit wir planen können. Und wenn wir mit Big O befreundet sind, kann er uns helfen, eine Arbeit zu wählen, die nicht so schwer ist!

Jetzt müssen wir neue Arbeit machen. Ach nein. Ich mag diese Arbeit überhaupt nicht.

Die neue Arbeit ist: Addiere alle Dinge von eins bis n.

Warten! Was ist n? Habe ich das vermisst? Wie kann ich eins zu n hinzufügen, wenn Sie mir nicht sagen, was n ist?

Nun, ich weiß nicht was n ist. Mir wurde nicht gesagt Warst du? Nein? Naja. Also können wir die Arbeit nicht machen. Wütend.

Aber obwohl wir die Arbeit jetzt nicht machen werden, können wir erraten, wie schwer es sein würde, wenn wir wüssten. Wir müssten n Dinge zusammenzählen, richtig? Na sicher!

Jetzt kommt das große O, und er wird uns sagen, wie schwer diese Arbeit ist. Er sagt: Alle Dinge von N bis Eins hinzuzufügen, ist O (n). Um all diese Dinge hinzuzufügen, muss ich n-mal hinzufügen. [1] Das ist ein großes O! Er sagt uns, wie schwer es ist, irgendeine Arbeit zu erledigen.

Für mich denke ich an ein großes O wie einen großen, langsamen Boss-Mann. Er denkt an die Arbeit, tut es aber nicht. Er könnte sagen: "Diese Arbeit ist schnell." Oder er könnte sagen: "Diese Arbeit ist so langsam und hart!" Aber er macht die Arbeit nicht. Er schaut sich nur die Arbeit an und sagt uns dann, wie viel Zeit das dauern kann.

Ich interessiere mich viel für großes O. Warum? Ich arbeite nicht gern! Niemand arbeitet gerne. Deshalb lieben wir alle das große O! Er sagt uns, wie schnell wir arbeiten können. Er hilft uns dabei zu denken, wie hart Arbeit ist.

Oh, mehr Arbeit. Nun machen wir die Arbeit nicht. Aber machen wir uns Schritt für Schritt einen Plan.

Sie gaben uns zehn Karten. Sie sind alle durcheinander: sieben, vier, zwei, sechs ... überhaupt nicht gerade. Und jetzt ... ist es unsere Aufgabe, sie zu sortieren.

Ergh. Das hört sich nach viel Arbeit an!

Wie können wir dieses Deck sortieren? Ich habe einen Plan.

Ich werde jedes Kartenpaar paarweise durch das Deck von Anfang bis Ende betrachten. Wenn die erste Karte in einem Paar groß ist und die nächste Karte in diesem Paar klein ist, tausche ich sie. Sonst gehe ich zum nächsten Paar und so weiter und so weiter ... und bald ist das Deck fertig.

Wenn das Deck fertig ist, frage ich: Habe ich in diesem Pass Karten ausgetauscht? Wenn ja, muss ich alles noch einmal von oben machen.Irgendwann, irgendwann wird es keine Swaps geben, und unsere Art von Deck wäre erledigt. So viel Arbeit!.

Nun, wie viel Arbeit wäre das, um die Karten nach diesen Regeln zu sortieren?

Ich habe zehn Karten. Die meiste Zeit - wenn ich also nicht viel Glück habe - muss ich das ganze Deck bis zu zehnmal durchlaufen, wobei jedes Mal bis zu zehn Kartentausch durch das Deck erfolgen.

Big O, hilf mir!.

Big O kommt herein und sagt: Für einen Stapel von n Karten wird es in einer Zeit von O (N im Quadrat) erledigt, um dies auf diese Weise zu sortieren.

Warum sagt er n im Quadrat?.

Nun, Sie wissen, dass n im Quadrat n mal n ist. Nun, ich bekomme es: n Karten geprüft, bis zu n mal durch das Deck. Das sind zwei Schleifen mit jeweils n Schritten. Das ist eine Menge Arbeit, die erledigt werden muss. Sicher eine Menge Arbeit!

Wenn nun ein großes O sagt, dass es eine O (n-Quadrat) -Erarbeit braucht, bedeutet es nicht, dass es n-Quadrat-Additionen auf der Nase ist. In manchen Fällen könnte es etwas kleiner sein. Im schlimmsten Fall ist es jedoch in der Nähe von n quadratischen Arbeitsschritten, um das Deck zu sortieren.

Jetzt ist hier das große O unser Freund.

Big O weist darauf hin: Wenn n groß wird, wird die Arbeit beim Sortieren von Karten VIEL VIEL HÄRTER als der alte Job "Just-Add-Thats". Woher wissen wir das?.

Wenn n wirklich groß wird, ist es uns egal, was wir zu n oder n quadrieren.

Für großes n ist n Quadrat größer als n. 

Big O sagt uns, dass es schwieriger ist, Dinge zu sortieren, als Dinge hinzuzufügen. O (n im Quadrat) ist mehr als O(n) für großes n. Das heißt: Wenn n wirklich groß wird, MUSS ein gemischtes Deck aus n Dingen mehr Zeit in Anspruch nehmen, als nur n gemischte Dingen hinzuzufügen.

Big O löst die Arbeit nicht für uns. Big O sagt uns, wie schwer die Arbeit ist.

Ich habe ein Kartenspiel. Ich habe sie sortiert. Du hast geholfen. Vielen Dank.

Gibt es eine schnellere Möglichkeit, die Karten zu sortieren? Kann das große O uns helfen?.

Ja, es geht schneller! Das Lernen dauert einige Zeit, aber es funktioniert ... und es funktioniert ziemlich schnell. Sie können es auch versuchen, aber nehmen Sie sich bei jedem Schritt Zeit und verlieren Sie nicht Ihren Platz.

Auf diese neue Art, ein Deck zu sortieren, prüfen wir keine Kartenpaare wie vor einer Weile. Hier sind deine neuen Regeln, um dieses Deck zu sortieren:.

Erstens: Ich wähle eine Karte in dem Teil des Decks, an dem wir gerade arbeiten. Sie können eine für mich auswählen, wenn Sie möchten. (Das erste Mal, wenn wir das tun, "der Teil des Decks, an dem wir jetzt arbeiten", ist natürlich das gesamte Deck.)

Zweitens: Ich spiele das Deck mit der von Ihnen gewählten Karte. Was ist das Spieß? Wie spreche ich? Nun, ich gehe von der Startkarte nach unten und suche nach einer Karte, die höher ist als die Splay-Karte.

Drei: Ich gehe von der Endkarte nach oben und suche nach einer Karte, die niedriger ist als die Splay-Karte.

Sobald ich diese beiden Karten gefunden habe, tausche ich sie aus und suche nach weiteren Karten, die sie austauschen können. Das heißt, ich gehe zurück zu Schritt Zwei und spreche von der Karte, die Sie noch ausgewählt haben. 

Irgendwann wird diese Schleife (von zwei bis drei) enden. Es endet, wenn sich beide Hälften dieser Suche auf der Splay-Karte treffen. Dann haben wir gerade das Deck mit der Karte, die Sie in Schritt Eins gewählt haben, gespreizt. Nun sind alle Karten nahe am Start niedriger als die Splay-Karte. und die Karten am Ende sind höher als die Splay-Karte. Cooler Trick!.

Vier (und das ist der lustige Teil): Ich habe jetzt zwei kleine Decks, eines niedriger als die Splay-Karte und eines mehr High. Jetzt gehe ich auf jedem kleinen Deck zu Schritt 1! Das heißt, ich fange von Schritt Eins auf dem ersten kleinen Deck an, und wenn diese Arbeit abgeschlossen ist, beginne ich von Schritt Eins auf dem nächsten kleinen Deck.

Ich zerlege das Deck in Teile und sortiere jedes Teil, kleiner und kleiner, und irgendwann habe ich keine Arbeit mehr. Nun mag dies langsam erscheinen, mit allen Regeln. Aber glaub mir, es ist überhaupt nicht langsam. Es ist viel weniger Arbeit als die erste Art, Dinge zu sortieren! 

Wie heißt diese Sorte? Es heißt Quick Sort! Diese Sorte wurde von einem Mann namens C. A. R. Hoare gemacht und er nannte sie Quick Sort. Jetzt wird Quick Sort immer verwendet!

Quick Sort zerlegt große Decks in kleine. Das heißt, es löst große Aufgaben in kleinen auf.

Hmmm. Ich glaube, da gibt es eine Regel. Um große Aufgaben klein zu machen, teilen Sie sie auf.

Diese Art ist ziemlich schnell. Wie schnell Big O sagt uns: Diese Art erfordert im Normalfall O (n log n) Arbeit.

Ist es mehr oder weniger schnell als die erste Sorte? Big O, bitte hilf! 

Die erste Sorte war O (n im Quadrat). Schnelle Sortierung ist jedoch O (n log n). Sie wissen, dass n log n kleiner als n im Quadrat ist, für großes n, richtig? Nun, wir wissen, dass Quick Sort schnell ist!

Wenn Sie ein Deck sortieren müssen, was ist der beste Weg? Nun, Sie können machen, was Sie wollen, aber ich würde Quick Sort wählen.

Warum wähle ich Schnellsortierung? Ich arbeite natürlich nicht gern! Ich möchte, dass die Arbeit so schnell wie möglich erledigt ist.Woher weiß ich, dass Quick Sort weniger Arbeit bedeutet? Ich weiß, dass O (n log n) kleiner als O (n im Quadrat) ist. Die O's sind kleiner, daher ist Quick Sort weniger Arbeit!.

Jetzt kennen Sie meinen Freund, Big O. Er hilft uns, weniger zu arbeiten. Und wenn Sie großes O kennen, können Sie auch weniger arbeiten!.

Das hast du bei mir gelernt! Du bist so schlau! Ich danke dir sehr!

Jetzt ist die Arbeit erledigt und los geht's!

[1]: Es gibt eine Möglichkeit, alle Dinge von eins bis n gleichzeitig zu betrügen und hinzuzufügen. Ein Kind namens Gauß fand das heraus, als er acht Jahre alt war. Ich bin nicht so schlau, also frag mich nicht, wie er es gemacht hat


[1]: There is a way to cheat and add all the things from one to n, all at one time. Some kid named Gauss found this out when he was eight. I am not that smart though, so don't ask me how he did it .

11
johnwbyrd

Angenommen, es handelt sich um einen Algorithmus A, der mit einem Datensatz der Größe n etwas anfangen sollte.

Dann bedeutet O( <some expression X involving n> ) in einfachem Englisch:

Wenn Sie beim Ausführen von A Pech haben, sind möglicherweise X(n) Vorgänge erforderlich, um den Vorgang abzuschließen.

Zufällig gibt es bestimmte Funktionen (stellen Sie sie sich als Implementierungen von X (n)) vor, die recht häufig auftreten häufig. Diese sind bekannt und leicht zu vergleichen (Beispiele: 1, Log N, N, N^2, N!, etc ..)

Durch Vergleichen dieser Werte, wenn von A und anderen Algorithmen gesprochen wird, ist es einfach, die Algorithmen nach der Anzahl der Operationen zu ordnen, die sie ausführen dürfen (Worst-Case) müssen ausgefüllt werden.

Im Allgemeinen besteht unser Ziel darin, einen Algorithmus A so zu finden oder zu strukturieren, dass er eine Funktion X(n) hat, die eine möglichst niedrige Zahl zurückgibt.

9
Kjartan

Ich habe einen einfacheren Weg, die Zeitkomplexität zu verstehen. Die gebräuchlichste Metrik zur Berechnung der Zeitkomplexität ist die Big-O-Notation. Dadurch werden alle konstanten Faktoren entfernt, so dass die Laufzeit in Bezug auf N geschätzt werden kann, wenn sich N der Unendlichkeit nähert. Im Allgemeinen können Sie es so vorstellen:

statement;

Ist konstant Die Laufzeit der Anweisung ändert sich nicht in Bezug auf N

for ( i = 0; i < N; i++ )
  statement;

Ist linear Die Laufzeit der Schleife ist direkt proportional zu N. Wenn sich N verdoppelt, ist dies auch die Laufzeit.

for ( i = 0; i < N; i++ ) 
{
for ( j = 0; j < N; j++ )
  statement;
}

Ist quadratisch. Die Laufzeit der beiden Schleifen ist proportional zum Quadrat von N. Wenn sich N verdoppelt, erhöht sich die Laufzeit um N * N.

while ( low <= high ) 
{
 mid = ( low + high ) / 2;
 if ( target < list[mid] )
 high = mid - 1;
 else if ( target > list[mid] )
  low = mid + 1;
else break;
}

Ist logarithmisch. Die Laufzeit des Algorithmus ist proportional zur Anzahl der Male, an denen N durch 2 geteilt werden kann. Dies liegt daran, dass der Algorithmus den Arbeitsbereich bei jeder Iteration in zwei Hälften teilt.

void quicksort ( int list[], int left, int right )
{
  int pivot = partition ( list, left, right );
  quicksort ( list, left, pivot - 1 );
  quicksort ( list, pivot + 1, right );
}

Ist N * log (N). Die Laufzeit besteht aus N Schleifen (iterativ oder rekursiv), die logarithmisch sind. Daher ist der Algorithmus eine Kombination aus linearem und logarithmischem Algorithmus.

Im Allgemeinen ist es mit jedem Element in einer Dimension etwas zu tun, etwas mit jedem Element in zwei Dimensionen zu tun ist quadratisch, und der Arbeitsbereich in zwei Hälften zu teilen ist logarithmisch. Es gibt andere Big-O-Maße wie kubische, exponentielle und Quadratwurzel, die jedoch bei weitem nicht so häufig sind. Die große O-Notation wird als O () beschrieben, wobei das Maß ist. Der Quicksort-Algorithmus würde als O (N * log (N)) beschrieben.

Anmerkung: Bei alledem wurden die besten, durchschnittlichen und ungünstigsten Werte berücksichtigt. Jeder hätte seine eigene Big O-Notation. Beachten Sie auch, dass dies eine sehr vereinfachende Erklärung ist. Big O ist das häufigste, aber ich habe es auch komplexer gezeigt. Es gibt auch andere Notationen wie Big Omega, Little O und Big Theta. Sie werden ihnen wahrscheinlich nicht außerhalb eines Kurses zur Algorithmusanalyse begegnen. 

  • Mehr dazu unter: Hier
9
nitin kumar

Sagen Sie, Sie bestellen Harry Potter: Complete 8-Film Collection [Blu-ray] bei Amazon und laden die gleiche Filmsammlung gleichzeitig online herunter. Sie möchten testen, welche Methode schneller ist. Die Lieferung dauert fast einen Tag und der Download ist etwa 30 Minuten früher abgeschlossen. Großartig! Es ist also ein enges Rennen.

Was ist, wenn ich mehrere Blu-ray-Filme wie "Der Herr der Ringe", "Twilight", "The Dark Knight Trilogy" usw. bestelle und alle Filme gleichzeitig online lade? Diesmal dauert es noch einen Tag, bis die Lieferung abgeschlossen ist, der Online-Download dauert jedoch 3 Tage. Bei Online-Einkäufen hat die Anzahl der gekauften Artikel (Eingabe) keinen Einfluss auf die Lieferzeit. Die Ausgabe ist konstant. Wir nennen dies O(1).

Beim Online-Download ist die Downloadzeit direkt proportional zu den Dateigrößen (Eingabe). Wir nennen dies O(n).

Aus den Experimenten wissen wir, dass Online-Shopping besser skaliert als Online-Download. Es ist sehr wichtig, die O-Notation zu verstehen, da Sie damit die Skalierbarkeit und Effizienz von Algorithmen analysieren können.

Hinweis: Die Big O-Notation repräsentiert das Worst-Case-Szenario eines Algorithmus. Nehmen wir an, dass O(1) und O(n) die Worst-Case-Szenarien des obigen Beispiels sind.

Reference: http://carlcheo.com/compsci

9
raaz

Wenn Sie eine passende Vorstellung von Unendlichkeit in Ihrem Kopf haben, gibt es eine sehr kurze Beschreibung:

Die große O-Notation zeigt Ihnen die Kosten für die Lösung eines unendlich großen Problems.

Und außerdem

Konstante Faktoren sind vernachlässigbar

Wenn Sie auf einen Computer upgraden, der Ihren Algorithmus doppelt so schnell ausführen kann, wird dies durch die große O-Notation nicht bemerkt. Konstante Faktorverbesserungen sind zu gering, um überhaupt in dem Maßstab wahrgenommen zu werden, mit dem die große O-Notation funktioniert. Beachten Sie, dass dies ein beabsichtigter Teil des Designs der O-Notation ist.

Es kann jedoch etwas "größer" als ein konstanter Faktor erfasst werden.

Wenn Sie daran interessiert sind, Berechnungen durchzuführen, deren Größe "groß" genug ist, um als ungefähr unendlich betrachtet zu werden, dann ist die große O-Notation ungefähr die Kosten für die Lösung Ihres Problems.


Wenn das oben Genannte keinen Sinn ergibt, haben Sie keine kompatible Vorstellung von Unendlichkeit in Ihrem Kopf, und Sie sollten wahrscheinlich alle obigen Punkte ignorieren. Die einzige Möglichkeit, diese Ideen rigoros zu machen oder sie zu erklären, wenn sie nicht bereits intuitiv nützlich sind, besteht darin, Ihnen zunächst eine große O-Notation oder ähnliches beizubringen. (Wenn Sie jedoch die große O-Notation in der Zukunft gut verstanden haben, kann es sich lohnen, diese Ideen erneut zu betrachten.)

8
Hurkyl

Was ist eine einfache englische Erklärung der "Big O" -Notation?

Sehr schnelle Anmerkung:

Das O in "Big O" bezieht sich auf "Reihenfolge" (oder genau "Reihenfolge von").
Sie könnten also wortwörtlich die Idee bekommen, etwas zu bestellen, um sie zu vergleichen. 

  • "Big O" macht zwei Dinge:

    1. Schätzt, wie viele Schritte der Methode Ihr Computer anwendet, um eine Aufgabe auszuführen.
    2. Erleichtern Sie den Vergleich mit anderen, um festzustellen, ob es gut ist oder nicht.
    3. "Big O 'erreicht die beiden oben genannten Werte mit standardisierten Notations.
  • Es gibt sieben meistbenutzte Notationen

    1. O (1) bedeutet, dass Ihr Computer eine Aufgabe mit dem 1-Schritt erledigt hat. Er ist ausgezeichnet, Bestellnummer 1
    2. O (logN) bedeutet, dass Ihr Computer eine Aufgabe mit logN-Schritten erledigt hat
    3. O (N), beende eine Aufgabe mit N-Schritten, ihrer Messe, Auftrag Nr. 3
    4. O (NlogN), beendet eine Aufgabe mit O(NlogN)-Schritten, es ist nicht gut, Auftrag Nr. 4
    5. O (N ^ 2), erledige eine Aufgabe mit N^2 Schritten, es ist schlecht, Order No.5
    6. O (2 ^ N), erledige eine Aufgabe mit 2^N Schritten, es ist schrecklich, Order No.6
    7. O (N!), Erledige eine Aufgabe mit N! Schritten, es ist schrecklich, Order No.7

 enter image description here

Angenommen, Sie erhalten die Notation O(N^2). Sie wissen nicht nur, dass die Methode N * N-Schritte zur Erledigung einer Aufgabe benötigt, und Sie erkennen auch, dass sie aus ihrer Rangfolge nicht als O(NlogN) geeignet ist.

Bitte beachten Sie die Reihenfolge am Zeilenende, nur zum besseren Verständnis. Wenn alle Möglichkeiten in Betracht gezogen werden, gibt es mehr als 7 Notationen.

In CS werden die Schritte zum Ausführen einer Aufgabe als Algorithmen bezeichnet.
In der Terminologie wird die Big O-Notation verwendet, um die Leistung oder Komplexität eines Algorithmus zu beschreiben.

Außerdem legt Big O den ungünstigsten Fall fest oder misst die Upper-Bound-Schritte.
Sie können sich für den besten Fall auf Big-Ω (Big-Omega) beziehen.

Big-Ω (Big-Omega) -Notation (Artikel) | Khan Akademie

  • Zusammenfassung
    "Big O" beschreibt die Leistung des Algorithmus und wertet sie aus.

    oder formell adressieren, "Big O" klassifiziert die Algorithmen und standardisiert den Vergleichsprozess. 

7
JawSaw

Einfachste Art, es zu betrachten (in einfachem Englisch)

Wir versuchen herauszufinden, wie sich die Anzahl der Eingabeparameter auf die Laufzeit eines Algorithmus auswirkt. Wenn die Laufzeit Ihrer Anwendung proportional zur Anzahl der Eingabeparameter ist, dann heißt es in Big O of n. 

Die obige Aussage ist ein guter Anfang, aber nicht ganz richtig.

Eine genauere Erklärung (mathematisch)

Annehmen

n = Anzahl der Eingabeparameter

T (n) = Die tatsächliche Funktion, die die Laufzeit des Algorithmus als Funktion von n ausdrückt

c = eine Konstante

f (n) = Eine Näherungsfunktion, die die Laufzeit des Algorithmus als Funktion von n ausdrückt

Für Big O gilt die Approximation f(n) als ausreichend, solange die unten stehende Bedingung erfüllt ist.

lim     T(n) ≤ c×f(n)
n→∞

Die Gleichung wird als ... gelesen. Wenn sich n der Unendlichkeit nähert, ist T von n kleiner oder gleich dem c-fachen von n.

In der großen O-Notation wird dies als geschrieben

T(n)∈O(n)

Dies wird gelesen, da T von n in großem O von n ist.

Zurück zu Englisch

Basierend auf der obigen mathematischen Definition bedeutet dies, wenn Sie sagen, dass Ihr Algorithmus ein großes O von n ist, dies eine Funktion von n (Anzahl der Eingabeparameter) oder schneller ist. Wenn Ihr Algorithmus Big O von n ist, dann ist es auch automatisch das Big O von n Quadrat. 

Großes O von n bedeutet, dass mein Algorithmus mindestens so schnell läuft. Sie können nicht die Big-O-Notation Ihres Algorithmus betrachten und sagen, dass sie langsam ist. Man kann nur sagen, es ist schnell. 

Überprüfen Sie this out für ein Video-Tutorial zu Big O von UC Berkley. Es ist eigentlich ein einfaches Konzept. Wenn Sie Professor Shewchuck (auch bekannt als God-Level-Lehrer) hören, werden Sie sagen: "Oh, das ist alles, was es ist!". 

6
developer747

Dies ist eine sehr vereinfachte Erklärung, aber ich hoffe, dass sie die wichtigsten Details abdeckt.

Nehmen wir an, Ihr Algorithmus, der sich mit dem Problem befasst, hängt von einigen "Faktoren" ab. Nehmen wir zum Beispiel N und X.

Abhängig von N und X erfordert Ihr Algorithmus einige Operationen, zum Beispiel im WORST-Fall 3(N^2) + log(X).

Da Big-O keinen konstanten Faktor interessiert (aka 3), ist das Big-O Ihres Algorithmus O(N^2 + log(X)). Im Wesentlichen wird die Menge an Operationen übersetzt, die Ihr Algorithmus für die Worst-Case-Skalen benötigt.

4
nkt

Definition: - Big O-Notation ist eine Notation, die angibt, wie sich eine Algorithmus-Leistung verhält, wenn die Dateneingabe zunimmt. 

Wenn wir über Algorithmen sprechen, gibt es drei wichtige Säulen: Eingabe, Ausgabe und Verarbeitung von Algorithmen. Big O ist eine symbolische Notation, die besagt, wenn die Dateneingabe in welcher Geschwindigkeit erhöht wird, wird die Leistung der Algorithmusverarbeitung variieren.

Ich möchte Sie dazu ermutigen, dieses Youtube-Video zu sehen, das Big O Notation ausführlich mit Codebeispielen erklärt.

 Algorithm basic pillars

Nehmen Sie zum Beispiel an, dass ein Algorithmus 5 Datensätze benötigt und die zur Verarbeitung desselben Zeit 27 Sekunden dauert. Wenn wir nun die Datensätze auf 10 erhöhen, dauert der Algorithmus 105 Sekunden.

In einfachen Worten ist die benötigte Zeit das Quadrat der Anzahl der Datensätze. Wir können dies mit O (n ^ 2) bezeichnen. Diese symbolische Darstellung wird als Big O-Notation bezeichnet.

Bitte beachten Sie, dass die Einheiten alles in den Eingängen sein können, es können Bytes, Bits, Anzahl der Datensätze, die Leistung in jeder Einheit wie Sekunde, Minuten, Tage usw. gemessen werden. Es ist also nicht die genaue Einheit, sondern die Beziehung.

 Big O symbols

Schauen Sie sich zum Beispiel die Funktion "Function1" an, die eine Sammlung übernimmt und die Verarbeitung des ersten Datensatzes vornimmt. Bei dieser Funktion ist die Leistung jetzt gleich, unabhängig davon, ob Sie 1000, 10000 oder 100000 Datensätze eingegeben haben. Also können wir es mit O(1) bezeichnen.

void Function1(List<string> data)
{
string str = data[0];
}

Siehe nun die Funktion "Function2 ()". In diesem Fall erhöht sich die Verarbeitungszeit mit der Anzahl der Datensätze. Wir können diese Algorithmusleistung mit O(n) bezeichnen.

void Function2(List<string> data)
        {
            foreach(string str in data)
            {
                if (str == "shiv")
                {
                    return;
                }
            }
        }

Wenn wir für jeden Algorithmus eine Big-O-Notation sehen, können wir sie in drei Leistungskategorien einteilen: -

  1. Log und konstante Kategorie: - Jeder Entwickler würde seine Algorithmus-Leistung in dieser Kategorie gerne sehen.
  2. Linear: - Der Entwickler möchte keine Algorithmen in dieser Kategorie sehen, bis die letzte oder die einzige Option übrig ist.
  3. Exponential: - Hier wollen wir unsere Algorithmen nicht sehen und eine Überarbeitung ist erforderlich.

Indem wir uns die Big-O-Notation anschauen, kategorisieren wir gute und schlechte Zonen für Algorithmen.

 Bog O classification

Ich würde Ihnen empfehlen, dieses 10 Minuten Video anzuschauen, in dem Big O mit Beispielcode behandelt wird

https://www.youtube.com/watch?v=k6kxtzICG_g

4

Wenn ich dies einem 6-jährigen Kind erklären möchte, werde ich zum Beispiel einige Funktionen f(x) = x und f(x) = x ^ 2 zeichnen und ein Kind fragen, welche Funktion dies tun soll ist die obere Funktion oben auf der Seite. Dann fahren wir mit dem Zeichnen fort und sehen, dass x ^ 2 gewinnt. "Wer gewinnt" ist eigentlich die Funktion, die schneller wächst, wenn x zur Unendlichkeit neigt. "Funktion x ist in Big O von x ^ 2" bedeutet, dass x langsamer wächst als x ^ 2, wenn x zur Unendlichkeit neigt. Das Gleiche ist möglich, wenn x zu 0 tendiert. Wenn wir diese beiden Funktionen für x von 0 auf 1 zeichnen, wird x eine übergeordnete Funktion, so dass die Funktion x ^ 2 in Big O von x für x zu 0 tendiert ". Wenn das Kind älter wird, füge ich hinzu, dass Big O eine Funktion sein kann, die nicht schneller wächst, sondern auf dieselbe Weise wie eine gegebene Funktion. Außerdem wird Konstante verworfen. Also ist 2x in Big O von x.

3
user3745123

Vorwort

algorithm : Prozedur/Formel zur Lösung eines Problems


Wie analysieren Algorithmen und wie können wir Algorithmen miteinander vergleichen?

example: Sie und ein Freund werden aufgefordert, eine Funktion zu erstellen, um die Zahlen von 0 bis N zu summieren. Sie kommen mit f(x) und Ihr Freund mit g (x). Beide Funktionen haben das gleiche Ergebnis, jedoch einen anderen Algorithmus. Um die Effizienz der Algorithmen objektiv zu vergleichen, verwenden wir Big-O-Notation .

Big-O-Notation: beschreibt wie schnell die Laufzeit relativ zur Eingabe zunimmt, wenn die Eingabe beliebig groß wird.

3 Schlüssel zum Mitnehmen:

  1. Vergleiche wie schnell die Laufzeit wächstNICHTgenaue Laufzeiten vergleichen (abhängig von der Hardware)
  2. Nur mit Laufzeit betroffenes Wachstum relativ zur Eingabe (n)
  3. Wenn n willkürlich groß wird, konzentrieren Sie sich auf die Begriffe, die am schnellsten wachsen, wenn n groß wird (Unendlichkeit). AKA asymptotische Analyse

Raumkomplexität: Abgesehen von der Zeitkomplexität ist uns auch die Raumkomplexität wichtig (wie viel Speicher/Speicherplatz ein Algorithmus benötigt). Anstatt die Zeit der Operationen zu überprüfen, überprüfen wir die Größe der Speicherzuordnung.

3
Ryan Efendy

Ich habe eine wirklich großartige Erklärung für die O-Notation gefunden, vor allem für jemanden, der sich nicht besonders mit Mathematik beschäftigt.

https://rob-bell.net/2009/06/a-beginner-guide-to-big-o-notation/

Die Big O-Notation wird in der Informatik verwendet, um die Leistung zu beschreiben oder Komplexität eines Algorithmus. Großes O beschreibt speziell das Worst-Case-Szenario und kann zur Beschreibung der Ausführungszeit verwendet werden erforderlich oder der belegte Speicherplatz (z. B. im Arbeitsspeicher oder auf der Festplatte) von einer Algorithmus.

Jeder, der Programmierperlen oder eine andere Informatik gelesen hat Bücher und keine Grundkenntnisse in Mathematik haben eine Wand erreicht als sie Kapitel erreichten, in denen O (N log N) oder andere scheinbar erwähnt wurden verrückte Syntax. Hoffentlich hilft Ihnen dieser Artikel dabei, eine Verständnis der Grundlagen von Big O und Logarithmen.

Als erster Programmierer und zweiter Mathematiker (oder vielleicht dritter oder vierter) fand ich, dass der beste Weg, Big O gründlich zu verstehen, der war. einige Beispiele im Code erzeugen. Nachfolgend finden Sie einige allgemeine Befehle von Wachstum zusammen mit Beschreibungen und Beispielen wo möglich.

O(1)

O (1) beschreibt einen Algorithmus, der immer zur gleichen Zeit ausgeführt wird (oder Leerzeichen) unabhängig von der Größe des Eingabedatensatzes.

bool IsFirstElementNull(IList<string> elements) {
    return elements[0] == null; } O(N)

O(N)

O (N) beschreibt einen Algorithmus, dessen Leistung linear wächst und direkt proportional zur Größe des Eingangsdatensatzes. Das Beispiel Im Folgenden wird auch gezeigt, wie Big O die Worst-Case-Leistung bevorzugt Szenario; Eine übereinstimmende Zeichenfolge konnte bei jeder Iteration des .__ gefunden werden. for-Schleife und die Funktion würde früher zurückkehren, aber Big O-Notation wird Nehmen Sie immer die Obergrenze an, an der der Algorithmus die .__ ausführt. maximale Anzahl von Iterationen.

bool ContainsValue(IList<string> elements, string value) {
    foreach (var element in elements)
    {
        if (element == value) return true;
    }

    return false;
} 

AUF2)

AUF2) repräsentiert einen Algorithmus, dessen Leistung direkt ist proportional zum Quadrat der Größe des Eingabedatensatzes. Das ist Häufig bei Algorithmen, die verschachtelte Iterationen über die Daten beinhalten einstellen. Tiefere verschachtelte Iterationen führen zu O (N3), AUF4) usw.

bool ContainsDuplicates(IList<string> elements) {
    for (var outer = 0; outer < elements.Count; outer++)
    {
        for (var inner = 0; inner < elements.Count; inner++)
        {
            // Don't compare with self
            if (outer == inner) continue;

            if (elements[outer] == elements[inner]) return true;
        }
    }

    return false;
}

O (2N)

O (2N) bezeichnet einen Algorithmus, dessen Wachstum sich bei jeder Addition zu .__ verdoppelt. der Eingabedatensatz. Die Wachstumskurve eines O (2N) Funktion ist exponentiell - sehr flach, dann meteorisch ansteigend. Ein Beispiel eines O (2N) Funktion ist die rekursive Berechnung von Fibonacci Zahlen:

int Fibonacci(int number) {
    if (number <= 1) return number;

    return Fibonacci(number - 2) + Fibonacci(number - 1);
}

Logarithmen

Logarithmen sind etwas komplizierter zu erklären, daher verwende ich eine allgemeine Beispiel:

Die binäre Suche ist eine Technik, mit der sortierte Datensätze durchsucht werden. Es klappt indem Sie das mittlere Element des Datensatzes auswählen, im Wesentlichen das Medianwert und vergleicht ihn mit einem Zielwert. Wenn die Werte damit übereinstimmen. wird Erfolg zurückgeben. Wenn der Zielwert höher als der Wert von .__ ist. Das Sondenelement nimmt die obere Hälfte des Datensatzes und Führen Sie dieselbe Operation dagegen aus. Ebenso, wenn der Zielwert ist niedriger als der Wert des Sondenelements, das die .__ ausführt. Betrieb gegen die untere Hälfte. Die Daten werden weiterhin halbiert Mit jeder Iteration setzen, bis der Wert gefunden wurde oder bis den Datensatz nicht mehr aufteilen.

Diese Art von Algorithmus wird als O (log N) beschrieben. Die iterative Halbierung von Datensätzen, die im Beispiel für binäre Suche beschrieben werden, führt zu einem Wachstum Kurve, die am Anfang ihren Höhepunkt erreicht und mit der Größe langsam abflacht der Datensätze nehmen z. ein Eingabedatensatz mit 10 Elementen dauert eine Sekunde, ein Datensatz mit 100 Elementen dauert zwei Sekunden, und ein Datensatz mit 1000 Elementen dauert drei Sekunden. Die Verdoppelung der Größe des Eingabedatensatzes hat nur geringe Auswirkungen auf Sein Wachstum als nach einer einzigen Iteration des Algorithmus der Datensatz wird halbiert und ist daher mit einem Eingabedatensatz halb so groß wie Größe. Dies macht Algorithmen wie die binäre Suche äußerst effizient beim Umgang mit großen Datensätzen.

3
SIW

Big O beschreibt eine Klasse von Funktionen.

Es beschreibt, wie schnell Funktionen für große Eingabewerte wachsen.

Für eine gegebene Funktion f beschreibt O(f) alle Funktionen g(n), für die Sie ein n0 und eine Konstante c finden können, damit alle Werte von g(n) mit n> = n0 sind kleiner oder gleich c * f (n)

In weniger mathematischen Wörtern ist O(f) eine Menge von Funktionen .. _, und zwar alle Funktionen, die ab einem Wert von n0 langsamer oder so schnell wie f werden.

Wenn f(n) = n, dann 

g (n) = 3n ist in O (f). Weil konstante Faktoren keine Rolle spielen h (n) = n + 1000 ist in O(f), da sie für alle Werte kleiner sein können als 1000, aber für große O sind nur große Eingaben wichtig.

i(n) = n ^ 2 ist jedoch nicht in O(f), da eine quadratische Funktion schneller wächst als eine lineare.

2
xuma202

Ein großes O ist ein Mittel, um die oberen Grenzen jeder Funktion darzustellen. Wir verwenden es im Allgemeinen zum Ausdrücken der oberen Grenzen einer Funktion, die die Laufzeit eines Algorithmus angibt.

Ex: f(n) = 2 (n ^ 2) + 3n eine Funktion sein, die die Laufzeit eines hypothetischen Algorithmus darstellt, gibt die Big-O-Notation im Wesentlichen die Obergrenze dieser Funktion an, die 0 (n ^ 2)

Diese Notation besagt im Wesentlichen, dass für jede Eingabe 'n' die Laufzeit nicht größer sein wird als der durch die Big-O-Notation ausgedrückte Wert.

Stimmen Sie auch allen oben genannten Antworten zu. Hoffe das hilft !!

2
user3170122

Großes O im Klartext ist wie <= (kleiner oder gleich). Wenn wir für zwei Funktionen f und g sagen, f = O(g), bedeutet dies, dass f <= g ist. 

Dies bedeutet jedoch nicht, dass für irgendein n f(n) <= g (n) gilt. Tatsächlich bedeutet es, dass f in Bezug auf Wachstum kleiner oder gleich g ist . Dies bedeutet, dass nach einem Punkt f(n) <= c * g (n) ist, wenn c eine Konstante ist. Und nach einem Punkt bedeutet als für alle n> = n0, wobei n0 eine andere Konstante ist.

2
A. Mashreghi

Sie repräsentiert die Geschwindigkeit eines Algorithmus in auf lange Sicht.

Für eine wörtliche Analogie ist es Ihnen egal, wie schnell ein Läufer einen 100-m-Lauf oder sogar einen 5-km-Lauf sprintet. Sie interessieren sich mehr für Marathonläufer und vorzugsweise für Ultra-Marathonläufer (jenseits dessen die Analogie zum Laufen zusammenbricht und Sie auf die metaphorische Bedeutung von "Langfristig" zurückgreifen müssen).

Sie können sicher hier aufhören zu lesen.

Ich füge diese Antwort hinzu, weil ich überrascht bin, wie mathematisch und technisch die übrigen Antworten sind. Der Begriff "Langfristigkeit" im ersten Satz bezieht sich auf die willkürlich zeitaufwändigen Rechenaufgaben. Im Gegensatz zum Laufen, das durch die menschliche Kapazität begrenzt ist, kann die Ausführung bestimmter Algorithmen durch Rechenaufgaben sogar mehr als Millionen von Jahren dauern.

Was ist mit all diesen mathematischen Logarithmen und Polynomen? Es stellt sich heraus, dass Algorithmen intrinsisch auf diese mathematischen Ausdrücke bezogen sind. Wenn Sie die Höhe aller Kinder im Block messen, wird dies genauso viel Zeit in Anspruch nehmen wie Kinder. Dies ist untrennbar mit der Vorstellung von n ^ 1 oder nur n verbunden, wobei n nicht mehr als die Anzahl der Kinder im Block ist. Im Ultra-Marathon-Fall messen Sie die Höhe aller Kinder in Ihrer Stadt, müssen dann jedoch die Reisezeiten ignorieren und davon ausgehen, dass sie alle in einer Reihe verfügbar sind (ansonsten springen wir der aktuellen Erklärung voraus).

Angenommen, Sie versuchen dann, die Liste, die Sie aus den Kinderhöhen zusammengestellt haben, in der Reihenfolge der kürzesten Höhe bis zur längsten Höhe anzuordnen. Wenn es sich nur um die Kinder in Ihrer Nachbarschaft handelt, können Sie es nur beobachten und die geordnete Liste auflisten. Dies ist die "Sprint" -Analogie, und wir interessieren uns wirklich nicht für Sprints in der Informatik. Warum also einen Computer benutzen, wenn man etwas gucken kann?

Wenn Sie jedoch eine Liste der Höhen aller Kinder in Ihrer Stadt oder noch besser Ihres Landes erstellt haben, werden Sie feststellen, dass Ihre Vorgehensweise untrennbar mit dem mathematischen log und n ^ 2 zusammenhängt . Wenn Sie in Ihrer Liste nach dem kürzesten Kind suchen, seinen Namen in ein separates Notizbuch schreiben und aus dem ursprünglichen Notizbuch streichen, ist intrinsisch an das mathematische n ^ 2 gebunden. Wenn Sie daran denken, die Hälfte Ihres Notizbuchs zu ordnen, dann die andere Hälfte und dann die Ergebnisse zu kombinieren, gelangen Sie zu einer Methode, die intrinsisch an den Logarithmus gebunden ist.

Angenommen, Sie mussten zuerst in den Laden gehen, um ein Maßband zu kaufen. Dies ist ein Beispiel für einen Aufwand, der in kurzen Sprints von Bedeutung ist, z. B. beim Messen der Kinder im Block. Wenn Sie jedoch alle Kinder in der Stadt messen, können Sie diese Kosten ignorieren. Dies ist die intrinsische Verbindung zum mathematischen Abfallen von Polynomialausdrücken niedrigerer Ordnung.

Ich hoffe, ich habe erklärt, dass es sich bei der Big-O-Notation nur um die langfristige handelt, dass die Mathematik von Natur aus mit Berechnungsmethoden verbunden ist und dass das Weglassen mathematischer Ausdrücke und anderer Vereinfachungen in einem vernünftigen Sinn mit der langfristigen verbunden ist Weg.

Sobald Sie sich dessen bewusst sind, werden Sie feststellen, dass das Big-O wirklich super einfach ist, da die harte High-School-Mathematik einfach wegfällt. Der einzige schwierige Teil ist das Analysieren eines Algorithmus, um die mathematischen Ausdrücke zu identifizieren. Mit etwas Übung können Sie jedoch anfangen, Ausdrücke während der Analyse selbst zu löschen und Teile des Algorithmus sicher zu ignorieren, um sich nur auf den für das Big-O relevanten Teil zu konzentrieren. I. e. Sie sollten in der Lage sein, die meisten Situationen zu beobachten.

Glücklich, es war meine Lieblingsbeschäftigung in der Informatik - herauszufinden, dass etwas einfacher war, als ich dachte, und dann bei Google-Interviews zu zeigen, wann der Uneingeweihte eingeschüchtert werden würde, lol.

1
user2297550

Was ist eine einfache englische Erklärung der "Big O" -Notation?

Ich möchte betonen, dass das Antriebsmotiv für die "Big O" -Notation eine Sache ist, wenn eine Eingangsgröße des Algorithmus zu groß einige Teile (dh Konstanten, Koeffizienten, Terme) der Gleichung, die das Maß des Algorithmus beschreibt, wird zu so unbedeutend, dass wir ignorieren sie. Die Teile der Gleichung, die überleben, nachdem einige ihrer Teile ignoriert wurden, werden als “Big O” -Notation des Algorithmus bezeichnet. 

Wenn die Eingabegröße NICHT zu groß ist, ist die Vorstellung der “Big O” -Notation (obere Schranke) unwichtig. 


Les sagen, Sie möchten die Leistung des folgenden Algorithmus quantifizieren

int sumArray (int[] nums){
    int sum=0;   // taking initialization and assignments n=1
    for(int i=0;nums.length;i++){
        sum += nums[i]; // taking initialization and assignments n=1
    }
    return sum;
}

Nehmen wir im obigen Algorithmus an, dass Sie T(n) wie folgt herausfinden (zeitliche Komplexität): 

T(n) = 2*n + 2

Um die “Big O” -Notation zu finden, müssen wir eine sehr große Eingabegröße berücksichtigen:

n= 1,000,000   -> T(1,000,000) = 2,000,002
n=1,000,000,000  -> T(1,000,000,000) = 2,000,000,002
n=10,000,000,000  -> T(10,000,000,000) = 20,000,000,002

Diese ähnlichen Eingänge geben wir für eine andere Funktion an F(n) = n

n= 1,000,000   -> F(1,000,000) = 1,000,000 
n=1,000,000,000  -> F(1,000,000,000) = 1,000,000,000
n=10,000,000,000  -> F(10,000,000,000) = 10,000,000,000

Wie Sie als Eingabegröße sehen können, erhalten Sie zu groß die T(n) annähernd gleich oder näher an F(n), so dass die Konstante 2 und der Koeffizient 2 zu unbedeutend werden, jetzt die Vorstellung von Big O ”kommt herein, 

O(T(n)) = F(n)
O(T(n)) = n

Wir sagen, das große O von T(n) ist n, und die Notation ist O(T(n)) = n. Es ist die Obergrenze von T(n), da nzu groß erhält. Dasselbe gilt für andere Algorithmen.

TLDR: Big O erklärt die Leistung eines Algorithmus in mathematischer Hinsicht. 

Langsamere Algorithmen neigen dazu, mit n mit der Stärke von x oder vielen zu laufen, je nach Tiefe, wohingegen schnellere Algorithmen wie die binäre Suche bei O (log n) ausgeführt werden, wodurch sie schneller werden, wenn der Datensatz größer wird. Big O könnte mit anderen Ausdrücken mit n oder auch nicht mit n erklärt werden (dh: O(1)).

Man kann Big O berechnen, wenn man die komplexesten Linien des Algorithmus betrachtet.

Bei kleinen oder unsortierten Datensätzen kann Big O überraschend sein, da n log n Komplexitätsalgorithmen wie die binäre Suche für kleinere oder unsortierte Mengen langsam sein können. Ein einfaches Beispiel für die lineare Suche gegenüber der binären Suche finden Sie in meinem JavaScript-Beispiel:

https://codepen.io/serdarsenay/pen/XELWqN?editors=1011 (unten geschriebene Algorithmen)

function lineerSearch() {
  init();
  var t = timer('lineerSearch benchmark');
  var input = this.event.target.value;
  for(var i = 0;i<unsortedhaystack.length - 1;i++) {
    if (unsortedhaystack[i] === input) {
      document.getElementById('result').innerHTML = 'result is... "' + unsortedhaystack[i] + '", on index: ' + i + ' of the unsorted array. Found' + ' within ' + i + ' iterations';
      console.log(document.getElementById('result').innerHTML);
      t.stop(); 
      return unsortedhaystack[i]; 
    }
  }
}

function binarySearch () {
  init();
  sortHaystack();
  var t = timer('binarySearch benchmark');
  var firstIndex = 0;
  var lastIndex = haystack.length-1;
  var input = this.event.target.value;

  //currently point in the half of the array
  var currentIndex = (haystack.length-1)/2 | 0;
  var iterations = 0;

  while (firstIndex <= lastIndex) {
    currentIndex = (firstIndex + lastIndex)/2 | 0;
    iterations++;
    if (haystack[currentIndex]  < input) {
      firstIndex = currentIndex + 1;
      //console.log(currentIndex + " added, fI:"+firstIndex+", lI: "+lastIndex);
    } else if (haystack[currentIndex] > input) {
      lastIndex = currentIndex - 1;
      //console.log(currentIndex + " substracted, fI:"+firstIndex+", lI: "+lastIndex);
    } else {
      document.getElementById('result').innerHTML = 'result is... "' + haystack[currentIndex] + '", on index: ' + currentIndex + ' of the sorted array. Found' + ' within ' + iterations + ' iterations';
      console.log(document.getElementById('result').innerHTML);
      t.stop(); 
      return true;
    }
  }
}
0
serdarsenay

Big O - Wirtschaftlicher Standpunkt. 

Mein liebstes englisches Wort, um dieses Konzept zu beschreiben, ist der price, den Sie für eine Aufgabe zahlen, wenn sie größer wird. 

Betrachten Sie es als wiederkehrende Kosten anstelle von Fixkosten, die Sie am Anfang bezahlen würden. Die Fixkosten werden im Großen und Ganzen vernachlässigbar, da die Kosten nur wachsen und sich addieren. Wir möchten messen, wie schnell sie wachsen werden und wie schnell sie sich in Bezug auf den Rohstoff addieren, den wir für die eingesetzte Größe des Problems liefern. 

Wenn jedoch die anfänglichen Einrichtungskosten hoch sind und Sie nur eine kleine Menge des Produkts produzieren, möchten Sie diese Anfangskosten betrachten - sie werden auch Konstanten genannt.

Da diese Konstanten auf lange Sicht keine Rolle spielen, können wir mit dieser Sprache Aufgaben diskutieren, über die Art der Infrastruktur hinaus, auf der wir sie betreiben. Die Fabriken können also überall sein und die Arbeiter können wer auch immer sein - es ist alles Soße. Aber die Größe der Fabrik und die Anzahl der Arbeiter wären die Dinge, die wir mit zunehmendem Input und Output langfristig ändern könnten. 

Daher wird dies zu einer Annäherung von big picture, wie viel Sie ausgeben müssten, um etwas auszuführen. Da time und space hier die wirtschaftlichen Größen sind (d. H. Sie sind begrenzt), können sie beide in dieser Sprache ausgedrückt werden. 

Technische Anmerkungen: Einige Beispiele für zeitliche Komplexität - O(n) bedeutet im Allgemeinen, dass, wenn ein Problem die Größe 'n' hat, ich zumindest alles sehen muss. O (log n) bedeutet im Allgemeinen, dass ich die Größe des Problems halbiere und es prüfe und wiederhole, bis die Aufgabe erledigt ist. O (n ^ 2) bedeutet, dass ich Paare von Dingen betrachten muss (z. B. Handshakes bei einer Party zwischen n Personen). 

0
snagpaul