2.1 Grundlæggende sortering

I dette afsnit behandles to grundlæggende sorteringsmetoder, udvalgssortering og indsættelsessortering, samt en variation af den ene, shellsortering.

Spillets regler.

Vi betragter algoritmer på rækker af elementer, der hver indeholder en nøgle. Målet er at omarrangere elementerne således at deres nøgler til sidst står i ikke-aftagende ordning. I java konkretiseres nøgler af en indbygget mekanisme: grænsefladen for sammenlignelige elementer, Comparable. Med ganske få undtagelser vil vores kode kun bruge to metoder for at behandle til elementerne: sammenligningsmetoden less(), der afgør om et element er mindre end et andet, og ombytningsmetoden exch(), der bytter plads på to elementer.
private static boolean less(Comparable v, Comparable w) {
   return (v.compareTo(w) < 0);
}

private static void exch(Comparable[] a, int i, int j) {
   Comparable swap = a[i];
   a[i] = a[j];
   a[j] = swap;
} 

Derudover skaber v.compareTo(w) en undtagelse hvis v og w er inkompatible typer, eller hvis nogen af dem har værdien null.

Datumstypen Date.java viser, hvordan man implementerer sammenligningsgrænsefladen Comparable for en brugerdefineret datatype.

Udvalgssortering.

En af de enkleste sorteringsalgoritmer virker som følger: Begynd med at finde det mindste element i rækken, og lad det bytte plads med rækkens første element. Fortsæt med at finde det næstmindste element og lad det bytte plads med rækkens andet element. Fortsæt indtil hele rækken er sorteret. Denne algoritme kaldes udvalgssortering, fordi den hele tiden vælger det mindste, tilbageværende element. Programmet Selection.java implementer denne algoritme.

Selection sort

Påstand.

Udvalgssortering bruger \(\sim~N^2/2\) sammenligninger og \(N\) ombytninger for at sortere en række af længde \(N\).

Indsættelsessortering.

Den algoritme, kortspillere typisk bruger til at sortere kortene på hånden, er at betragte kortene et efter et og putte dem på deres rette plads bland de allerede behandlede kort. For at implementere dette i en række, skal vi skabe plads for det nye element ved at flytte de større elementer en position til højre inden vi kan sætte det nye element på den nu ledige plads. Programmet Insertion.java implementerer denne metode, som kaldes indsættelsessortering.

Selection sort

Påstand.

For en række af længde \(N\) som indeholder forskellige nøgler i uniformt tilfældig orden, bruger indsættelsesortering i gennemsnit \(\sim N^2/4\) sammenligninger og \(\sim N^2/4\) ombytninger. I værste flad bruges \(\sim N^2/2\) sammenligninger og \(\sim N^2/2\) ombytninger. I bedste fald bruges \(N-1\) sammenligninger og ingen ombytninger.

Indsættelsessortering virker udmærket for visse typer af ikke-tilfældige rækker, som man ofte møder i praksis, sågar hvis N er enorm. En inversion er et par af nøgler i uorden. For eksempel er der 11 inversioner i E X A M P L E, nemlig E-A, X-A, X-M, X-P, X-L, X-E, M-L, M-E, P-L, P-E og L-E. En række kaldes delvis sorteret, hvis antallet af inversioner i rækken er mindre en et konstant multiplum af rækkestørrelsen.

Påstand.

Antallet af ombytninger ved indsættelsessortering er lig med antallet af inversioner i rækken. Antallet af sammenligninger er mindst antallet af inversioner og højst antallet af inversioner plus rækkestørrelsen.

Egenskab.

For rækker af forskellige nøgler i uniformt tilfældig orden er køretiderne af indsættelsessortering og udvalssortering kvadratiske og inden for en lille konstant faktor af hinanden.

Programmet SortCompare.java bruger sorteringsmetoden sort() i to i kommandolinjen angivne sorteringsalgoritmer til at gennemføre et antal eksperimenter (sortering af tilfældige rækker af given størrelse) og skriver forholdet mellem de observerede køretider.

Visualisering af sorteringsalgoritmer.

Vi benytter en enkel visuel repræsentation for at synliggøre sorteringsalgoritmernes opførsel. Vi tegner rækkernes indhold som vertikale søjler, som skal sorteres efter deres højde. Programmerne SelectionBars.java og InsertionBars.java producerer disse visualiseringer.

Visualization of selection sort and insertion sort

Shellsortering.

Shellsortering er en enkel udvidelse af indsættelsessortering opkaldt efter Donald Shell, som beskrev metoden i 1959. Shellsortering tillader ombytning af elementer som står langt fra hinanden i rækken, hvilket skaber delvist sorterede rækker, der til sidst indsættelsessorteres. Givet et heltal h kaldes en sekvens h-sorteret, hvis alle delsekvenser bestående af hvert hte element er sorteret. En sorteret sekvens her h-sorteret for h=1.

An h-sorted file in shellsort
Ved at h-sortere for store værdier af h flyttes elementer over lange afstande uden at særligt mange andre elementer skal give plads. Efterhånden mindskes h, og elementer står allerede nogenlunde det rette sted i rækken. Hver faldende sekvens af værdier for h, der ender med h=1, vil resultere i en sorteret række. Programmet Shell.java implementerer shellsortering.

Shellsort
Programmet ShellBars.java producerer en visualisering af shellsortering.

Shellsort visualization

Egenskab.

Antallet af sammenligninger ved shellsortering med h = 1, 4, 13, 40, 121, 364, ... er begrænset af et lille multiplum af N gange længden af h-sekvensen.

Påstand.

Antallet af sammenligninger ved shellsortering med h = 1, 4, 13, 40, 121, 364, ... er proportional med N3/2.