merge sort å andra sidan fungerar enligt en grundläggande princip: det är ytterst lätt att slå samman redan sorterade matriser. Så det delar upp en startmatris i hälften om och om igen tills det bara är enstaka element. Sedan bygger det långsamt om huvudmatrisen genom att slå samman dessa element i sorterad ordning. Eftersom vi började från byggstenar i storlek ett var det väldigt enkelt att bygga initiala sorterade arrayer. Då är det lätt att slå samman dem. I slutändan spenderar vi O (n log n) tid, och (viktigare) gör vi det på ett sätt som garanteras vara stabilt.
nyckeln till att förstå Tim sorts implementering är att förstå dess användning av körningar. Tim Sort utnyttjar naturligt förekommande förinställda data till sin fördel. Med presorted menar vi helt enkelt att sekventiella element alla ökar eller minskar (vi bryr oss inte om vilka).
först ställer vi in en minrun storlek. Vad vi menar med detta är att vi vill se till att alla våra körningar är åtminstone en viss längd. Observera att vi inte garanterar att vi hittar körningar av denna storlek — vi kommer in i detta senare. Vi säger helt enkelt att en körning måste vara minst av en viss längd.
När vi stöter på en körning ställer vi den åt sidan. När vi hittar den längsta körningen inom ettminrun intervall. Vi har nu en välbekant datastruktur: en liten, sorterad array. Om det är minst minrun I Längd, då huzzah! Vi är bra på att gå vidare. Om det inte är, sätter vi insättningssortering i spel.
Du kanske kommer ihåg från ovan att Infogningssortering är särskilt effektiv på två typer av arrayer: små och redan sorterade. Vad vi just gjort är en liten, sorterad array. Om det inte är minst minrun I längd, når vi framåt och tar tag i tillräckligt med andra element för att slutföra körningen, använd sedan insättningssortering för att driva dem in i vår sorterade array, snabbt och enkelt. Självklart, om en körning möter slutet av matrisen kan du låta det vara lite kort.
När du har skapat alla dina körningar (dvs. sorterade subarrays) använder du din Sammanfogningssortering för att gå med dem tillsammans. I bästa fall är hela arrayen redan sorterad och Tim Sort är smart nog att veta att det inte behöver göra något annat. Andra gånger tenderar det bara att vara extremt effektivt. Som en extra fördel är både Infogningssortering och Sammanfogningssortering stabila, så den resulterande matrisen är stabil.
För dem som föredrar kulor:
upprätta enminrun storlek som är en effekt av 2 (vanligtvis 32, aldrig mer än 64 eller din insättning Sort kommer att förlora effektivitet)
hitta en körning i den förstaminrun av data.
om körningen inte är minst minrun I Längd, använd insättningssortering för att ta tag i efterföljande eller tidigare objekt och sätt in dem i körningen tills det är rätt minsta storlek.
upprepa tills hela matrisen är uppdelad i sorterade underavsnitt.
använd den senare halvan av Merge Sort för att gå med i de beställda matriserna.
slutsats
Tim Sort är kraftfull. Det är snabbt och stabilt, men kanske viktigast av allt utnyttjar det verkliga världsmönster och använder dem för att bygga en slutprodukt. Är det för varje situation? Förmodligen inte. Lycka till att programmera det på en whiteboard under en intervju, och om du bara behöver en snabb enkel sorteringsalgoritm i en nypa vill du förmodligen inte bry dig om att implementera något så här komplext. Men för Dataforskare som krossar siffror är det mer än värt en titt.
för nyfikna kan du kolla in hela Tim-Sorteringskoden på github.
tack
Tack en och alla till mina läsare. Jag uppskattar din tid och hoppas verkligen att du hittade innehållet informativt. Om du har några frågor eller svar är du välkommen att släppa en nedan.