web-dev-qa-db-ger.com

Sind da irgendwelche O(1/n) Algorithmen?

Gibt es O(1/n) Algorithmen?

Oder etwas anderes, das weniger als O (1) ist? 

320
Shalmanese

Diese Frage ist nicht so dumm, wie es scheinen mag. Zumindest theoretisch ist etwas wie O (1/n) völlig vernünftig, wenn wir die mathematische Definition der Big O-Notation nehmen:

Jetzt können Sie g (x) für 1/x leicht ersetzen. Es ist offensichtlich, dass die obige Definition für einige f gilt.

Für die Abschätzung des asymptotischen Laufzeitwachstums ist dies weniger realisierbar… ein aussagekräftiger Algorithmus kann nicht schneller werden, wenn die Eingabe wächst. Natürlich können Sie einen beliebigen Algorithmus konstruieren, um dies zu erfüllen, z. die folgende:

def get_faster(list):
    how_long = (1 / len(list)) * 100000
    sleep(how_long)

Diese Funktion benötigt natürlich weniger Zeit, wenn die Eingabegröße zunimmt. Zumindest bis zu einem gewissen, von der Hardware erzwungenen Grenzwert (Genauigkeit der Zahlen, minimale Zeit, die sleep warten kann, Zeit für die Verarbeitung von Argumenten usw.): Dies wäre dann der Fall eine konstante untere Schranke, so hat die obige Funktion noch die Laufzeit O (1).

Es gibt jedoch are tatsächlich Algorithmen der realen Welt, bei denen sich die Laufzeit (zumindest teilweise) verringern kann, wenn die Eingabegröße zunimmt. Beachten Sie, dass diese Algorithmen jedoch nicht Laufzeitverhalten unter O (1) aufweisen. Trotzdem sind sie interessant. Nehmen Sie zum Beispiel den sehr einfachen Textsuchalgorithmus durch Horspool . Hier wird die erwartete Laufzeit mit zunehmender Länge des Suchmusters sinken (aber eine längere Länge des Heuhaufens erhöht die Laufzeit erneut).

298
Konrad Rudolph

Ja. 

Es gibt genau einen Algorithmus mit Laufzeit O (1/n), den "leeren" Algorithmus.

Ein Algorithmus O(1/n) bedeutet, dass er asymptotisch in weniger Schritten ausgeführt wird als der Algorithmus, der aus einem einzelnen Befehl besteht. Wenn es in weniger als einem Schritt für alle n> n0 ausgeführt wird, muss es aus genau keiner Anweisung für diese n bestehen. Da die Prüfung von 'wenn n> n0' mindestens eine Anweisung kostet, darf sie keine Anweisung für alle n enthalten.

Zusammenfassend: Der einzige Algorithmus, der O(1/n) ist, ist der leere Algorithmus, der aus der Anweisung " no " besteht. 

127
Tobias

Das ist nicht möglich. Die Definition von Big-O ist die nicht größer als Ungleichung:

A(n) = O(B(n))
<=>
exists constants C and n0, C > 0, n0 > 0 such that
for all n > n0, A(n) <= C * B(n)

Somit ist B(n) tatsächlich der Maximalwert. Wenn sich der Wert verringert, wenn n steigt, ändert sich die Schätzung nicht.

25
sharptooth

scharfzahn ist richtig, O(1) ist die bestmögliche Leistung. Es handelt sich jedoch nicht um eine schnelle Lösung, sondern nur um eine zeitlich festgelegte Lösung.

Eine interessante Variante, und was vielleicht wirklich vorgeschlagen wird, ist, welche Probleme einfacher werden, wenn die Bevölkerung wächst. Ich kann mir eine, wenn auch erfundene und freche Antwort vorstellen:

Haben zwei Personen im Set denselben Geburtstag? Wenn n 365 überschreitet, wird true zurückgegeben. Obwohl für weniger als 365, ist dies O (n ln n). Vielleicht keine gute Antwort, da das Problem nicht langsam einfacher wird, sondern nur zu O(1) für n> 365 wird.

23
Adrian

Von meinem früheren Lernen der Big-O-Notation, auch wenn Sie 1 Schritt benötigen (z. B. das Prüfen einer Variablen, das Zuweisen einer Zuweisung), ist dies O (1).

Beachten Sie, dass O(1) dasselbe ist wie O (6), da die "Konstante" keine Rolle spielt. Deshalb sagen wir, dass O(n) dasselbe ist wie O (3n).

Wenn Sie also nur 1 Schritt benötigen, ist das O (1) ... und da Ihr Programm mindestens 1 Schritt benötigt, ist der Mindestalgorithmus, den ein Algorithmus annehmen kann, O (1). Wenn wir es nicht tun, ist es O (0), denke ich? Wenn wir überhaupt etwas tun, dann ist es O (1), und das ist das Minimum, das es gehen kann.

(Wenn wir uns dafür entscheiden, es nicht zu tun, kann es zu einer Zen- oder Tao-Frage werden ... im Bereich der Programmierung ist O(1) immer noch das Minimum).

Oder wie wäre es damit: 

Programmierer : Chef, ich habe einen Weg gefunden, es in O(1) Zeit zu tun!
Chef : Keine Notwendigkeit, wir sind heute morgen bankrott.
Programmierer : Oh, dann wird es zu O (0).

15

Nein das ist nicht möglich:

Da n in 1/n gegen unendlich geht, erreichen wir schließlich 1/(inf), was effektiv 0 ist.

Somit wäre die Big-Oh-Klasse des Problems O(0) mit einem massiven n, aber näher an der konstanten Zeit mit einem niedrigen n. Dies ist nicht sinnvoll, da nur Folgendes in kürzerer Zeit erledigt werden kann:

void nothing() {};

Und auch das ist umstritten!

Sobald Sie einen Befehl ausführen, befinden Sie sich in mindestens O (1). Nein, wir können keine Big-Oh-Klasse von O (1/n) haben!

8
Ed James

Ich verwende häufig O(1/n), um Wahrscheinlichkeiten zu beschreiben, die mit zunehmenden Eingaben kleiner werden. Zum Beispiel ist die Wahrscheinlichkeit, dass eine faire Münze bei log2 (n) Flips auftaucht, 0 (1/n) ).

7
Dave

Was ist, wenn Sie die Funktion überhaupt nicht ausführen (NOOP)? oder mit einem festen Wert. Zählt das?

7
SpliFF

O (1) bedeutet einfach "konstante Zeit".

Wenn Sie einem Loop [1] einen frühen Abbruch hinzufügen, wird der Algorithmus O(1) zu O (n), jedoch in schneller O-Notation, aber schneller.

Der Trick ist im Allgemeinen Der Algorithmus für konstante Zeit ist der beste und linear ist besser als exponentiell, aber für kleine Mengen von n ist der exponentielle Algorithmus tatsächlich schneller.

1: Eine statische Listenlänge für dieses Beispiel voraussetzen

6
LapTop006

Ich glaube, Quantenalgorithmen können durch Superposition mehrere Berechnungen "auf einmal" ausführen ... 

Ich bezweifle, dass dies eine nützliche Antwort ist.

5

Für alle, die diese Frage lesen und verstehen möchten, worum es in dem Gespräch geht, könnte dies hilfreich sein:

|    |constant |logarithmic |linear|  N-log-N |quadratic|  cubic  |  exponential  |
|  n |  O(1)   | O(log n)   | O(n) |O(n log n)|  O(n^2) |  O(n^3) |     O(2^n)    |
|  1 |       1 |          1 |     1|         1|        1|       1 |             2 |
|  2 |       1 |          1 |     2|         2|        4|       8 |             4 |
|  4 |       1 |          2 |     4|         8|       16|      64 |            16 |
|  8 |       1 |          3 |     8|        24|       64|     512 |           256 |
| 16 |       1 |          4 |    16|        64|      256|   4,096 |         65536 |
| 32 |       1 |          5 |    32|       160|    1,024|  32,768 | 4,294,967,296 |
| 64 |       1 |          6 |    64|       384|    4,069| 262,144 |   1.8 x 10^19 |
5
Craig O'Connor

viele Leute hatten die richtige Antwort (Nein). Hier haben Sie eine andere Möglichkeit, das zu beweisen: Um eine Funktion zu haben, müssen Sie die Funktion aufrufen und eine Antwort zurückgeben. Dies dauert eine gewisse konstante Zeit. WENN der Rest der Verarbeitung für größere Eingaben weniger Zeit in Anspruch nahm, dauert das Ausdrucken der Antwort (was wir als ein einzelnes Bit annehmen können) mindestens eine konstante Zeit. 

3
Brian Postow

Wenn eine Lösung vorhanden ist, kann sie in konstanter Zeit = sofort vorbereitet und abgerufen werden. Verwenden Sie beispielsweise eine Datenstruktur LIFO, wenn Sie wissen, dass die Sortierabfrage in umgekehrter Reihenfolge ausgeführt wird. Dann sind die Daten bereits sortiert, da das geeignete Modell (LIFO) ausgewählt wurde.

2
Larsson

Sie können O (1) nicht unterschreiten, jedoch ist O(k) mit k kleiner als N möglich. Wir nannten sie sublineare Zeitalgorithmen . Bei einigen Problemen kann der sublineare Zeitalgorithmus nur annähernde Lösungen für ein bestimmtes Problem liefern. Manchmal ist eine ungefähre Lösung jedoch in Ordnung, wahrscheinlich weil der Datensatz zu groß ist oder es zu rechenaufwendig ist, um alles zu berechnen.

2
Hao Wooi Lim

Welche Probleme werden mit wachsender Bevölkerung leichter? Eine Antwort ist eine Sache wie Bittorrent, bei der die Downloadgeschwindigkeit eine inverse Funktion der Anzahl von Knoten ist. Im Gegensatz zu einem Auto, das mit zunehmender Belastung langsamer wird, beschleunigt ein Filesharing-Netzwerk wie Bittorrent die Anzahl der angeschlossenen Knoten.

2

Wie bereits erwähnt wurde, können, abgesehen von der möglichen Ausnahme der Nullfunktion, keine O(1/n)-Funktionen vorhanden sein, da die benötigte Zeit gegen 0 gehen muss.

Natürlich gibt es einige Algorithmen, wie die von Konrad definierten, die zumindest in gewissem Sinne weniger als O(1) zu sein scheinen.

def get_faster(list):
    how_long = 1/len(list)
    sleep(how_long)

Wenn Sie diese Algorithmen untersuchen möchten, sollten Sie entweder Ihre eigene asymptotische Messung oder Ihre eigene Zeitvorstellung definieren. In dem obigen Algorithmus könnte ich beispielsweise die Verwendung einer Anzahl von "freien" Operationen eine bestimmte Anzahl von Malen zulassen. Wenn ich im obigen Algorithmus t 'definiere, indem ich die Zeit für alles außer dem Schlaf ausschließe, dann ist t' = 1/n. Es gibt wahrscheinlich bessere Beispiele, da das asymptotische Verhalten trivial ist. Ich bin mir sicher, dass jemand da draußen mit Sinnen aufkommen kann, die nicht triviale Ergebnisse liefern.

1
Casebash

O (1/n) ist nicht kleiner als O (1). Dies bedeutet im Wesentlichen, dass je mehr Daten vorhanden sind, desto schneller wird der Algorithmus. Nehmen wir an, Sie bekommen ein Array und füllen es immer bis zu 10 aus100 Elemente, wenn es weniger als das hat und nichts tun, wenn es mehr gibt. Dies ist natürlich nicht O(1/n), sondern etwas wie O(-n) :) Zu schlechte O-Big-Notation erlaubt keine negativen Werte.

1
vava

Die meisten anderen Antworten interpretieren big-O ausschließlich als Laufzeit eines Algorithmus. Aber da die Frage es nicht erwähnte, hielt ich es für erwähnenswert, die andere Anwendung von Big-O in der numerischen Analyse zu erwähnen, bei der es um Fehler geht.

Viele Algorithmen können O (h ^ p) oder O (n ^ {- p}) sein, je nachdem, ob es sich um die Schrittgröße (h) oder die Anzahl der Unterteilungen (n) handelt. In Eulers Methode suchen Sie beispielsweise nach einer Schätzung von y(h), vorausgesetzt, Sie kennen y(0) und dy/dx (the Ableitung von y). Ihre Schätzung von y(h) ist genauer, je näher h an 0 ist. Um y(x) für ein beliebiges x zu finden, nimmt man das Intervall 0 bis x , teilt es auf bis zu n Teile auf und führt an jedem Punkt die Euler-Methode aus, um von y(0) zu y(x/n) zu y (2x/n) zu gelangen, und so weiter.

Eulers Methode ist also ein O(h) oder O(1/n) Algorithmus, wobei h typischerweise als Schrittgröße interpretiert wird und n als die Anzahl von Malen, die Sie ausführen Teilen Sie ein Intervall.

Sie können auch O(1/h) in Anwendungen für die reelle numerische Analyse verwenden, da Gleitkomma-Rundungsfehler . Je kürzer Sie Ihr Intervall einstellen, desto häufiger tritt bei der Implementierung bestimmter Algorithmen ein Abbruch auf, desto mehr signifikante Ziffern gehen verloren und desto mehr Fehler werden durch den Algorithmus übertragen.

Wenn Sie bei der Euler-Methode Gleitkommazahlen verwenden, verwenden Sie einen ausreichend kleinen Schritt und eine ausreichende Löschung, und Sie fügen einer großen Zahl eine kleine Zahl hinzu, wobei die große Zahl unverändert bleibt. Für Algorithmen, die die Ableitung durch Subtrahieren von zwei Zahlen von einer an zwei sehr engen Positionen bewerteten Funktion berechnen, wobei y '(x) mit (y (x + h) - y(x)/h approximiert wird ), in glatten Funktionen nähert sich y (x + h) y(x), was zu einer großen Löschung und einer Schätzung für die Ableitung mit weniger signifikanten Zahlen führt. Dies wird sich wiederum auf den Algorithmus ausbreiten, für den Sie die Ableitung benötigen (z. B. ein Grenzwertproblem).

1
Andrew Lei

In der numerischen Analyse sollten Approximationsalgorithmen in der Approximationstoleranz eine unterkonstante asymptotische Komplexität aufweisen.

class Function
{
    public double[] ApproximateSolution(double tolerance)
    {
        // if this isn't sub-constant on the parameter, it's rather useless
    }
}
0
Sam Harwell

OK, ich habe darüber nachgedacht und vielleicht gibt es einen Algorithmus, der dieser allgemeinen Form folgen könnte:

Sie müssen das Problem des fahrenden Verkäufers für ein Diagramm mit 1000 Knoten berechnen. Sie erhalten jedoch auch eine Liste mit Knoten, die Sie nicht besuchen können. Je größer die Liste der nicht sichtbaren Knoten wird, desto einfacher lässt sich das Problem lösen. 

0
Shalmanese

Ich sehe einen Algorithmus, der zwar O(1/n) zu einer oberen Schranke gehört:

Sie haben eine große Reihe von Eingängen, die sich aufgrund von etwas außerhalb der Routine ändern (möglicherweise ist dies Hardware, oder es könnte sogar ein anderer Kern des Prozessors sein, der das ausführt.), Und Sie müssen einen zufälligen, aber gültigen auswählen.

Wenn es sich nicht geändert hat, würden Sie einfach eine Liste von Elementen erstellen, einen zufällig auswählen und O(1) Zeit erhalten. Die dynamische Natur der Daten schließt jedoch das Erstellen einer Liste aus. Sie müssen lediglich nach dem Zufallsprinzip suchen und die Gültigkeit des Tests prüfen. (Beachten Sie, dass es inhärent keine Garantie gibt, dass die Antwort nach der Rückkehr noch gültig ist. Dies könnte immer noch die KI für eine Einheit in einem Spiel verwenden. Sie könnte auf ein Ziel schießen, das während dieser Zeit außer Sicht war den Abzug betätigen.)

Dies hat eine Worst-Case-Leistung von unendlich, aber die durchschnittliche Fallleistung sinkt, wenn sich der Datenraum auffüllt.

0
Loren Pechtel

Was ist mit diesem:

void FindRandomInList(list l)
{
    while(1)
    {
        int Rand = Random.next();
        if (l.contains(Rand))
            return;
    }
}

mit zunehmender Größe der Liste nimmt die erwartete Laufzeit des Programms ab.

0
Shalmanese

Ich denke, weniger als O(1) ist nicht möglich. Jede von algo benötigte Zeit wird als O (1) bezeichnet. Aber für O(1/n) wie wäre es mit der Funktion unten. (Ich weiß, es gibt viele Varianten, die in dieser Lösung bereits vorgestellt wurden, aber ich denke, sie haben alle einige Mängel (nicht große, sie erklären das Konzept gut).

def 1_by_n(n, C = 10):   #n could be float. C could be any positive number
  if n <= 0.0:           #If input is actually 0, infinite loop.
    while True:
      sleep(1)           #or pass
    return               #This line is not needed and is unreachable
  delta = 0.0001
  itr = delta
  while delta < C/n:
    itr += delta

Daher nimmt die Funktion mit zunehmendem n immer weniger Zeit in Anspruch. Es ist auch sichergestellt, dass, wenn die Eingabe tatsächlich 0 ist, die Funktion eine Ewigkeit benötigt, um zurückzukehren.

Man könnte argumentieren, dass dies durch die Präzision der Maschine begrenzt wird. daher hat sinc eit eine obere Schranke, es ist O (1). Das können wir aber auch umgehen, indem wir n und C in string eingeben. Das Hinzufügen und Vergleichen erfolgt über Zeichenfolge. Idee ist, dass wir damit n beliebig klein reduzieren können. Die Obergrenze der Funktion ist also nicht begrenzt, selbst wenn wir n = 0 ignorieren.

Ich glaube auch, dass wir nicht einfach sagen können, dass die Laufzeit 0 (1/n) ist. Aber wir sollten etwas sagen wie O (1 + 1/n)

0
user1953366