सी
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]);
}
प्लेटफार्म
हम सभी जानते हैं कि बड़े-एंडियन मशीनें अपने छोटे-एंडियन समकक्षों की तुलना में बहुत अधिक कुशल हैं। बेंचमार्किंग के लिए, हम क्लीवरसेट को अनुकूलन के साथ संकलित करेंगे और बेतरतीब ढंग से 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
बू, थोड़ा एंडियन! बू!
विवरण
प्रविष्टि सॉर्ट वास्तव में लगभग-सॉर्ट की गई सूचियों के लिए कुशल है, लेकिन यह यादृच्छिक रूप से सॉर्ट किए गए लोगों के लिए बहुत ही अयोग्य है।
क्लेवरसॉर्ट का अंडरहैंड हिस्सा सबसे पहला मैक्रो है:
#define FIRSTSHORT(N) *((uint16_t *) input[N])
बड़े-एंडियन मशीनों पर, दो 8-बिट पूर्णांक के एक स्ट्रिंग को शाब्दिक रूप से क्रमबद्ध करना या उन्हें 16-बिट पूर्णांक में परिवर्तित करना और बाद में उन्हें आदेश देना समान परिणाम देता है।
स्वाभाविक रूप से, यह छोटे एंडियन मशीनों पर भी संभव है, लेकिन मैक्रो होना चाहिए था
#define FIRSTSHORT(N) (input[N][0] | (input[N][1] >> 8))
जो सभी प्लेटफार्मों पर अपेक्षित रूप से काम करता है।
उपरोक्त "बड़ा-एंडियन बेंचमार्क" वास्तव में उचित मैक्रो का उपयोग करने का परिणाम है।
गलत मैक्रो और एक छोटे से एंडियन मशीन के साथ, सूची को हर पंक्ति के दूसरे चरित्र द्वारा पूर्व-क्रमबद्ध किया जाता है , जिसके परिणामस्वरूप लेक्सिकोग्राफिक दृष्टिकोण से यादृच्छिक क्रम होता है। सम्मिलन क्रम इस मामले में बहुत खराब व्यवहार करता है।