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?
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.
i
läuft die innere Schleife mindestens zweimal. Das passiert n/2
mal.i
durch 4 teilbar läuft die innere Schleife mindestens dreimal. Das passiert n/4
mal.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).
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))
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!
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.
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
do
eine Schleife,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).