C
聪明排序
CleverSort是一种先进的(即,过度设计和次优)两步字符串排序算法。
在步骤1中,首先使用基数排序和每行的前两个字节对输入行进行预排序。基数排序是非比较的,对字符串非常有效。
在步骤2中,它在字符串的预排序列表上使用插入排序。由于列表几乎是在步骤1之后排序的,因此插入排序对于此任务非常有效。
码
#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]);
}
平台类
我们都知道,高位优先机器比低位优先机器效率更高。为了进行基准测试,我们将在启用优化的情况下编译CleverSort并随机创建一个巨大的4字节行列表(刚好超过100,000个字符串):
$ 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
大端基准
$ time ./cleversort < input > /dev/null
real 0m0.185s
user 0m0.181s
sys 0m0.003s
不是太寒酸。
小端安贝克马克
$ time ./cleversort < input > /dev/null
real 0m27.598s
user 0m27.559s
sys 0m0.003s
嘘,小恩迪恩!!
描述
插入排序对于几乎排序的列表确实非常有效,但是对于随机排序的列表则效率非常低。
CleverSort的不足部分是FIRSTSHORT宏:
#define FIRSTSHORT(N) *((uint16_t *) input[N])
在big-endian机器上,按字典顺序对两个8位整数的字符串进行排序或将其转换为16位整数,然后对它们进行排序将产生相同的结果。
当然,这在小字节序机器上也是可能的,但是宏应该已经
#define FIRSTSHORT(N) (input[N][0] | (input[N][1] >> 8))
可以在所有平台上正常工作。
上面的“ big-endian基准”实际上是使用适当宏的结果。
如果使用了错误的宏和低位字节序的机器,则该列表将按每行的第二个字符进行预排序,从而从词典编排的角度进行随机排序。在这种情况下,插入排序的行为非常差。