Lussen en geneste lussen analyseren
Bereken de tijdcomplexiteit van enkele lussen, geneste lussen en lussen met krimpende bereiken, zoals bij binary search of driehoeksiteraties.
Lussen en geneste lussen analyseren is een gratis Voorbereiding op programmeerinterviews-les op CoddyKit. Dit is les 2 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Voorbereiding op programmeerinterviews. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Voorbereiding op programmeerinterviews bevat in totaal 4 lessen.
Eén lus: O(n)
De eenvoudigste lus voert de inhoud n keer uit en is dus O(n). Een grotere stap verandert het aantal uitvoeringen, maar niet de klasse. Begin altijd met tellen hoe vaak de inhoud wordt uitgevoerd. Bekijk de code.
# O(n): body runs n times
def count_ops_linear(n):
ops = 0
for i in range(n):
ops += 1 # constant work
return ops
print(count_ops_linear(100)) # 100
# Still O(n): step=2 halves count but same class
def count_ops_half(n):
ops = 0
for i in range(0, n, 2):
ops += 1
return ops
print(count_ops_half(100)) # 50 => O(n)Geneste lussen: O(n²) en verder
Twee geneste lussen die elk n keer lopen, geven n x n = O(n^2); drie lussen geven O(n^3). Maar als de binnenste lus een vast aantal keer loopt, blijft het geheel lineair.
def count_pairs(n):
ops = 0
for i in range(n): # n iterations
for j in range(n): # n iterations each
ops += 1
return ops
print(count_pairs(10)) # 100 = 10^2
print(count_pairs(100)) # 10000 = 100^2
# Doubling n quadruples ops: classic O(n^2)Driehoekslus: O(n²/2) = O(n²)
Wanneer de binnenste lus bij i+1 begint, vormen de iteraties een driehoek: n(n-1)/2, wat na het weglaten van de helft nog steeds O(n^2) is. Problemen met alle unieke paren zien er zo uit.
def count_unique_pairs(n):
ops = 0
for i in range(n): # n iterations
for j in range(i+1, n): # n-1, n-2, ..., 0
ops += 1
return ops
print(count_unique_pairs(10)) # 45 = 10*9/2
print(count_unique_pairs(100)) # 4950
# Still O(n^2) -- constant factor 1/2 droppedLus met krimpende bereik: O(log n)
Wanneer de lusvariabele bij elke stap wordt gehalveerd, krijg je O(log n). De belangrijkste vraag is: krimpt het bereik vermenigvuldigend (log n) of optellend (n)? Bekijk de code.
def count_log_ops(n):
ops = 0
i = n
while i >= 1:
ops += 1
i //= 2 # halve each iteration
return ops
import math
for n in [8, 16, 64, 1024]:
ops = count_log_ops(n)
print(f'n={n}, ops={ops}, log2={int(math.log2(n))}')
# ops tracks log2(n) closelyGeneste lus met krimpende binnenste lus: O(n log n)
Een buitenste lus die n keer loopt met een binnenste lus van O(log n) geeft O(n log n) — de vorm van mergesort. Een binnenste stap van O(log n) herkennen is de sleutel tot het analyseren van sorteringen.
import math
def count_n_log_n(n):
ops = 0
for i in range(n): # n iterations
j = n
while j >= 1: # log n iterations
ops += 1
j //= 2
return ops
for n in [8, 32, 128]:
ops = count_n_log_n(n)
predicted = int(n * math.log2(n))
print(f'n={n}: actual={ops}, n*log2(n)~={predicted}')Afhankelijke binnenste lussen
Wanneer het bereik van de binnenste lus afhangt van de index van de buitenste lus, tel je het totale aantal iteraties, niet het aantal per stap. Een binnenste lus die van 0 tot i loopt, geeft n(n-1)/2 = O(n^2). Bekijk de code.
# Inner loop runs i times: total = 0+1+2+...+(n-1) = n(n-1)/2 => O(n^2)
def sum_inner_i(n):
ops = 0
for i in range(n):
for j in range(i): # runs 0,1,2,...,n-1 times
ops += 1
return ops
print(sum_inner_i(10)) # 45 = 10*9/2 => O(n^2)
# Inner loop runs n/i times (i doubles): sum ≈ n*log n => O(n log n)
def sum_inner_n_over_i(n):
ops = 0
i = 1
while i <= n:
for j in range(n // i):
ops += 1
i *= 2
return ops
print(sum_inner_n_over_i(64)) # ~ 64*6 = 384Bubblesort stap voor stap analyseren
Bubblesort voert n(n-1)/2 vergelijkingen uit en is dus O(n^2). Zelfs met vroegtijdig stoppen heeft een omgekeerd gesorteerde invoer elke vergelijking nodig. Te langzaam voor grote invoeren.
def bubble_sort(arr):
n = len(arr)
comparisons = 0
for i in range(n):
swapped = False
for j in range(0, n - i - 1):
comparisons += 1
if arr[j] > arr[j+1]:
arr[j], arr[j+1] = arr[j+1], arr[j]
swapped = True
if not swapped: # early exit if sorted
break
return comparisons
arr = list(range(10, 0, -1)) # worst case: reversed
ops = bubble_sort(arr)
print(f'Sorted: {arr}')
print(f'Comparisons: {ops}') # 45 = 10*9/2Lussen over strings en substrings
Let op: Python slicing is O(k) en niet gratis, en strings samenvoegen met + in een lus is O(n^2), omdat er elke keer wordt gekopieerd. Gebruik in plaats daarvan ''.join(parts)'. Bekijk de code.
# O(n^2): string concat in loop
def build_bad(n):
s = ''
for i in range(n):
s += str(i) # copies s each time!
return s
# O(n): join is a single pass
def build_good(n):
parts = []
for i in range(n):
parts.append(str(i))
return ''.join(parts)
print(build_good(10)) # '0123456789'Meerdere invoerparameters
Bij twee invoeren kan de complexiteit beide gebruiken: O(m + n) voor afzonderlijk werk en O(m x n) voor genest werk. Grafen worden vaak beschreven als O(V + E). Geef elke variabele een duidelijke naam.
# O(m + n): two independent loops
def independent(m, n):
a = sum(range(m)) # O(m)
b = sum(range(n)) # O(n)
return a + b # total O(m + n)
# O(m * n): nested
def nested(m, n):
count = 0
for i in range(m): # O(m)
for j in range(n): # O(n) each
count += 1
return count # O(m * n)
print(independent(5, 10)) # 10 + 45 = 55
print(nested(5, 10)) # 50Lussen in lussen versus opeenvolgende aanroepen
Een functieaanroep is niet gratis — de binnenste lus telt ook mee. Roep je een hulpfunctie van O(n) n keer aan, dan krijg je O(n^2). Kijk bij een analyse altijd in aanroepen die als zwarte doos worden behandeld.
# Naive string matching: O(n*m)
def naive_search(text, pattern):
n, m = len(text), len(pattern)
matches = []
for i in range(n - m + 1): # O(n)
if text[i:i+m] == pattern: # O(m) comparison + O(m) slice
matches.append(i)
return matches
# Total: O(n*m)
print(naive_search('abcabcabc', 'abc')) # [0, 3, 6]Praktijk: complexiteit in één oogopslag herkennen
Maak er een gewoonte van: tel de niveaus van geneste lussen, controleer of de binnenste lus afhangt van de buitenste en let op verborgen kosten in functieaanroepen en slicing. De code is een puzzel om uit te proberen.
# What is the complexity of this function?
def mystery(nums):
result = []
for i in range(len(nums)): # O(n)
for j in range(i, len(nums)): # O(n) worst
if sum(nums[i:j+1]) == 0: # O(n) slice + sum!
result.append((i, j))
return result
# Answer: O(n^3) -- three nested n-proportional ops
# Outer O(n) x inner O(n) x sum/slice O(n) = O(n^3)Korte controle
Korte controle — kijk hoe goed de technieken voor lusanalyse zijn blijven hangen. Vertrouw hier op je redenering. 💪
Samenvatting van de les
Samenvatting: geneste lussen vermenigvuldigen en onafhankelijke lussen tellen op, een binnenste lus die halveert geeft O(n log n), en ook verborgen kosten in aanroepen en slicing moeten worden meegeteld.
Leer Voorbereiding op programmeerinterviews met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 90
- Lessen
- 360
Veelgestelde vragen
Is de les “Lussen en geneste lussen analyseren” gratis?
Ja — de volledige tekst van “Lussen en geneste lussen analyseren” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus Voorbereiding op programmeerinterviews wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus Voorbereiding op programmeerinterviews bevat in totaal 4 lessen.
Wat leer ik in “Lussen en geneste lussen analyseren”?
Bereken de tijdcomplexiteit van enkele lussen, geneste lussen en lussen met krimpende bereiken, zoals bij binary search of driehoeksiteraties. Je oefent met Voorbereiding op programmeerinterviews door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met Voorbereiding op programmeerinterviews te beginnen?
Ervaring vooraf is niet nodig. Voorbereiding op programmeerinterviews op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 2 van 4.
Hoe lang duurt de les “Lussen en geneste lussen analyseren”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over Voorbereiding op programmeerinterviews?
Ja. Elke les over Voorbereiding op programmeerinterviews bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- Big-O-notatie vanaf de basis
- Lussen en geneste lussen analyseren
- Recursie en de recursieboom-methode
- Ruimtecomplexiteit en afwegingen