C
CleverSort
CleverSort, son teknoloji ürünü (yani aşırı tasarlanmış ve en iyi alt) iki aşamalı dize sıralama algoritmasıdır.
1. adımda, giriş satırlarını radix sıralama ve her satırın ilk iki baytı kullanarak önceden sıralayarak başlar . Radix sıralama karşılaştırmalı değildir ve karakter dizileri için çok iyi çalışır.
2. adımda , önceden sıralanmış dizeler listesinde ekleme sıralamasını kullanır . Liste neredeyse 1. adımdan sonra sıralandığından, bu sıralama için ekleme sıralama oldukça verimlidir.
kod
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Convert first two bytes of Nth line into integer
#define FIRSTSHORT(N) *((uint16_t *) input[N])
int main()
{
char **input = 0, **output, *ptemp;
int first_index[65536], i, j, lines = 0, occurrences[65536];
size_t temp;
// Read lines from STDIN
while(1)
{
if(lines % 1000 == 0)
input = realloc(input, 1000 * (lines / 1000 + 1) * sizeof(char*));
if(getline(&input[lines], &temp, stdin) != -1)
lines++;
else
break;
}
output = malloc(lines * sizeof(char*));
// Radix sort
memset(occurrences, 0, 65536 * sizeof(int));
for(i = 0; i < lines; i++) occurrences[FIRSTSHORT(i)]++;
first_index[0] = 0;
for(i = 0; i < 65536 - 1; i++)
first_index[i + 1] = first_index[i] + occurrences[i];
memset(occurrences, 0, 65536 * sizeof(int));
for(i = 0; i < lines; i++)
{
temp = FIRSTSHORT(i), output[first_index[temp] + occurrences[temp]++] = input[i];
}
// Insertion sort
for(i = 1; i < lines; i++)
{
j = i;
while(j > 0 && strcmp(output[j - 1], output[j]) > 0)
ptemp = output[j - 1], output[j - 1] = output[j], output[j] = ptemp, j--;
}
// Write sorted lines to STDOUT
for(i = 0; i < lines; i++)
printf("%s", output[i]);
}
Platformlar
Hepimiz büyük-endian makinelerinin küçük-endian emsallerinden çok daha verimli olduğunu biliyoruz. Karşılaştırma için, CleverSort'u açık olan optimizasyonlarla derleyeceğiz ve rastgele olarak 4 baytlık satırlar içeren (100.000'den fazla dizeden oluşan) büyük bir liste oluşturacağız:
$ gcc -o cleversort -Ofast cleversort.c
$ head -c 300000 /dev/zero | openssl enc -aes-256-cbc -k '' | base64 -w 4 > input
$ wc -l input
100011 input
Big-endian benchmark
$ time ./cleversort < input > /dev/null
real 0m0.185s
user 0m0.181s
sys 0m0.003s
O kadar da eski püskü değil.
Küçük Endian Bechmark
$ time ./cleversort < input > /dev/null
real 0m27.598s
user 0m27.559s
sys 0m0.003s
Boo, küçük Endian! Boo!
Açıklama
Ekleme sıralama neredeyse sıralanan listeler için oldukça verimlidir, ancak rastgele sıralananlar için korkunç derecede verimsizdir.
CleverSort'un temel kısmı FIRSTSHORT makrosudur :
#define FIRSTSHORT(N) *((uint16_t *) input[N])
Büyük endian makinelerinde, iki 8 bitlik tamsayıdan oluşan bir dizgeyi sözlüksel olarak sıralamak veya bunları 16 bitlik tam sayılara dönüştürmek ve daha sonra sıralamak aynı sonuçları verir.
Doğal olarak, bu küçük-endian makinelerinde de mümkündür, ancak makro
#define FIRSTSHORT(N) (input[N][0] | (input[N][1] >> 8))
tüm platformlarda beklendiği gibi çalışıyor.
Yukarıdaki "big-endian benchmark" aslında doğru makroyu kullanmanın sonucudur.
Yanlış makro ve küçük bir endian makinesiyle, liste her satırın ikinci karakterine göre önceden sıralanır, bu da sözlükten bakış açısından rasgele bir sıralamaya yol açar. Ekleme sıralama bu durumda çok kötü davranır.