- Leren
- Informatica & ICT
- Informatica
- Informatica: hoe computers, data, algoritmen en internet werken
- Zoek- en sorteeralgoritmen
Zoek- en sorteeralgoritmen en efficiëntie
BeginnerLes 4 van 7 in Cursus Informatica: hoe computers, data, algoritmen en internet werken
Wat je leert
- Vind een zoekwaarde in een lijst met lineair zoeken en, als de lijst gesorteerd is, met binair zoeken. Doorloop beide methoden op concrete lijsten en tel hoeveel elementen ze controleren.
- Doorzoek een willekeurige lijst met lineair zoekenControleer elementen vanaf het begin één voor één, geef de positie van de eerste overeenkomst terug of meld dat de zoekwaarde ontbreekt, en tel de vergelijkingen in het beste en slechtste geval.
- Doorzoek een gesorteerde lijst met binair zoekenGebruik de gesorteerde volgorde om bij elke controle het resterende deel van de lijst te halveren, volg de onder-, boven- en middenpositie en leg uit waarom ongeveer log₂ n controles voldoende zijn.
- Doorzoek een willekeurige lijst met lineair zoeken
- Geef aan wat een correcte sortering moet opleveren, doorloop daarna bubblesort en selectionsort doorgang voor doorgang en tel hun vergelijkingen en verwisselingen.
- Beschrijf hoe een correct gesorteerde lijst eruitzietDefinieer gesorteerde volgorde, sorteersleutels, verwisselingen, stabiliteit, in-place sorteren en inversies, zodat je sorteeralgoritmen kunt doorlopen, controleren en vergelijken.
- Doorloop bubblesort en tel de bewerkingenSorteer een lijst door buren die in de verkeerde volgorde staan herhaaldelijk te verwisselen, volg het proces doorgang voor doorgang, stop vroegtijdig als een doorgang geen verwisselingen oplevert en tel de vergelijkingen en verwisselingen.
- Doorloop selectionsort en tel de bewerkingenSorteer een lijst door steeds het kleinste overgebleven element te selecteren en op zijn plaats te verwisselen, volg het proces doorgang voor doorgang en vergelijk de aantallen vergelijkingen en verwisselingen met die van bubblesort.
- Beschrijf hoe een correct gesorteerde lijst eruitziet
- Voeg twee gesorteerde lijsten samen tot één, doorloop hoe mergesort een lijst splitst en de delen weer samenvoegt en leg uit waarom het ongeveer n log₂ n vergelijkingen nodig heeft.
- Voeg twee gesorteerde lijsten samen tot éénCombineer twee al gesorteerde lijsten door steeds het kleinere eerste ongebruikte element te nemen, tel de vergelijkingen en leg uit waarom het resultaat gesorteerd is.
- Doorloop mergesort en leg de groei volgens n log n uitSorteer door een lijst in tweeën te splitsen tot afzonderlijke elementen overblijven en de delen op volgorde weer samen te voegen. Gebruik een basisgeval om het splitsen te stoppen en tel de vergelijkingen per niveau.
- Voeg twee gesorteerde lijsten samen tot één
- Tel de basisstappen van een algoritme als functie van de invoergrootte, vergelijk logaritmische, lineaire, n log n- en kwadratische groei en gebruik groeisnelheden om uitvoeringstijden te voorspellen.
- Tel de stappen die een algoritme uitvoertMeet een algoritme aan het aantal basisbewerkingen dat het uitvoert voor invoer met grootte n, bepaal het aantal voor lussen en geneste lussen en onderscheid het beste, slechtste en gemiddelde geval.
- Vergelijk hoe het aantal stappen groeit met de invoergrootteHerken constante, logaritmische, lineaire, n log n-, kwadratische en exponentiële groei, bekijk wat er gebeurt als de invoer verdubbelt, lees de informele O-notaties en leg uit waarom groeisnelheid bij grote invoer belangrijker is dan constante factoren.
- Voorspel en meet uitvoeringstijdenGebruik een bekende uitvoeringstijd en een groeisnelheid om de tijd voor grotere invoer te schatten, controleer een groeisnelheid door een programma bij verdubbelende groottes te timen en geef voorspellingen als schattingen.
- Tel de stappen die een algoritme uitvoert
- Laat zien dat een algoritme stopt en voor elke geldige invoer het juiste antwoord geeft, test het met randgevallen en weeg tijd, geheugen en andere factoren af om een algoritme voor een situatie te kiezen.
- Onderbouw dat een algoritme correct isGeef aan wat een algoritme moet bereiken, leg uit waarom testen alleen niet kan bewijzen dat het correct is en gebruik lusinvarianten en een terminatieargument om te laten zien dat zoek- en sorteeralgoritmen werken.
- Test algoritmen met randgevallenKies invoer op de grenzen van wat een algoritme verwerkt, voorspel de verwachte uitvoer voordat je het uitvoert en vind fouten van één te veel of te weinig en oneindige lussen die gewone invoer niet aan het licht brengt.
- Kies een algoritme dat bij de situatie pastVergelijk zoek- en sorteeralgoritmen op tijd, geheugen, stabiliteit en hun eisen aan de gegevens en bepaal welk algoritme bij een bepaalde taak past, ook wanneer eerst sorteren loont.
- Onderbouw dat een algoritme correct is
Zoek- en sorteeralgoritmen: uitleg
1Doorzoek een lijst stap voor stap
Eén waarde vinden begint met een eenvoudige vraag: welke posities moeten nog worden gecontroleerd? Volg lineair zoeken door een gewone lijst en gebruik daarna de gesorteerde volgorde om met binair zoeken grote delen van een lijst uit te sluiten. Je houdt posities en waarden apart bij, ziet hoe elke zoekmethode meldt dat de waarde ontbreekt en telt hoeveel werk gemakkelijke en moeilijke invoer kost. Korte doorlopen laten ook zien waarom de laatst overgebleven positie nog moet worden gecontroleerd.
1.1 Doorzoek een willekeurige lijst met lineair zoeken
Bij zoeken vraag je of een zoekwaarde voorkomt en waar die voorkomt. Een lijst heeft genummerde posities die indexen heten. Python telt vanaf nul: in [7, 3, 9, 3, 5] staat op index 0 de waarde 7 en op index 4 de waarde 5. De waarde en de index beantwoorden verschillende vragen.
Controleer één element tegelijk
Lineair zoeken, ook sequentieel zoeken genoemd, begint bij het eerste element en vergelijkt elk element met de zoekwaarde. Zodra de methode een overeenkomst vindt, geeft ze de index terug. Als de lijst eindigt zonder overeenkomst, geeft ze -1 terug, ons signaal voor “niet gevonden”.
def linear_search(items, target):
for i in range(len(items)):
if items[i] == target:
return i
return -1
len(items) geeft het aantal elementen. range(len(items)) levert elke geldige index, vanaf 0 tot net vóór de lengte. items[i] leest de waarde op de huidige index. Een return beëindigt de functie, dus een latere overeenkomst vervangt nooit de eerste.
Zoeken naar 3 in de lijst hierboven verloopt als volgt:
- Vergelijk op index 0 de waarde 7 met 3. Ze verschillen, dus ga verder.
- Vergelijk op index 1 de waarde 3 met 3. Ze komen overeen, dus geef index 1 terug.
Het resultaat is index 1 na twee vergelijkingen. De tweede 3, op index 3, wordt nooit gecontroleerd. Als je in plaats daarvan naar 4 zoekt, controleert de methode 7, 3, 9, 3 en 5 en geeft ze na vijf vergelijkingen -1 terug. Een teruggegeven index van 1 betekent het tweede element, niet een element met de waarde 1.
Tel het werk
Laat het aantal elementen zijn. Voor een niet-lege lijst is het beste geval één vergelijking: het eerste element komt overeen. Het slechtste geval is vergelijkingen: de zoekwaarde staat achteraan of ontbreekt. Een lege lijst heeft nul vergelijkingen nodig en geeft -1 terug.
Als een zoekwaarde één keer voorkomt en even waarschijnlijk op elke positie kan staan, is het gemiddelde aantal vergelijkingen
Voor 1.000 elementen zijn dat 500,5 vergelijkingen. Een gemiddelde kan een breuk zijn, ook al maakt elke afzonderlijke zoekopdracht een geheel aantal vergelijkingen. Dit gemiddelde beschrijft die specifieke verdeling van succesvolle zoekopdrachten; vaak voorkomende mislukte zoekopdrachten zouden het totale gemiddelde verhogen.
Meld een mislukte zoekopdracht na de lus
Een else: return -1 binnen de lus zou bij de eerste ongelijkheid opgeven. Op [7, 3, 9] zou die een zoekopdracht naar 3 afwijzen na alleen 7 te hebben gezien. Het teruggeven van een mislukt resultaat hoort na de lus, als elke positie is uitgesloten.
Lineair zoeken vereist geen gesorteerde volgorde of voorbereiding. Het werkt met getallen, woorden of records die op een identificatie worden vergeleken. Een versie voor gesorteerde gegevens kan stoppen zodra ze voorbij de mogelijke positie van de zoekwaarde komt: in [2, 5, 8, 12] is het zien van 8 genoeg om 6 uit te sluiten. De code hierboven blijft bewust zoeken tot ze een overeenkomst vindt of het einde bereikt.
Verwante taken gebruiken dezelfde doorloop maar een andere stopregel. Om elk voorkomen te tellen, elke overeenkomende index te verzamelen en een grootste element te vinden, moet je de hele lijst bekijken; bij het zoeken naar de eerste overeenkomst mag je eerder terugkeren.
Belangrijkste punten
- Lineair zoeken controleert posities op volgorde en geeft de index van de eerste overeenkomst terug.
- Geef
-1pas terug nadat elke mogelijke overeenkomst is uitgesloten. - Een niet-lege lijst vereist in het beste geval één vergelijking en in het slechtste geval .
- Het gemiddelde gaat uit van één voorkomen van de zoekwaarde, even waarschijnlijk op elke positie.
1.2 Doorzoek een gesorteerde lijst met binair zoeken
Binair zoeken gebruikt de gesorteerde volgorde om posities uit te sluiten zonder ze afzonderlijk te controleren. De invoer moet in oplopende volgorde gesorteerd zijn. Ook moet het mogelijk zijn snel een element op een gekozen index te bereiken, zoals bij een array of Pythonlijst.
Houd een interval met beide grenzen bij
low en high geven de eerste en laatste nog mogelijke positie aan, inclusief beide grenzen. Begin met low = 0 en high = len(items) - 1. Kies de middelste index door naar beneden af te ronden. Als de middelste waarde te klein is, is elke waarde links daarvan ook te klein; verplaats low voorbij het midden. Is die te groot, verplaats high dan tot net vóór het midden.
def binary_search(items, target):
low = 0
high = len(items) - 1
while low <= high:
mid = (low + high) // 2
if items[mid] == target:
return mid
elif items[mid] < target:
low = mid + 1
else:
high = mid - 1
return -1
// deelt en rondt naar beneden af. De lus omvat ook het geval low == high, omdat er dan nog één ongecontroleerde positie over is. Als low > high, is het interval leeg.
Doorloop een gevonden en een ontbrekende waarde
Gebruik [3, 8, 12, 17, 23, 31, 42, 56, 64, 77, 85], met indexen 0 tot en met 10. Om 64 te vinden is de eerste middelste index 5, met waarde 31. Omdat 31 te klein is, zet je low = 6. De volgende middelste index is 8, met waarde 64. Geef na twee controles van het middelste element 8 terug.
Zoek je in dezelfde lijst naar 20, dan krijg je:
| Controle | Ondergrens | Bovengrens | Middenpositie | Middelste waarde | Bijwerking |
|---|---|---|---|---|---|
| 1 | 0 | 10 | 5 | 31 | bovengrens wordt 4 |
| 2 | 0 | 4 | 2 | 12 | ondergrens wordt 3 |
| 3 | 3 | 4 | 3 | 17 | ondergrens wordt 4 |
| 4 | 4 | 4 | 4 | 23 | bovengrens wordt 3 |
Nu is het interval leeg, dus geef je -1 terug. Dit is een onderbouwde melding dat de waarde ontbreekt: de gesorteerde volgorde rechtvaardigde elk uitgesloten deel.
Waarom is dit snel?
Na elke controle zonder overeenkomst blijft hoogstens de helft van het interval over. Voor een niet-lege lijst is het maximale aantal controles van een middelste element . De logaritme met grondtal 2 beschrijft herhaald halveren: , dus zijn voor duizend elementen hoogstens 10 controles nodig; voor een miljoen hoogstens 20. Eén controle in deze Pythoncode kan twee vergelijkingen maken, == en <. Controles en vergelijkingen zijn verschillende teleenheden.
Voorwaarden en grensfouten
De gesorteerde volgorde is essentieel. Als je in [9, 2, 7, 4, 1] naar 2 zoekt, ziet de methode eerst 7 en sluit ze het rechterdeel uit. Daarna ziet ze 9 en sluit ze de resterende overeenkomst op index 1 uit. Snelle toegang tot het midden is ook belangrijk: als je schakels moet volgen om het midden van een gekoppelde lijst te bereiken, gaat het snelheidsvoordeel van de arrayversie verloren.
Sluit na een controle zonder overeenkomst altijd het gecontroleerde midden uit. Met low = mid kan [10, 20] bij het zoeken naar 20 oneindig onveranderd blijven. Met while low < high sla je de laatste kandidaat over en faalt het zoeken naar 5 in [5]. Bij een lege lijst is high = -1, zodat de correcte lus nooit begint.
Bij dubbele waarden geeft deze versie een willekeurige overeenkomende index terug. Zoeken naar 4 in [2, 4, 4, 4, 9] geeft direct index 2 terug; om de eerste vindplaats te vinden is een aangepaste zoekmethode nodig die na een overeenkomst links verder zoekt.
Belangrijkste punten
- Binair zoeken vereist gesorteerde gegevens en snelle toegang tot posities.
- Houd een interval inclusief beide grenzen bij en ga door zolang
low <= high. - Sluit na een controle zonder overeenkomst
miduit metmid + 1ofmid - 1. - Voor zijn hoogstens controles van een middelste element nodig.
- Een overeenkomende index hoeft niet de eerste vindplaats te zijn.
- Een leeg interval betekent dat de zoekwaarde ontbreekt.
2Sorteer een lijst met bubblesort en selectionsort
Een lijst kan op volgorde lijken te staan en toch de verkeerde elementen bevatten. Maak eerst de sorteertaak precies, inclusief herhaalde sleutels en de bijbehorende records. Volg daarna twee methoden die met verwisselingen een volgorde opbouwen: bubblesort zet het grootste resterende element rechts op zijn plaats, terwijl selectionsort het kleinste resterende element links plaatst. De doorlopen laten zien dat ze verschillende aantallen vergelijkingen en verplaatsingen kosten.
2.1 Beschrijf hoe een correct gesorteerde lijst eruitziet
Sorteren zet elementen op volgorde volgens een gekozen sleutel. Bij getallen in oplopende volgorde is elk element kleiner dan of gelijk aan het volgende. “Niet-dalend” laat ruimte voor gelijke buren: [2, 5, 5, 9] is gesorteerd. Aflopende volgorde keert de richting om.
Controleer twee voorwaarden
Een correcte sortering moet uitvoer opleveren die op volgorde staat en precies de oorspronkelijke elementen bevat, met behoud van elke herhaling. [3, 1, 2] sorteren tot [1, 2, 3] lukt. Zowel [1, 2] als [1, 1, 3] is fout, ook al staan de buren op volgorde. De eerste lijst verliest een element; de tweede verandert welke elementen voorkomen. Een herschikking die alle voorkomens behoudt, heet een permutatie.
Bij een record is de sleutel alleen het veld dat voor de vergelijking wordt gebruikt. Steden kun je sorteren op naam of inwonertal. Het hele stadsrecord beweegt mee als de sleutel met het inwonertal beweegt; als je de naam ervan losmaakt, raken de gegevens beschadigd.
Tekstvolgorde hangt af van de sleutel
Een gewone tekstvergelijking volgt tekencodes, één teken tegelijk. In ASCII en Unicode gebruiken A–Z de codes 65–90 en a–z de codes 97–122. Daardoor komt “Zebra” bij een gewone vergelijking vóór “appel”. Door kopieën in kleine letters te vergelijken kun je voor deze voorbeelden een volgorde krijgen die geen onderscheid maakt tussen hoofdletters en kleine letters.
Ook cijfers in tekst gedragen zich als tekens. “10” komt bij het sorteren vóór “9”, omdat het eerste teken “1” is. Een numerieke sleutel zet die tekenreeksen om in de getallen die ze voorstellen, zodat 9 vóór 10 komt. Bepaal wat de gegevens betekenen voordat je de vergelijking kiest.
Verplaats waarden zonder ze te verliezen
Een verwisseling wisselt twee posities om. Een tijdelijke variabele beschermt de waarde die anders zou worden overschreven:
temp = items[i]
items[i] = items[j]
items[j] = temp
Python staat ook items[i], items[j] = items[j], items[i] toe. Als je de twee toekenningen schrijft zonder de eerste waarde te bewaren, verandert [4, 7] in [7, 7]. Bubblesort en selectionsort verplaatsen elementen door te verwisselen; mergesort kopieert elementen naar samengevoegde uitvoer.
Stabiliteit en geheugen
Een stabiele sortering behoudt de oorspronkelijke volgorde van records met gelijke sleutels. Begin met Ana 85, Ben 92, Cara 85, in alfabetische volgorde. Een stabiele aflopende sortering op score levert Ben 92, Ana 85, Cara 85 op. Ana blijft vóór Cara staan. Zo kan een latere sortering op score een eerdere alfabetische volgorde binnen elke scoregroep behouden. De ingebouwde sorteerfunctie van Python is stabiel.
Een in-placesortering herschikt de bestaande lijst met slechts enkele extra variabelen, onafhankelijk van de lengte. De hier behandelde methoden bubblesort en selectionsort werken in place. De gebruikelijke mergesort heeft extra opslag nodig die evenredig is met het aantal elementen. Stabiliteit en geheugen beschrijven verschillende eigenschappen: een sortering kan in place werken en toch instabiel zijn.
Meet wanorde met inversies
Een inversie is een paar posities waarbij de sleutel van een eerder element groter is dan die van een later element. In [5, 1, 4, 2, 8] zijn de inversies (5, 1), (5, 4), (5, 2) en (4, 2): vier in totaal. De elementen van een paar hoeven geen buren te zijn.
Een gesorteerde lijst heeft nul inversies. Een omgekeerde lijst met verschillende elementen heeft er , het maximum. Gelijke sleutels vormen nooit een inversie: [3, 3, 1] heeft er twee, één voor elke 3 vóór 1. Inversies tellen is nuttig bij het uitleggen van het aantal verwisselingen bij bubblesort.
Belangrijkste punten
- Een correcte sortering behoudt elk oorspronkelijk element en zet de sleutels op volgorde.
- Een sorteersleutel bepaalt welk veld of welke waarde de volgorde bepaalt.
- Stabiliteit behoudt de volgorde van records met gelijke sleutels.
- Een in-placesortering heeft slechts een vaste hoeveelheid extra werkruimte nodig.
- Een inversie is een paar dat in de verkeerde volgorde staat, ook als de elementen geen buren zijn.
2.2 Doorloop bubblesort en tel de bewerkingen
Bubblesort vergelijkt aangrenzende elementen van links naar rechts. Als het linker element groter is, verwisselt het algoritme het paar. Elke keer door de lijst gaan is een doorgang. Een groot element kan tijdens één doorgang herhaaldelijk naar rechts bewegen, totdat het grootste resterende element zijn definitieve positie bereikt.
Volg de eerste doorgang
Begin met [5, 1, 4, 2, 8]:
- Vergelijk 5 en 1; verwissel ze voor
[1, 5, 4, 2, 8]. - Vergelijk 5 en 4; verwissel ze voor
[1, 4, 5, 2, 8]. - Vergelijk 5 en 2; verwissel ze voor
[1, 4, 2, 5, 8]. - Vergelijk 5 en 8; laat ze staan.
De doorgang maakt vier vergelijkingen en drie verwisselingen. Het grootste element, 8, staat op zijn plaats. De rest is nog ongesorteerd: 4 staat vóór 2. Eén doorgang garandeert de definitieve positie van het maximum, niet de volgorde van elk element.
Doorgang 2 heeft alleen de eerste vier posities nodig. Vergelijk 1 met 4, verwissel daarna 4 met 2 en vergelijk vervolgens 4 met 5. Dat geeft [1, 2, 4, 5, 8] na nog eens drie vergelijkingen en één verwisseling. Doorgang 3 vergelijkt 1 met 2 en 2 met 4. Er zijn geen verwisselingen, wat bevestigt dat de lijst gesorteerd is. Totaal: negen vergelijkingen en vier verwisselingen.
Verkort elke doorgang en stop vroegtijdig
def bubble_sort(items):
n = len(items)
for p in range(n - 1):
swapped = False
for j in range(n - 1 - p):
if items[j] > items[j + 1]:
items[j], items[j + 1] = items[j + 1], items[j]
swapped = True
if not swapped:
break
Doorgangsteller p begint bij nul. De grootste waarde van j is n - 2 - p, zodat j + 1 binnen het ongesorteerde deel blijft. Zet swapped aan het begin van elke doorgang terug; een verwisseling in een eerdere doorgang zegt niets over de vraag of in de huidige doorgang een element is verplaatst.
Na elke doorgang staat één positie extra aan de rechterkant definitief vast. Een doorgang zonder verwisselingen bewijst dat alle vergeleken buren op volgorde staan. Het al vaststaande einddeel staat ook op volgorde, dus kan het algoritme stoppen. De bevestigende doorgang telt nog steeds mee als werk.
Vergelijk het beste en slechtste geval
Voor een gesorteerde niet-lege lijst maakt de versie met vroegtijdige beëindiging vergelijkingen en nul verwisselingen. Op een omgekeerde lijst met verschillende elementen maakt ze
vergelijkingen en evenveel verwisselingen. Vijf elementen vereisen er 10; 1.000 elementen vereisen er 499.500. Zonder vroegtijdig stoppen zou het uitgewerkte voorbeeld met vijf elementen ook de laatste doorgang met één vergelijking uitvoeren en op 10 vergelijkingen uitkomen.
Elke verwisseling verwijdert precies één inversie. De vier inversies in de oorspronkelijke uitgewerkte lijst verklaren de vier verwisselingen. Gelijke buren blijven staan omdat de test > gebruikt. Daardoor is deze versie stabiel en werkt ze in place. Als je > vervangt door >=, kan de volgorde van records met gelijke sleutels omkeren.
De positie is ook van belang als er weinig inversies zijn. [5, 1, 2, 3, 4] gebruikt vier verwisselingen en een tweede doorgang om de volgorde te bevestigen, voor zeven vergelijkingen. [2, 3, 4, 5, 1] heeft ook vier verwisselingen nodig, maar de 1 kan per doorgang maar één keer naar links bewegen. Er zijn alle vier de doorgangen en 10 vergelijkingen nodig.
Belangrijkste punten
- Elke doorgang zet het grootste resterende element rechts op zijn plaats.
- Na een doorgang zonder verwisselingen kun je vroegtijdig stoppen.
- Tel de doorgang die de volgorde bevestigt mee, ook als die geen verwisselingen maakt.
- In het slechtste geval zijn er vergelijkingen; gesorteerde invoer vereist er .
- Door alleen buren te verwisselen die strikt in de verkeerde volgorde staan, blijft de stabiliteit behouden.
- Het aantal verwisselingen is gelijk aan het aantal inversies in de invoer.
2.3 Doorloop selectionsort en tel de bewerkingen
Selectionsort bouwt links een gesorteerd begindeel op. Elke doorgang vindt het kleinste element in het resterende einddeel en verwisselt dat met het element op de volgende positie van het begindeel. De doorloop vindt de positie; de verwisseling gebeurt na de doorloop.
Onthoud een index
Begin op positie i met smallest = i. Vergelijk elk later element met items[smallest]. Werk smallest alleen bij als er een kleiner element verschijnt. Wissel na afloop van de doorloop items[i] en items[smallest] om.
def selection_sort(items):
n = len(items)
for i in range(n - 1):
smallest = i
for j in range(i + 1, n):
if items[j] < items[smallest]:
smallest = j
if smallest != i:
items[i], items[smallest] = items[smallest], items[i]
Als je alleen de kleinste waarde onthoudt, heb je de positie niet voor de verwisseling. Als je de doorloop bij index 0 begint, bekijk je de al geplaatste elementen opnieuw; de verdere zoektocht begint direct na i.
Doorloop de doorgangen
Begin met [29, 10, 14, 37, 13].
| Doorgang | Resterend minimum | Lijst na plaatsing | Vergelijkingen | Verwisselingen die elementen verplaatsen |
|---|---|---|---|---|
| 1 | 10 | [10, 29, 14, 37, 13] | 4 | 1 |
| 2 | 13 | [10, 13, 14, 37, 29] | 3 | 1 |
| 3 | 14 | [10, 13, 14, 37, 29] | 2 | 0 |
| 4 | 29 | [10, 13, 14, 29, 37] | 1 | 1 |
Het derde minimum staat al op zijn plaats, dus bewegen er geen waarden. Na vier doorgangen moet het laatste element het grootste zijn; het heeft geen afzonderlijke doorgang nodig. Er zijn 10 vergelijkingen en drie verwisselingen die elementen verplaatsen. De voorwaarde in de code slaat verwisselingen van een positie met zichzelf over; als je die voorwaarde weglaat, blijft het resultaat hetzelfde.
Vergelijkingen en verwisselingen hebben verschillende kosten
Selectionsort maakt altijd vergelijkingen tussen elementen: elke doorgang moet het hele resterende einddeel bekijken om het minimum te vinden. Het totaal is 10 voor vijf elementen of 499.500 voor 1.000, ook bij al gesorteerde invoer. Een doorloop die de onthouden index niet verandert, stelt het minimum van die doorgang vast, maar garandeert in het algemeen niet dat het resterende einddeel op volgorde staat.
Voor een niet-lege lijst is er hoogstens één verwisseling die elementen verplaatst per doorgang, dus hoogstens in totaal. Lege invoer vereist geen doorgangen of verwisselingen. Bubblesort kan verwisselingen nodig hebben op een omgekeerde lijst met verschillende elementen. Als het verplaatsen van grote records veel meer kost dan het vergelijken van hun sleutels, kan het kleine aantal verwisselingen van selectionsort ondanks de vele vergelijkingen van belang zijn. Als je tijdens de doorloop bij elk nieuw minimum verwisselt, gaat dat voordeel verloren.
Gelijke sleutels kunnen van volgorde veranderen
Deze methode met verwisselingen werkt in place, maar is instabiel. Geef records met gelijke sleutels de labels 4a en 4b zodat hun identiteit zichtbaar is. Begin je met [4a, 4b, 1], dan verwisselt de eerste doorgang 4a en 1, wat [1, 4b, 4a] oplevert. De gelijke sleutels hebben hun oorspronkelijke volgorde omgekeerd, hoewel het algoritme ze nooit rechtstreeks als ongelijk heeft vergeleken. Het eerste minimum dat tijdens een doorloop wordt gevonden behouden, voorkomt niet dat een verwisseling over een grotere afstand een record met gelijke sleutel passeert.
Belangrijkste punten
- Selectionsort zoekt een minimum en verwisselt daarna één keer na de doorloop.
- Na elke doorgang krijgt het gesorteerde begindeel er één element bij.
- Het aantal vergelijkingen is altijd .
- Voor niet-lege invoer gebruikt het algoritme hoogstens verwisselingen die elementen verplaatsen en een vaste hoeveelheid extra opslag.
- De gebruikelijke versie met verwisselingen over grotere afstand is instabiel.
3Sorteer sneller met mergesort
Een grote lijst sorteren door die herhaaldelijk volledig te doorzoeken wordt kostbaar. Mergesort gebruikt een ander plan: verdeel de lijst in kleinere delen, sorteer die delen en combineer de resultaten. Leer eerst waarom je twee gesorteerde lijsten kunt samenvoegen door alleen naar hun eerste ongebruikte elementen te kijken. Volg daarna de recursieve splitsingen en samenvoegingen en houd het werk per niveau en het extra geheugen voor de uitvoer bij.
3.1 Voeg twee gesorteerde lijsten samen tot één
Samenvoegen combineert twee al gesorteerde lijsten tot één gesorteerde uitvoer. Houd bij elke invoerlijst een positiemarkering bij het eerste ongebruikte element. Vergelijk die twee elementen, kopieer het kleinste en schuif alleen de bijbehorende markering op.
Kies het volgende kleinste element
Voeg [3, 27, 38, 43] samen met [9, 10, 82]:
| Vergelijking van eerste ongebruikte elementen | Kopieer naar uitvoer | Uitvoer tot nu toe |
|---|---|---|
| 3 en 9 | 3 | [3] |
| 27 en 9 | 9 | [3, 9] |
| 27 en 10 | 10 | [3, 9, 10] |
| 27 en 82 | 27 | [3, 9, 10, 27] |
| 38 en 82 | 38 | [3, 9, 10, 27, 38] |
| 43 en 82 | 43 | [3, 9, 10, 27, 38, 43] |
De linker lijst is nu leeg. Kopieer de resterende 82 zonder nog een vergelijking tussen elementen. Het resultaat is [3, 9, 10, 27, 38, 43, 82], met zes vergelijkingen. Het resterende lijstdeel kopiëren hoort bij het algoritme: als je stopt wanneer de vergelijkingen stoppen, gaan gegevens verloren.
Waarom kan de methode elementen achter de eerste ongebruikte elementen negeren? Elk eerste ongebruikte element is het kleinste resterende element van de eigen lijst. Het kleinste van die twee is daarom het kleinste resterende element in totaal. Deze redenering blijft gelden nadat een markering opschuift, omdat de ongebruikte delen gesorteerd blijven.
Lees de code voor samenvoegen
def merge(left, right):
result = []
i = j = 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
result.extend(left[i:])
result.extend(right[j:])
return result
append voegt één element toe. Een deel zoals left[i:] bevat het ongebruikte resterende lijstdeel en extend kopieert de elementen daarvan. Als de lus eindigt, kan hoogstens één ongebruikt resterend lijstdeel niet leeg zijn. Als een invoerlijst leeg begint, maakt de lus nul vergelijkingen en wordt de andere lijst intact gekopieerd.
Tel vergelijkingen en opslag
Voor twee niet-lege lijsten met lengtes en zijn hoogstens vergelijkingen van eerste ongebruikte elementen nodig. Elke vergelijking plaatst één element en minstens het laatste element kan zonder vergelijking worden gekopieerd. Het kleinst mogelijke aantal vergelijkingen bij het samenvoegen is de lengte van de kortste lijst: [1, 2, 3] samenvoegen met [4, 5, 6] kost drie vergelijkingen voordat de linkerkant leeg is.
Het totale kopieerwerk groeit met , ook als de vergelijkingen vroeg eindigen, omdat elk element in de uitvoer moet voorkomen. De nieuwe lijst heeft ook ruimte nodig voor elementen. Het aantal vergelijkingen, het kopieerwerk en de extra opslag meten verschillende delen van dezelfde bewerking.
Ga om met gelijke sleutels en invoervolgorde
De test <= neemt bij gelijke sleutels het element van links. Als de twee invoerlijsten uit opeenvolgende delen van een oorspronkelijke lijst komen, blijft zo het eerdere record vóór het latere record met gelijke sleutel staan. Dit is de regel voor gelijke sleutels die nodig is voor stabiele mergesort.
De eis dat de invoer gesorteerd is, staat vast. Als je [5, 1] samenvoegt met [3], kopieert de methode 3 en daarna het resterende lijstdeel [5, 1], wat [3, 5, 1] oplevert. De regel voor het eerste ongebruikte element faalde omdat 5 niet de kleinste resterende waarde in de eigen invoerlijst was.
Belangrijkste punten
- Samenvoegen vergelijkt de eerste ongebruikte elementen van twee gesorteerde invoerlijsten.
- Kopieer het ongebruikte resterende lijstdeel als één kant leeg is.
- Twee niet-lege invoerlijsten vereisen hoogstens vergelijkingen van eerste ongebruikte elementen.
- Bij gelijke sleutels eerst van links nemen behoudt de volgorde tussen de twee helften.
3.2 Doorloop mergesort en leg de groei volgens n log n uit
Mergesort lost een grote sorteertaak op door die in kleinere sorteertaken te splitsen. Dit is verdeel en heers: verdeel de lijst, sorteer elke helft en voeg de gesorteerde helften samen.
Stop met splitsen bij het basisgeval
Een functie is recursief als ze zichzelf aanroept. Mergesort roept zichzelf aan op kortere lijsten. Het basisgeval geeft een lijst met nul of één element ongewijzigd terug, omdat zo’n lijst al gesorteerd is.
def merge_sort(items):
if len(items) <= 1:
return items
mid = len(items) // 2
left = merge_sort(items[:mid])
right = merge_sort(items[mid:])
return merge(left, right)
De delen verdelen de invoer zonder elementen te verliezen. Bij een oneven lengte heeft de rechterkant één element meer: [6, 2, 9, 4, 1, 7, 3] splitst in [6, 2, 9] en [4, 1, 7, 3]. Beide helften zijn korter, dus bereiken recursieve aanroepen uiteindelijk het basisgeval. Een basisgeval alleen zou terminatie niet garanderen als een aanroep de oorspronkelijke lijst steeds aan zichzelf bleef doorgeven.
Bouw de gesorteerde lijst weer op
Doorloop [38, 27, 43, 3, 9, 82, 10, 15]. De lijst splitst in twee helften van vier elementen, daarna vier delen van twee elementen en daarna afzonderlijke elementen. Splitsen herschikt de waarden niet. De volgorde wordt tijdens het samenvoegen opgebouwd:
- Voeg afzonderlijke elementen samen tot
[27, 38],[3, 43],[9, 82]en[10, 15]. Elk paar kost één vergelijking: vier in totaal. - Voeg paren samen tot
[3, 27, 38, 43]en[9, 10, 15, 82]. Elk kost drie vergelijkingen: zes in totaal. - Voeg die helften samen tot
[3, 9, 10, 15, 27, 38, 43, 82]. Dit kost zeven vergelijkingen.
De volledige sortering kost vergelijkingen tussen elementen. Tel niet alleen de laatste samenvoeging: de gesorteerde helften moesten eerst worden gemaakt. Het voorbeeld met zeven elementen hierboven wordt met deze splitsingsregel in 14 vergelijkingen gesorteerd tot [1, 2, 3, 4, 6, 7, 9].
Tel niveaus en werk per niveau
Voor acht elementen bereik je door halveren na drie niveaus afzonderlijke elementen, omdat . In het algemeen zijn er ongeveer samenvoegingsniveaus. Over een volledig niveau verwerken de samenvoegingen gezamenlijk alle elementen. Elk niveau doet dus werk dat evenredig is met , wat leidt tot groei als .
Voor acht elementen is een nuttige ruime bovengrens voor vergelijkingen, niet het exacte aantal. De uitgewerkte lijst gebruikte er 17; een al gesorteerde of omgekeerde lijst met acht elementen gebruikt er 12. De invoervolgorde verandert wanneer bij een samenvoeging één kant opraakt, maar elke lijst doorloopt nog steeds de niveaus van splitsen en samenvoegen. De groei van het aantal vergelijkingen blijft bij deze versie in zowel het beste als het slechtste geval .
Voor een miljoen elementen geven ongeveer 20 niveaus ongeveer 20 miljoen vergelijkingen als schatting van de bovengrens. Selectionsort gebruikt er ongeveer 500 miljard. Het verschil groeit snel met de invoergrootte.
Houd rekening met de extra uitvoerruimte
De gewone mergesort met lijsten heeft extra opslag nodig die evenredig is met . Door bij gelijke sleutels het eerste ongebruikte element van links te kiezen, is de sortering stabiel.
Belangrijkste punten
- Mergesort sorteert recursief twee kortere helften en voegt die daarna samen.
- Lijsten met nul of één element vormen het basisgeval.
- Oneven lengtes splitsen in helften die één element verschillen.
- Elk van de ongeveer niveaus doet werk dat evenredig is met .
- Exacte aantallen vergelijkingen hangen af van de volgorde; de groeifamilie is .
- De gebruikelijke versie is stabiel als bij gelijke sleutels eerst links wordt genomen en heeft evenredig veel extra opslag nodig.
4Tel stappen en vergelijk hoe uitvoeringstijden groeien
Een stopwatch vertelt hoe één programma één keer draaide; een aantal stappen helpt verklaren wat er gebeurt als de invoer groeit. Kies een bewerking om te tellen, zet herhaald werk om in een formule en vergelijk groeipatronen van één opzoeking tot het proberen van elke selectie. Gebruik die patronen om uitvoeringstijden en tijdsbudgetten te schatten en ontwerp daarna metingen die kunnen controleren of de voorspellingen bij echte uitvoeringen passen.
4.1 Tel de stappen die een algoritme uitvoert
Een gemeten uitvoeringstijd hangt af van de machine en het programma. Een aantal stappen beschrijft het werk van het algoritme met behulp van een gekozen herhaalde bewerking. De invoergrootte, geschreven als , is het aantal elementen dat wordt verwerkt.
Kies de bewerking voordat je telt
Bij zoeken en sorteren zijn vergelijkingen tussen elementwaarden meestal een bruikbare basisbewerking. Tel verwisselingen apart als het verplaatsen van gegevens van belang is. Bij binair zoeken is het handig om controles van een middelste element te tellen. In de Pythonversie toetst een controle zonder overeenkomst zowel op gelijkheid als op kleiner zijn en kan die dus twee vergelijkingen tussen elementen omvatten.
| Methode | Teleenheid | Aantal in het slechtste geval |
|---|---|---|
| Lineair zoeken | Vergelijkingen van element met zoekwaarde | |
| Binair zoeken, niet-lege invoer | Controles van middelste element | |
| Bubblesort | Vergelijkingen van buren | |
| Selectionsort | Vergelijkingen van sleutels | |
| Mergesort | Vergelijkingen van eerste ongebruikte elementen | Hoogstens ongeveer |
Deze aantallen beschrijven herhaalde bewerkingen, geen regels code. Eén regel binnen een lus kan een miljoen keer worden uitgevoerd; verschillende regels voor de voorbereiding worden misschien elk één keer uitgevoerd.
Onderscheid gevallen bij dezelfde grootte
Het beste geval kost de minste stappen van alle geldige invoer met grootte . Het slechtste geval kost de meeste en biedt een garantie. Het gemiddelde geval neemt het gemiddelde over een bepaalde verdeling van invoer.
Voor een niet-lege lijst heeft lineair zoeken één vergelijking nodig als de zoekwaarde vooraan staat en als die achteraan staat of ontbreekt. Het gemiddelde voor een succesvolle zoekopdracht is als de eerste positie met een overeenkomst even waarschijnlijk elke positie kan zijn. Het woord “gemiddelde” vereist die verdeling; het betekent niet voor elk algoritme het midden tussen het beste en slechtste aantal.
Zet lussen om in aantallen
Eén vergelijking per element bij een volledige doorloop geeft vergelijkingen. Twee volledig geneste lussen die elk keer worden uitgevoerd, voeren hun gemeenschappelijke inhoud keer uit. Een ander patroon met geneste lussen vergelijkt elk paar slechts één keer:
for i in range(n):
for j in range(i + 1, n):
compare(items[i], items[j])
De eerste herhaling van de buitenste lus vergelijkt het element met latere elementen. De volgende vergelijkt met en de laatste vergelijkt met geen enkel element. Het totaal is
Schrijf de som vooruit en achteruit. Elk paar boven elkaar telt op tot en er zijn van die paren. Hun totaal is , tweemaal de oorspronkelijke som. Voor vijf elementen is ; voor 1.000 is het aantal paren 499.500.
Herken herhaald halveren
Een lus die het resterende werk halveert, kost ongeveer herhalingen. Eén miljoen komt na 20 halveringen voor het eerst op 1 of lager uit: en liggen aan weerszijden van een miljoen. Dit verschilt sterk van telkens maar één element verwijderen.
Houd bij groeivergelijkingen de snelst groeiende term over. Het aantal paren is . Bij zijn de termen 500.000 en 500, dus bepaalt de kwadratische term de groei. Door de kleinere term en de constante factor weg te laten beschrijf je de groeifamilie; het exacte aantal van 499.500 wordt daardoor geen exact aantal van één miljoen.
Belangrijkste punten
- Benoem de bewerking die je telt en druk het aantal uit met de invoergrootte.
- Aantallen in het slechtste geval zijn garanties; gemiddelden hangen af van een invoerverdeling.
- Volledig geneste doorlopen geven uitvoeringen van de lusinhoud.
- Elk paar verschillende elementen één keer vergelijken geeft vergelijkingen.
- Herhaald halveren levert logaritmische groei op.
4.2 Vergelijk hoe het aantal stappen groeit met de invoergrootte
Een groeisnelheid beschrijft hoe de hoeveelheid werk verandert als de invoer groter wordt. Ze helpt algoritmen te vergelijken buiten de specifieke grootte die in één doorloop is gebruikt.
Lees de gebruikelijke families
| Groeifamilie | Voorbeeld | Effect van verdubbeling van de invoergrootte |
|---|---|---|
| Constant, | Een bekende arraypositie lezen | Evenveel werk |
| Logaritmisch, | Binair zoeken | Ongeveer één extra controle |
| Lineair, | Volledige doorloop | Tweemaal zoveel werk |
| Mergesort | Iets meer dan tweemaal zoveel | |
| Kwadratisch, | Selectionsort | Ongeveer viermaal zoveel |
| Exponentieel, | Elke selectie van elementen proberen | Het aantal wordt gekwadrateerd |
Bij exponentiële groei verdubbelt het aantal al als er maar één element bijkomt: . De invoer verdubbelen is een veel grotere verandering dan er één element aan toevoegen.
Vergelijk groottes met getallen
Voor invoer van 10, 100, 1.000 en één miljoen elementen is ongeveer 3,3; 6,6; 10 en 20. De bijbehorende waarden van zijn ongeveer 33, 664, 9.966 en 20 miljoen. De kwadratische waarden zijn 100, 10.000, één miljoen en één biljoen.
Logaritmische groei is niet “de helft van de lijst”. Voor een miljoen elementen kost herhaald halveren slechts ongeveer 20 stappen. Als de invoer stijgt van 1.000 naar 2.000, stijgt van ongeveer 9.966 naar 21.932, een factor van ongeveer 2,2. De logaritme verandert ook, dus groeit het aantal iets sneller dan lineair.
Exponentieel werk wordt snel groot. en is ongeveer een miljoen. Bij een miljard stappen per seconde kosten stappen nog steeds ongeveer 13 dagen. Eén extra element verdubbelt die tijd.
Gebruik informele O-notaties
Programmeurs duiden deze families doorgaans aan met , , , , en . Hier geven ze de gebruikelijke groeifamilie voor het slechtste geval aan. Spreek uit als “orde n kwadraat”. De notatie laat constante factoren en termen van lagere orde weg: vergelijkingen behoort tot de kwadratische familie.
Een O-notatie is geen exacte uitvoeringstijd of aantal seconden. Ze beweert ook niet dat elke invoer het aantal van het slechtste geval gebruikt. Bubblesort met vroegtijdige beëindiging heeft een lineair beste geval, maar een kwadratisch slechtste geval.
Vind het omslagpunt
Stel dat methode A stappen kost en methode B . Bij 50 elementen kost A 5.000 stappen en B 2.500. Bij 100 kosten beide 10.000. Bij 1.000 kost A 100.000 en B één miljoen. De langzamere groei van A overwint uiteindelijk de grotere constante factor.
De snelheid van hardware verandert de schaal zonder de familie te veranderen. Een computer die 100 keer zo snel is, geeft een kwadratische methode ruimte voor slechts 10 keer zoveel elementen in dezelfde tijd, want . Een lineaire methode zou er 100 keer zoveel kunnen verwerken. Bij een kleine taak kunnen voorbereiding en constanten overheersen; bij grote invoer wordt de groei doorslaggevend.
Belangrijkste punten
- Verdubbeling van de invoer verdubbelt lineair werk ongeveer en verviervoudigt kwadratisch werk.
- Logaritmisch werk neemt bij verdubbeling van de invoer met ongeveer één stap toe.
- Mergesort combineert lineair werk per niveau met een logaritmisch aantal niveaus.
- Eén element toevoegen verdubbelt een aantal stappen volgens .
- Groeinotaties laten constanten weg; werkelijke aantallen bepalen de omslagpunten bij kleine invoer.
4.3 Voorspel en meet uitvoeringstijden
Met een bekende uitvoeringstijd en een groeipatroon kun je voorspellen hoe een grotere taak zich gedraagt. De voorspelling is een schatting, omdat de werkelijke tijd ook afhangt van de implementatie, het geheugen, de hardware en ander werk op de machine.
Schaal eerst de invoer en dan de tijd
Bij lineair werk vermenigvuldig je de tijd met de verhouding tussen de invoergroottes. Als een zoekopdracht in het slechtste geval bij één miljoen elementen 3 milliseconden kost, kosten tien miljoen elementen onder vergelijkbare omstandigheden ongeveer 30 milliseconden.
Bij kwadratisch werk kwadrateer je de verhouding. Stel dat selectionsort 2 seconden kost voor 50.000 elementen. Verdubbeling naar 100.000 elementen geeft
seconden. Bij een toename naar 500.000 elementen wordt de invoergrootte met 10 vermenigvuldigd, dus is de geschatte tijd seconden. De tijd met 10 vermenigvuldigen zou het algoritme ten onrechte als lineair behandelen.
Bij groei volgens gebruik je de verhouding tussen beide volledige uitdrukkingen. Verdubbeling van grote invoer kost iets meer dan tweemaal zoveel, omdat de logaritme met het aantal elementen meegroeit.
Reken terug vanuit een tijdsbudget
Gebruik dezelfde kwadratische referentiemeting: 2 seconden voor 50.000 elementen. Een budget van 32 seconden staat 16 keer zoveel tijd toe. De invoer kan groeien met de wortel van 16, dat is 4, tot ongeveer 200.000 elementen. Controleer de richting door in te vullen: viermaal zoveel invoer voorspelt 16 keer zoveel tijd, van 2 seconden naar 32 seconden.
Vergelijk algoritmen bij een grote invoer
Voor één miljoen elementen maakt selectionsort 499.999.500.000 vergelijkingen, ongeveer 500 miljard. Mergesort heeft er hoogstens ongeveer 20 miljoen nodig. Bij een hypothetisch miljard vergelijkingen per seconde komen die aantallen overeen met ongeveer 500 seconden tegenover 0,02 seconden, een verschil van grofweg een factor 25.000. Deze berekening gaat uit van gelijke kosten per vergelijking om het effect van het algoritme afzonderlijk te bekijken; gemeten programma’s besteden ook tijd aan verplaatsingen en geheugentoegang.
Test een voorspelling van de groei
Meet de uitvoeringstijd van hetzelfde programma bij verschillende groottes die steeds verdubbelen, zoals 10.000, 20.000 en 40.000 elementen. Deel elke tijd door de vorige tijd. Verhoudingen rond 2 wijzen op lineaire groei; iets boven 2 wijst op ; rond 4 wijst op kwadratische groei.
Houd de machine en meetmethode gelijk. Herhaal de metingen en gebruik groottes waarbij de opstarttijd niet overheerst. Vergelijk gelijke gevallen: bij de ene grootte op de eerste positie zoeken en bij een andere tevergeefs zoeken zou invoereffecten met groei vermengen. Voor bubblesort hebben gesorteerde en omgekeerde lijsten verschillende gevalsaanduidingen nodig.
Als verdubbelende groottes 0,04, 0,16 en 0,64 seconden opleveren, zijn beide verhoudingen 4. Dat ondersteunt een kwadratisch model over dat bereik. Eén verhouding met veel meetruis is zwakker bewijs dan een herhaald patroon. Aantallen stappen voor een bepaalde doorloop kunnen exact zijn; bij een voorspelling in seconden hoort “ongeveer” en moet je die toetsen aan metingen.
Belangrijkste punten
- Lineaire tijd schaalt met de invoerverhouding; kwadratische tijd met het kwadraat daarvan.
- Gebruik bij een kwadratisch tijdsbudget een vierkantswortel om de invoerverhouding te bepalen.
- Meet verschillende groottes met vergelijkbare invoergevallen en herhaalde uitvoeringen.
- Verhoudingen tussen gemeten tijden wijzen op groeipatronen; voorspelde seconden blijven schattingen.
5Onderbouw de correctheid en kies het juiste algoritme
Een snelle doorloop op één lijst laat twee vragen open: werkt het algoritme altijd en past het bij deze taak? Geef aan wat geldige invoer en correcte uitvoer betekenen, gebruik een lusinvariant om uit te leggen waarom de methode voortgang bewaart en laat zien waarom ze stopt. Kies daarna tests die grensfouten aan het licht brengen en vergelijk algoritmen aan de hand van wat de taak werkelijk vereist aan tijd, geheugen, stabiliteit en toegang tot de gegevens.
5.1 Onderbouw dat een algoritme correct is
Een correct algoritme stopt bij elke geldige invoer en produceert de vereiste uitvoer. Een specificatie vermeldt de invoervoorwaarde en het beloofde resultaat. Bij binair zoeken is de preconditie een oplopende gesorteerde volgorde. De postconditie is een overeenkomende index, of -1 precies als de zoekwaarde ontbreekt.
Gebruik een invariant om stappen te verbinden
Een lusinvariant is een uitspraak die geldt voordat de lus begint en door elke herhaling behouden blijft. Een correctheidsargument controleert of de invariant aan het begin geldt, behouden blijft en wat die bij het einde van de lus impliceert. Een afzonderlijk terminatieargument laat zien dat de lus uiteindelijk eindigt.
Gebruik voor selectionsort deze invariant: vóór doorgang i bevatten de eerste i posities de i kleinste elementen op volgorde.
- Begin: vóór doorgang 0 is het begindeel leeg. Het voldoet al aan de uitspraak.
- Behoud: de doorgang vindt het kleinste resterende element. Door dat daarna te plaatsen, wordt het gesorteerde begindeel één element langer en is het element minstens even groot als elk eerder geplaatst element.
- Einde: na hoogstens doorgangen blijft alleen het grootste element buiten het begindeel over. De hele lijst is gesorteerd.
Elke verplaatsing is een verwisseling, dus blijft ook de multiverzameling van elementen ongewijzigd. Uitvoer die alleen op volgorde staat, zou niet aan de volledige sorteerspecificatie voldoen.
Bubblesort gebruikt een invariant voor het einddeel: na doorgangen bevatten de laatste posities de grootste elementen op volgorde. De volgende doorgang brengt het grootste ongesorteerde element naar dat einddeel. Een doorgang zonder verwisselingen stelt vast dat het hele resterende deel op volgorde staat, waardoor vroegtijdige beëindiging mogelijk is.
Leg de uitgesloten intervallen bij binair zoeken uit
Gebruik de invariant: als de zoekwaarde voorkomt, ligt minstens één voorkomen binnen het interval van low tot en met high. Aanvankelijk omvat dat interval de hele lijst. Als de middelste waarde te klein is, maakt de gesorteerde volgorde elke waarde op of links van mid ook te klein. Door low bij te werken naar mid + 1 blijven alle mogelijke overeenkomsten behouden. De bijwerking naar high = mid - 1 volgt dezelfde redenering voor te grote waarden.
Bij een overeenkomst voldoet de teruggegeven positie direct aan de postconditie. Als het interval leeg raakt, sluit de invariant uit dat de zoekwaarde ergens in de lijst staat. De invoer blijft gesorteerd omdat de zoekmethode die nooit verandert.
Laat zien waarom de uitvoering stopt
Een afnemende niet-negatieve gehele maat bewijst voortgang naar een einde. Bij binair zoeken neemt het aantal mogelijke posities na elke controle zonder overeenkomst strikt af. De gecontroleerde middenpositie wordt uitgesloten, dus kan de lus niet oneindig hetzelfde interval behouden. Bubblesort en selectionsort maken hoogstens doorgangen bij niet-lege invoer en geen doorgangen bij lege invoer.
Mergesort bereikt lijsten met nul of één element omdat elke recursieve aanroep een kortere lijst gebruikt. Die basisgevallen zijn gesorteerd. Als de kortere aanroepen correct gesorteerde helften teruggeven, neemt de samenvoeging steeds het kleinste resterende element en behoudt ze alle elementen. Zo werkt de correctheid terug tot aan de oorspronkelijke aanroep.
Gebruik tests voor een andere taak
Een test vergelijkt één werkelijk resultaat met één verwacht resultaat. Veel geslaagde gekozen tests geven vertrouwen, terwijl één falende geldige invoer een tegenvoorbeeld is dat correctheid weerlegt. Een algemeen argument met een invariant dekt de onbegrensde familie van mogelijke invoeren die een eindige verzameling voorbeeldtests niet controleert. Testen is vooral nuttig om te controleren of de werkelijke code de methode uit het argument implementeert.
Belangrijkste punten
- Correctheid vereist het gespecificeerde resultaat en terminatie bij elke geldige invoer.
- Een invariant moet aanvankelijk gelden, na elke iteratie waar blijven en het resultaat bij het verlaten van de lus onderbouwen.
- Een argument voor een sortering moet zowel de elementen behouden als de volgorde vaststellen.
- Een strikt afnemende niet-negatieve maat toont terminatie aan.
- Eén falende geldige invoer weerlegt correctheid.
5.2 Test algoritmen met randgevallen
Een randgeval is geldige invoer dicht bij een grens waar je gemakkelijk fouten maakt in aannames en lusgrenzen. Bepaal het verwachte resultaat vanuit de specificatie voordat je de code uitvoert. Anders kan de foutieve uitvoer van een programma ongemerkt je verwachte antwoord worden.
Kies lijsten die grenzen beproeven
Test lege lijsten, lijsten met één en met twee elementen, al gesorteerde en omgekeerde lijsten, herhaalde en uitsluitend gelijke waarden, negatieve getallen en oneven en even lengtes. Neem bij zoekopdrachten de eerste positie, de laatste positie en zoekwaarden op die onder, boven en tussen opgeslagen waarden ontbreken.
Binair zoeken in een lege lijst moet -1 teruggeven zonder een element te benaderen: low = 0 en high = -1 maken het begininterval leeg. Het sorteren van [3, 3, 3] moet drie exemplaren van 3 teruggeven. Een uitvoer van [3] zou op volgorde staan, maar niet alle elementen behouden.
Doorloop de kleinste falende invoer
Binair zoeken met while low < high gaat bij [5] met zoekwaarde 5 de lus niet in. De oplossing is low <= high, omdat een interval met één positie nog een kandidaat bevat. Deze test met één element isoleert de grens duidelijker dan een lange lijst.
Met low = mid zet een zoekopdracht naar 20 in [10, 20] de middenpositie op 0, ziet 10 en laat low op 0 staan. Het interval is bij de volgende herhaling onveranderd. Gebruik low = mid + 1 om een al gecontroleerde positie uit te sluiten. Een lijst met twee elementen en de zoekwaarde achteraan legt deze oneindige lus bloot.
Bubblesort vergelijkt items[j] met items[j + 1]. Bij de eerste doorgang is de laatste geldige linker index n - 2. Doorgaan tot n - 1 leest voorbij de lijst en veroorzaakt de Pythonfout IndexError. Zo’n grensfout van één positie heet een fout van één te veel of te weinig.
Controleer beide beloften over de uitvoer
Controleer bij een sortering de volgorde van aangrenzende elementen en het aantal van elk oorspronkelijk element. Gebruik gelabelde records om stabiliteit te testen. Bij Ana 85, Ben 92, Cara 85 moet Ana vóór Cara blijven staan als een stabiele sortering op score de gelijke scores groepeert. Een controle van alleen de scores zou een verwisseling van die twee records missen.
Genereer ook willekeurige lijsten. Vergelijk hun resultaten met een betrouwbare implementatie zoals sorted van Python. Neem dubbele waarden en verschillende lengtes op in de gegenereerde invoer. Als een test faalt, verklein je de invoer terwijl de fout blijft optreden en doorloop je die daarna met de hand. Bewaar het kleine voorbeeld als regressietest, zodat de herstelde fout detecteerbaar blijft.
Houd de berekening van het midden veilig
Gehele getallen in Python groeien waar nodig, dus loopt (low + high) // 2 niet over. Sommige talen gebruiken gehele getallen met een vaste bitbreedte. Voor zeer grote niet-negatieve indexen kan hun som het bereik dat kan worden opgeslagen overschrijden. Gehele optelling in Java loopt cyclisch over; overloop van gehele getallen met teken in C heeft ongedefinieerd gedrag.
Bereken bij geldige indexen en low <= high in plaats daarvan low + (high - low) // 2. Het verschil is niet-negatief en het resultaat blijft tussen de grenzen. Dit berekent dezelfde naar beneden afgeronde middenpositie zonder de mogelijk overlopende som te vormen. Hier vullen grenswaardetesten en redeneren over de getalrepresentatie van de taal elkaar aan.
Belangrijkste punten
- Schrijf verwachte resultaten op voordat je tests uitvoert.
- Kleine lijsten leggen ontbrekende laatste controles, onveranderde intervallen en ongeldige toegang tot buren bloot.
- Controleer behoud van elementen, volgorde en, wanneer vereist, stabiliteit.
- Verklein falende willekeurige invoer en bewaar die als regressietest.
- De middenpositie op basis van het verschil voorkomt overloop bij geldige niet-negatieve indexen met vaste bitbreedte.
5.3 Kies een algoritme dat bij de situatie past
Een algoritme past bij een taak als de eisen en kosten aansluiten bij de gegevens en het werk dat wordt gedaan. Denk aan de invoervolgorde, toegang tot posities, het aantal toekomstige bewerkingen, extra geheugen, stabiliteit en de kosten van het verplaatsen van records.
Vergelijk de methoden
| Methode | Patroon van tijd of stappen | Extra opslag | Stabiel? |
|---|---|---|---|
| Lineair zoeken | Maximaal vergelijkingen | Vast | Geen eigenschap van een sortering |
| Binair zoeken | Maximaal controles van het midden | Vast | Geen eigenschap van een sortering |
| Bubblesort met vroegtijdige beëindiging | vergelijkingen indien gesorteerd; kwadratisch slechtste geval | Vast | Ja, bij strikt grotere sleutels verwisselen |
| Selectionsort | vergelijkingen; hoogstens verwisselingen die elementen verplaatsen | Vast | Nee, in de gebruikelijke vorm met verwisselingen |
| Mergesort | Groei van vergelijkingen volgens | Evenredig met | Ja, bij gelijke sleutels eerst links |
Binair zoeken vereist ook een gesorteerde volgorde en snelle toegang tot het midden. Een goede vergelijking bevat die voorwaarden; alleen een klein aantal zoekcontroles laat de kosten weg van het voorbereiden van ongeschikte gegevens.
Bepaal of eerst sorteren loont
Voor één zoekopdracht in een miljoen ongesorteerde elementen kost lineair zoeken hoogstens een miljoen vergelijkingen. Eerst met mergesort sorteren kost ongeveer 20 miljoen vergelijkingen vóór de eerste binaire zoekopdracht, die daarna hoogstens 20 controles van het midden vereist. De voorbereiding overtreft de besparing op die ene zoekopdracht ruimschoots.
Voor 100 zoekopdrachten in een onveranderde lijst kunnen herhaalde lineaire zoekopdrachten 100 miljoen vergelijkingen kosten. Eén keer sorteren en 100 binaire zoekopdrachten uitvoeren kost ongeveer 20 miljoen vergelijkingen plus 2.000 controles van het midden. De voorbereiding wordt hergebruikt, wat het tweede plan aantrekkelijk maakt. Volgens dit globale kostenmodel ligt het omslagpunt rond 20 zoekopdrachten. De schatting hangt af van vergelijkbare bewerkingskosten en doorlopen in het slechtste geval; het is geen universele grens voor het aantal zoekopdrachten.
Weeg volgorde, verplaatsing en geheugen af
Bubblesort kan snel klaar zijn als alleen een paar naburige elementen verkeerd staat. [1, 2, 4, 3, 5] heeft één verwisseling in de eerste doorgang nodig en een tweede doorgang om de volgorde te bevestigen: zeven vergelijkingen. Maar “bijna gesorteerd” garandeert niet dat er weinig doorgangen nodig zijn. Een kleine waarde helemaal rechts kan per doorgang maar één positie naar links bewegen.
De weinige verwisselingen van selectionsort helpen als records verplaatsen kostbaar is. Zowel selectionsort als bubblesort gebruikt slechts een vaste hoeveelheid extra opslag. Mergesort verwerkt grote lijsten met een veel langzamere tijdsgroei, maar de gebruikelijke vorm met lijsten heeft ruimte nodig voor ongeveer nog een lijst vol elementen.
Als records met gelijke sleutels hun eerdere volgorde moeten behouden, kies dan een stabiele methode. Een lijst die al alfabetisch op naam staat, kun je stabiel op cijfer sorteren en tegelijk binnen elke cijfergroep alfabetisch houden. Gewone selectionsort kan die volgorde bij gelijke sleutels verstoren.
Gebruik geteste bibliotheekfuncties
Echte programma’s gebruiken meestal de ingebouwde sorteerfunctie van de taal. De stabiele sortering van Python gebruikt een adaptieve methode op basis van samenvoegen, algemeen bekend als Timsort, die profiteert van volgorde die al in de invoer aanwezig is. sorted(items) geeft een nieuwe lijst terug, terwijl items.sort() de bestaande lijst verandert. Een methode die als API-gedrag een lijst op zijn plaats verandert, kan intern nog steeds tijdelijk werkgeheugen gebruiken; ze hoeft niet te voldoen aan de definitie van vaste extra opslag die voor de eenvoudige sorteringen hierboven wordt gebruikt.
Voor een handvol elementen kan eenvoudige, heldere code belangrijker zijn dan de groei. Vergelijk bij grote verzamelingen het gedrag in het slechtste geval en het geheugen naast de eigenschappen die de taak werkelijk vereist.
Belangrijkste punten
- Neem de voorbereidingskosten mee als je zoekmethoden op ongesorteerde gegevens vergelijkt.
- Bij herhaald zoeken kunnen de kosten van één keer sorteren worden terugverdiend.
- Selectionsort beperkt verwisselingen; mergesort beperkt de tijdsgroei maar heeft extra opslag nodig.
- Gebruik een stabiele sortering om een eerdere volgorde binnen groepen met gelijke sleutels te behouden.
- Ingebouwde sorteerfuncties bieden geteste implementaties; bij kleine invoer kan eenvoud de voorkeur hebben.
Zoek- en sorteeralgoritmen: voorbeelden
1Vind een zoekwaarde zonder posities uit het oog te verliezen
13 stappen
- 1IntroductieVind een waarde en geef de positie aan
Bij een zoekopdracht moet je een opgeslagen waarde onderscheiden van de positie ervan. In
[7, 3, 9, 3, 5]lopen de posities van 0 tot en met 4. De waarde 3 staat op indexen 1 en 3.We controleren eerst posities op volgorde (lineair zoeken) en gebruiken daarna de gesorteerde volgorde om groepen posities uit te sluiten (binair zoeken). We tellen vergelijkingen om te zien hoeveel werk elke methode doet. Beide methoden geven bij succes een index terug en
-1als de zoekwaarde ontbreekt. - 2UitlegSluit met één ongelijkheid één positie uit
Lineair zoeken vergelijkt de zoekwaarde van links naar rechts met elk element. Een overeenkomst beëindigt de zoekopdracht onmiddellijk; bij een ongelijkheid gaat de methode naar de volgende positie.
Een ongesorteerde lijst geeft geen reden om latere elementen na een vroege ongelijkheid af te wijzen. Daarom hoort het teruggeven van “niet gevonden” na de lus, zodra elke positie is gecontroleerd.
- 3VoorbeeldVind de eerste 3
Zoek in
[7, 3, 9, 3, 5]naar 3.Op index 0 verschilt 7 van 3, dus ga je verder. Op index 1 is de opgeslagen waarde 3, dus geef je na twee vergelijkingen 1 terug.
De tweede 3 wordt nooit bekeken. De teruggegeven index is 1, terwijl het aantal vergelijkingen 2 is; die getallen beschrijven verschillende delen van de doorloop.
- 4UitdagingDoorloop een latere overeenkomst
Lineair zoeken controleert
[19, 4, 11, 4, 8]op 11. Welke index geeft de methode terug en hoeveel vergelijkingen maakt ze?---reveal---
De methode geeft na drie vergelijkingen index 2 terug: 19, 4 en dan 11. Een mislukt resultaat teruggeven na de eerste ongelijkheid zou ten onrechte bij 19 stoppen. Index 2 is de derde positie omdat posities bij nul beginnen.
- 5KernpuntLaat de zoekwaarde het stopmoment bepalen
Voor een niet-lege lijst met elementen gebruikt lineair zoeken in het beste geval één vergelijking en in het slechtste geval . Een lege lijst gebruikt er nul.
Als de zoekwaarde één keer voorkomt en even waarschijnlijk op elke positie staat, is het gemiddelde voor een succesvolle zoekopdracht . Elk voorkomen tellen verandert de taak: zelfs een vroege overeenkomst kan die volledige doorloop niet beëindigen.
- 6AnalogieGebruik de volgorde om een kant uit te sluiten
Bij een woordenboek kun je naar de helft bladeren waarin het gezochte woord staat. Binair zoeken gebruikt hetzelfde idee van ordening met exacte indexgrenzen.
De preconditie is dat de gegevens gesorteerd zijn. Als een middelste getal te klein is, is elk eerder getal ook te klein. Zonder volgorde geeft een vergelijking met het midden geen dergelijke informatie over de andere posities.
- 7UitlegHoud beide grensposities als kandidaat
Begin met
low = 0enhigh = n - 1. Bereken zolanglow <= highgeldtmid = (low + high) // 2.Geef
midterug als het element overeenkomt. Is de waarde te klein, zet danlow = mid + 1; is die te groot, zet danhigh = mid - 1. De gecontroleerde middenpositie wordt na beide soorten ongelijkheid uitgesloten, zodat elke bijwerking het resterende zoekinterval kleiner maakt. - 8VoorbeeldControleer het midden en daarna de rechterhelft
Zoek 64 in
[3, 8, 12, 17, 23, 31, 42, 56, 64, 77, 85]. De begingrenzen zijn 0 en 10. Hun naar beneden afgeronde middenpositie is 5, met waarde 31.Omdat 31 kleiner is dan 64, zet je
low = 6. De resterende grenzen 6 en 10 geven middenpositie 8. De waarde daar is 64, dus geef je na twee controles van het middelste element 8 terug. - 9VoorbeeldZie hoe een ontbrekende zoekwaarde het interval leegmaakt
Zoek in dezelfde gesorteerde lijst naar 20. De gecontroleerde indexen en waarden zijn 5 → 31, 2 → 12, 3 → 17 en 4 → 23.
Na de bijwerkingen zijn
low = 4enhigh = 3. Er blijft geen kandidaat over, dus geef je-1terug. De laatste controle was van belang: gelijke grenzen vlak daarvoor betekenden één kandidaat, geen leeg interval. - 10UitdagingBereken de middenpositie na elke bijwerking opnieuw
Zoek 34 in
[2, 7, 13, 21, 34, 55]met grenzen die meetellen en naar beneden afgeronde middenposities. Welke indexen worden gecontroleerd?---reveal---
Controleer eerst index 2, met waarde 13. Zet
low = 3terwijlhighop 5 blijft, zodat de volgende middenpositie 4 is. Daar staat 34: geef na twee controles 4 terug. De positie na 2 was niet automatisch de volgende middenpositie. - 11TipControleer de laatste kandidaat en sluit oude kandidaten uit
low <= highcontroleert een interval met één positie. Een strikte voorwaarde<mist[5]bij het zoeken naar 5.Gebruik
mid + 1enmid - 1na controles zonder overeenkomst. Metlow = midkan een zoekopdracht naar 20 in[10, 20]de middenpositie 0 oneindig herhalen. Als dubbele waarden overeenkomen, geeft deze versie een overeenkomende index terug, zonder garantie dat het de eerste is. - 12UitdagingKies een zoekmethode voor de werkelijke invoer
Je hebt een ongesorteerde lijst en moet één waarde opzoeken, zonder tijd om een gesorteerde kopie te maken. Welke behandelde zoekmethode kun je direct gebruiken en waarom?
---reveal---
Lineair zoeken is geschikt omdat elke gelijkheidscontrole geldig is zonder enige ordening. Binair zoeken heeft een gesorteerde volgorde nodig om de uitgesloten intervallen te rechtvaardigen. Een klein aantal controles van het midden kan een ontbrekende preconditie niet compenseren.
- 13SamenvattingGebruik de juiste onderbouwing om te stoppen
Lineair zoeken stopt bij de eerste overeenkomst of na een volledige doorloop. Binair zoeken gebruikt een gesorteerde volgorde en snelle toegang via indexen om een interval inclusief beide grenzen te verkleinen.
Noteer de teruggegeven index apart van het aantal bewerkingen. Binair zoeken heeft voor niet-lege invoer hoogstens controles van het midden nodig, maar elke controle kan in code meer dan één vergelijking bevatten.
2Bouw een volgorde op met verwisselingen tussen buren en verder gelegen elementen
16 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieMaak de sorteertaak precies
- 2UitlegBehoud zowel elementen als volgorde
- 3VoorbeeldBekijk wat stabiliteit behoudt
- 4UitdagingControleer beide voorwaarden voor sorteren
- 5UitlegBreng een groot element naar rechts
- 6VoorbeeldVolg drie opeenvolgende verwisselingen
- 7VoorbeeldTel de bevestigende doorgang mee
- 8UitdagingVergelijk verwisselingen met vergelijkingen
- 9KernpuntTel inversies om verwisselingen te tellen
- 10UitlegSelecteer een minimum voordat je het verplaatst
- 11VoorbeeldPlaats de eerste twee minima
- 12VoorbeeldRond af zonder een waarde met zichzelf te verwisselen
- 13UitdagingVind een minimum na het begindeel
- 14KernpuntEen verwisseling over afstand kan een gelijke sleutel passeren
- 15UitdagingKies een methode bij kostbare verplaatsingen
- 16SamenvattingVolg het gebied dat elke methode vastzet
3Splits een lijst en bouw die met samenvoegingen weer op
13 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieGebruik de volgorde die al in kleinere delen is opgebouwd
- 2UitlegVergelijk alleen de eerste ongebruikte elementen
- 3VoorbeeldVoeg de eerste paar waarden samen
- 4VoorbeeldKopieer het resterende lijstdeel nadat de vergelijkingen eindigen
- 5UitdagingVoltooi een samenvoeging en tel de vergelijkingen
- 6UitlegMaak elk recursief probleem kleiner
- 7VoorbeeldSplits acht elementen in afzonderlijke elementen
- 8VoorbeeldBouw paren en helften weer op
- 9VoorbeeldTel elk samenvoegingsniveau
- 10UitdagingTel het werk binnen de helften mee
- 11VerbandBehoud de volgorde bij gelijke sleutels tijdens het opbouwen
- 12UitdagingPas de methode toe op een grote stabiele sortering
- 13SamenvattingTel elementen over de niveaus heen
4Zet herhaald werk om in een tijdschatting
14 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieVraag hoeveel werk de volgende grootte vereist
- 2UitlegKies wat als stap telt
- 3VoorbeeldTel elk paar slechts één keer
- 4UitdagingLees de grenzen voordat je de groei benoemt
- 5KernpuntVermeld het geval bij het aantal
- 6UitlegProbeer de verdubbelingstest
- 7VoorbeeldOnderscheid een groeiaanduiding van een exact aantal
- 8UitdagingVind een omslagpunt met exacte modellen
- 9VerbandBekijk de grens van snellere hardware
- 10VoorbeeldSchaal een gemeten kwadratische tijd
- 11UitdagingBepaal een invoergrootte vanuit een tijdsbudget
- 12TipMeet vergelijkbare gevallen herhaaldelijk
- 13UitdagingGebruik waargenomen verhoudingen voor een voorspelling
- 14SamenvattingNeem het telmodel mee in de schatting
5Laat zien dat een algoritme werkt en bij de taak past
15 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieVraag om een garantie en praktische geschiktheid
- 2UitlegFormuleer de beloften voordat je ze bewijst
- 3VoorbeeldBreid de invariant van selectionsort uit
- 4VoorbeeldBehoud een mogelijke overeenkomst en verklein het interval
- 5UitdagingOnderscheid behoud van terminatie
- 6UitlegVoorspel resultaten aan de grens vóór de uitvoering
- 7VoorbeeldLaat een interval met twee elementen een lus blootleggen
- 8UitdagingVind de grens van de lus voor buren
- 9TipBewaar een minimale falende test
- 10UitlegTel de voorbereidingskosten mee
- 11VoorbeeldHergebruik de gesorteerde lijst voor zoekopdrachten
- 12UitdagingBereken of voorbereiding loont
- 13VerbandKies eigenschappen naast tijdsgroei
- 14UitdagingVerbind correctheid met een praktische eis
- 15SamenvattingGebruik argumenten, tests en kosten samen
Zoek- en sorteeralgoritmen: oefenvragen
Set 1: Vind waarden en volg de algoritmen10 Oefenvragen
Vraag 1 van 10
[12, 7, 18, 7] op 7. Welke index geeft de methode terug?Toon antwoordVerberg antwoord
Vraag 2 van 10
[4, 9, 15, 22, 30, 41, 57]. Welke indexen controleert de methode bij het zoeken naar 41?Toon antwoordVerberg antwoord
Vraag 3 van 10
[6, 2, 6, 1]. Welke uitvoer voldoet aan de specificatie voor oplopend sorteren?Toon antwoordVerberg antwoord
[1, 2, 6] heeft waarden op volgorde, maar verliest één element. Sorteren herschikt gegevens; het verwijdert geen herhaalde waarden.Vraag 4 van 10
[8, 3, 6, 2]?Toon antwoordVerberg antwoord
[3, 6, 2, 8] overblijft. De grootste waarde staat nu rechts op zijn plaats. Een volledig gesorteerd resultaat veronderstelt dat één doorgang ook het resterende begindeel ordent; deze doorloop laat zien dat dit niet zo is.Vraag 5 van 10
[2, 11] samen met [5, 14, 19]. Welke elementen moeten nog worden gekopieerd nadat 11 is gekopieerd?Toon antwoordVerberg antwoord
Vraag 6 van 10
[16]. Wat moet die teruggeven?Toon antwoordVerberg antwoord
[16] ongewijzigd terug. Een lege lijst teruggeven zou het oorspronkelijke element verliezen. Nog een recursieve splitsing is niet nodig omdat het probleem de stopgrootte al heeft bereikt.Vraag 7 van 10
Toon antwoordVerberg antwoord
Vraag 8 van 10
Toon antwoordVerberg antwoord
Vraag 9 van 10
Toon antwoordVerberg antwoord
Vraag 10 van 10
while low < high. Welke kleinste niet-lege test legt bloot dat een aanwezige zoekwaarde wordt gemist?Toon antwoordVerberg antwoord
Set 2: Tel werk en kies praktische methoden10 Oefenvragen
Sla deze les op om elk antwoord te zien en elke set te oefenen.
Vraag 1 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 2 van 10
[6, 12, 18, 25, 33, 46] de grenzen direct na de eerste controle bij het zoeken naar 30?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 3 van 10
[1, 3, 2, 4]. Hoeveel vergelijkingen maakt het voordat het stopt?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 4 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 5 van 10
[1, 8, 13] en [4, 9] worden alleen vergelijkingen tussen eerste ongebruikte elementen geteld. Hoeveel zijn dat er?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 6 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 7 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 8 van 10
[4, 4, -2] en geeft [-2, 4] terug. Aan welke eis heeft die niet voldaan?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 9 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 10 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Set 3: Leg grenzen uit en vergelijk afwegingen10 Oefenvragen
Sla deze les op om elk antwoord te zien en elke set te oefenen.
Vraag 1 van 10
[5, 11, 16, 24, 38, 47, 59, 70]. Welke indexen worden gecontroleerd voor de ontbrekende zoekwaarde 41?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 2 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 3 van 10
[18, 7, 12, 4, 9]?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 4 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 5 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 6 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 7 van 10
low = mid. Welk deel van een volledig correctheidsargument kan falen?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 8 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 9 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 10 van 10
[2A, 6B] en rechter records [2C, 5D] en vergelijkt alleen numerieke sleutels. Wat is de volgorde van de samengevoegde records?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Set 4: Analyseer doorlopen en onderbouw beslissingen10 Oefenvragen
Sla deze les op om elk antwoord te zien en elke set te oefenen.
Vraag 1 van 10
[14, 6, 21, 6]. Als ze direct bij de eerste overeenkomst stopt, welk paar van zoekwaarde en resultaat is dan mogelijk?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 2 van 10
low = 6 en high = 6, en het resterende element is gelijk aan de zoekwaarde. Wat doet de correcte lus?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 3 van 10
[5, 3, 5, 2, 4, 1]?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 4 van 10
< bij het vinden van elk minimum. Wat is de uiteindelijke volgorde van de records in [7A, 3X, 7B, 2Y, 3Z] als alleen numerieke sleutels worden vergeleken?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 5 van 10
[9, 1, 7, 3]. Hoeveel vergelijkingen tussen elementen maakt de volledige sortering als je alleen vergelijkingen bij samenvoegingen telt?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 6 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 7 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 8 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 9 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 10 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Kom je niet uit je eigen opgave? Huiswerkhulp
Kernbegrippen
A
aangrenzende elementen
items[j] met items[j + 1], waardoor de verplaatsing afhangt van naburige paren.afweging
B
basisbewerking
basisgeval
beste geval
binair zoeken
C
constante groei
D
directe toegang
dominante term
doorgang
E
eerste ongebruikte element
exponentiële groei
F
fout van één te veel of te weinig
low < high gebruikt voor een binair zoekinterval met grenzen die meetellen, wordt een laatste kandidaat overgeslagen wanneer de grenzen gelijk worden.G
gemiddelde geval
gesorteerd begindeel
groeisnelheid
I
in-placesortering
index
[8, 13, 21] bevat index 2 de waarde 21, ook al is dat in het dagelijks tellen het derde element.inversie
[8, 3, 6] vormt 8 een inversie met beide latere waarden, hoewel slechts één paar aangrenzend is.invoergrootte
K
kwadratische groei
L
lineair zoeken
lineaire groei
logaritmische groei
lusinvariant
M
mergesort
middenpositie
(2 + 7) // 2 index 4 als volgende middenpositie.O
omslagpunt
ongesorteerd einddeel
overloop van gehele getallen
P
permutatie
[2, 8, 2] en [2, 2, 8] zijn permutaties van elkaar; [2, 8] verliest één voorkomen.positiemarkering
postconditie
preconditie
R
randgeval
recursie
recursief geval
referentiemeting van de uitvoeringstijd
regressietest
resterend lijstdeel
[14, 20] overblijft, zijn beide elementen van het resterende lijstdeel nog nodig.resterend zoekinterval
S
samenvoegen
[3, 10] en [6, 12] geeft [3, 6, 10, 12] zonder een van beide invoerlijsten opnieuw te sorteren.selectionsort
slechtste geval
sorteerfunctie uit een bibliotheek
sorted van Python maakt een nieuwe resultatenlijst, terwijl list.sort() de bestaande lijst herschikt.sorteersleutel
sorteren
specificatie
stabiele sortering
T
tegenvoorbeeld
terminatie
testen met willekeurige invoer
sorted te vergelijken, kun je een geval vinden dat zorgvuldig gekozen tests hebben gemist.tijdsbudget
V
verdeel en heers
verdubbelingstest
verwisseling
[2, 9] veranderen in [9, 9] in plaats van de waarden om te wisselen.volledige doorloop
voorbereidingskosten
voorspelling van de uitvoeringstijd
vroegtijdige beëindiging
Z
zoeken
zoekwaarde
Over deze les
Door StudeliFout melden
Maak je eigen Studiemateriaal
Maak van je aantekeningen, slides en documenten Leermodules, Oefenvragen, Flashcards en 6 andere tools.