web-dev-qa-db-de.com

Big-O-Komplexität eines Codes

Ich habe eine Frage zum Algorithmusentwurf zur Komplexität. In dieser Frage wird ein Stück Code gegeben, und ich sollte die Komplexität dieses Codes berechnen. Der Pseudo-Code lautet:

for(i=1;i<=n;i++){
    j=i
    do{
        k=j;
        j = j / 2;
    }while(k is even);
}

Ich habe diesen Algorithmus für einige Zahlen ausprobiert. und ich habe unterschiedliche Ergebnisse erzielt. Wenn beispielsweise n = 6 ist, ist diese Algorithmusausgabe wie folgt

i = 1 -> executes 1 time
i = 2 -> executes 2 times
i = 3 -> executes 1 time
i = 4 -> executes 3 times
i = 5 -> executes 1 time
i = 6 -> executes 2 times

Es gibt kein reguläres Thema, wie soll ich das berechnen?

54
Behzad Hassani

Die von den anderen Antworten gegebene obere Grenze ist tatsächlich zu hoch. Dieser Algorithmus hat eine O(n) - Laufzeit, die eine engere Obergrenze als O (n * logn) ist.

Beweis: Zählen wir, wie viele Iterationen die innere Schleife insgesamt durchführt.

Die äußere Schleife läuft n mal. Die innere Schleife läuft mindestens einmal für jede davon.

  • Bei i läuft die innere Schleife mindestens zweimal. Das passiert n/2 mal.
  • Bei i durch 4 teilbar läuft die innere Schleife mindestens dreimal. Das passiert n/4 mal.
  • Bei i durch 8 teilbar läuft die innere Schleife mindestens viermal. Das passiert n/8 mal.
  • ...

Insgesamt läuft also die innere Schleife:

n + n/2 + n/4 + n/8 + n/16 + ... <= 2n

Die Gesamtzahl der Iterationen der inneren Schleife liegt zwischen n und 2n, d. H. Es ist Θ (n).

99
interjay

Sie nehmen immer an, dass Sie in jedem Level das schlechteste Szenario erhalten. 
Jetzt durchlaufen Sie ein Array mit N Elementen. Wir beginnen also bereits mit O(N).
Nehmen wir an, Ihre i ist immer gleich X und X ist immer gleich (denken Sie daran, jedes Mal im schlechtesten Fall).
Wie oft müssen Sie X durch 2 teilen, um 1 zu erhalten? (Dies ist die einzige Bedingung, dass gerade Zahlen die Division stoppen, wenn sie 1 erreichen).
Mit anderen Worten, wir müssen die Gleichung lösen X/2^k = 1, die X=2^k und k=log<2>(X)__ ist. Dies führt dazu, dass unser Algorithmus O(n log<2>(X))-Schritte durchführt, die einfach als O(nlog(n)) 

6
David Haim

Für eine solche Schleife können wir die Anzahl der inneren und äußeren Schleife nicht voneinander trennen - Variablen sind eng!

Wir müssen also alle Schritte zählen.

Tatsächlich haben wir für jede Iteration der äußeren Schleife (auf i

1 + v_2(i) steps

dabei ist v_2 die 2-adic-Bewertung (siehe zum Beispiel: http://planetmath.org/padicvaluation ), die der Potenz von 2 bei der Zerlegung in Primfaktor von i entspricht.

Wenn wir also für alle i Schritte hinzufügen, erhalten wir eine Gesamtzahl von Schritten:

n_steps = \sum_{i=1}^{n} (1 + v_2(i)) 
        = n + v_2(n!)    // since v_2(i) + v_2(j) = v_2(i*j)
        = 2n - s_2(n)    // from Legendre formula (see http://en.wikipedia.org/wiki/Legendre%27s_formula with `p = 2`)

Wir sehen dann, dass Anzahl der Schrittegenau ist:

n_steps = 2n - s_2(n)

Da s_2(n) die Summe der Ziffern von n in der Basis 2 ist, ist sie vernachlässigbar (höchstens log_2(n), da die Ziffer in der Basis 2 0 oder 1 ist und da höchstens log_2(n)-Ziffern vorhanden sind) im Vergleich zu n.

Die Komplexität Ihres Algorithmus entspricht also n:

n_steps = O(n)

welches ist not die O(nlog(n)), die in vielen anderen Lösungen angegeben ist, aber eine geringere Menge!

4

beginnen wir mit dem schlimmsten Fall:

wenn Sie weiter mit 2 (ganzzahlig) teilen, müssen Sie nicht aufhören, bis Sie zu 1. gelangen. Die Anzahl der Schritte hängt von der Bitbreite ab. also ist der innere Teil log n . der äußere Teil ist offensichtlich n, also N log N total.

0
sp2danny

Eine do-Schleife halbiert j, bis k ungerade wird. k ist anfangs eine Kopie von j, die eine Kopie von i ist, so dass do 1 + Potenz von 2 ausführt, die i teilt

  • i = 1 ist ungerade, also durchläuft do eine Schleife,
  • i = 2 mal durch 2 dividiert, also 1 + 1,
  • i = 4 dividiert zweimal durch 2, also 1 + 2 usw.

Das macht höchstens 1 + log (i) do Ausführungen (Logarithmus mit Basis 2).

Die for-Schleife durchläuft i von 1 bis n, so dass die obere Grenze n-mal (1 + log n) ist, also 0 (n log n).

0
CiaPan