अंडरहैंड कोड प्रतियोगिता: नॉट-सो क्विक सॉर्ट [बंद]


28

काम

अपनी पसंद की भाषा में, एक प्रोग्राम लिखें, जो ईओएफ तक मानक इनपुट से इनपुट की लाइनों को पढ़ता है, और फिर उन्हें ASCIIbetical क्रम में मानक आउटपुट के समान लिखता है। sort कमांड-लाइन प्रोग्राम के । पायथन में एक छोटा, गैर-रेखांकित उदाहरण है:

import sys

for line in sorted(sys.stdin):
    print(line.rstrip('\n'))

नीचे का भाग

ओएस युद्ध के समान , आपका लक्ष्य यह साबित करना है कि आपका पसंदीदा प्लेटफ़ॉर्म "बेहतर" है, आपके कार्यक्रम को जानबूझकर एक प्रतिस्पर्धा वाले मंच पर बहुत धीरे-धीरे चलाया जाता है। इस प्रतियोगिता के लिए, "प्लेटफ़ॉर्म" में किसी भी संयोजन शामिल हैं:

  • प्रोसेसर
    • वास्तुकला (x86, अल्फा, एआरएम, एमआइपी, पावरपीसी, आदि)
    • साक्षी (64-बिट बनाम 32-बिट बनाम 16-बिट)
    • बड़ा- बनाम छोटा-सा
  • ऑपरेटिंग सिस्टम
    • विंडोज बनाम लिनक्स बनाम मैक ओएस, आदि।
    • एक ही ऑपरेटिंग सिस्टम के विभिन्न संस्करण
  • भाषा कार्यान्वयन
    • विभिन्न संकलक / दुभाषिया विक्रेता (जैसे, MSVC ++ बनाम GCC)
    • एक ही संकलक / दुभाषिया के विभिन्न संस्करण

यद्यपि आप कोड लिखकर आवश्यकताओं को पूरा कर सकते हैं:

#ifndef _WIN32
    Sleep(1000);
#endif

इस तरह के जवाब को अपवित्र नहीं किया जाना चाहिए। लक्ष्य सूक्ष्म होना है। आदर्श रूप में, आपके कोड को ऐसा दिखना चाहिए कि यह प्लेटफ़ॉर्म-निर्भर नहीं है। यदि आप करते हैं किसी भी है #ifdef(के आधार पर या शर्तों बयान os.nameया System.Environment.OSVersionया जो कुछ भी), वे एक प्रशंसनीय औचित्य (बेशक एक झूठ, के आधार पर) होना चाहिए।

अपने उत्तर में शामिल करें

  • कोड
  • आपके "पसंदीदा" और "प्रतिकूल" प्लेटफ़ॉर्म।
  • एक इनपुट जिसके साथ अपने कार्यक्रम का परीक्षण करें।
  • एक ही इनपुट के लिए प्रत्येक प्लेटफ़ॉर्म पर चलने का समय।
  • प्रतिकूल प्लेटफ़ॉर्म पर कार्यक्रम इतनी धीमी गति से क्यों चलता है, इसका विवरण ।

4
यह मेरे विचार से कठिन है। केवल जवाब मैं के साथ आ सकते हैं बहुत लंबे समय या तो कर रहे हैं और थोड़ा स्पष्ट है, या बहुत ही कम और अत्यंत स्पष्ट :-(
उतरी ossifrage

2
मैं इस प्रश्न को ऑफ-टॉपिक के रूप में बंद करने के लिए मतदान कर रहा हूं क्योंकि इस साइट पर अंडरहैंड चुनौतियां अब विषय पर नहीं हैं। meta.codegolf.stackexchange.com/a/8326/20469
बिल्ली

जवाबों:


29

सी

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))

जो सभी प्लेटफार्मों पर अपेक्षित रूप से काम करता है।

उपरोक्त "बड़ा-एंडियन बेंचमार्क" वास्तव में उचित मैक्रो का उपयोग करने का परिणाम है।

गलत मैक्रो और एक छोटे से एंडियन मशीन के साथ, सूची को हर पंक्ति के दूसरे चरित्र द्वारा पूर्व-क्रमबद्ध किया जाता है , जिसके परिणामस्वरूप लेक्सिकोग्राफिक दृष्टिकोण से यादृच्छिक क्रम होता है। सम्मिलन क्रम इस मामले में बहुत खराब व्यवहार करता है।


16

पायथन 2 बनाम पायथन 3

जाहिर है, पायथन 3, पाइथन 2 की तुलना में तेज़ी से परिमाण के कई आदेश हैं। आइए इसे शेलसॉर्ट एल्गोरिथ्म के एक उदाहरण के रूप में लागू करें :

कोड

import sys
from math import log

def shellsort(lst):

    ciura_sequence = [1, 4, 10, 23, 57, 132, 301, 701]  # best known gap sequence (Ciura, 2001)

    # check if we have to extend the sequence using the formula h_k = int(2.25h_k-1)
    max_sequence_element = 1/2*len(lst)
    if ciura_sequence[-1] <= max_sequence_element:
        n_additional_elements = int((log(max_sequence_element)-log(701)) / log(2.25))
        ciura_sequence += [int(701*2.25**k) for k in range(1,n_additional_elements+1)]
    else:
        # shorten the sequence if necessary
        while ciura_sequence[-1] >= max_sequence_element and len(ciura_sequence)>1:
            ciura_sequence.pop()

    # reverse the sequence so we start sorting using the largest gap
    ciura_sequence.reverse()

    # shellsort from http://sortvis.org/algorithms/shellsort.html
    for h in ciura_sequence:
        for j in range(h, len(lst)):
            i = j - h
            r = lst[j]
            flag = 0
            while i > -1:
                if r < lst[i]:
                    flag = 1
                    lst[i+h], lst[i] = lst[i], lst[i+h]
                    i -= h
                else:
                    break
            lst[i+h] = r

    return lst

# read from stdin, sort and print
input_list = [line.strip() for line in sys.stdin]
for line in shellsort(input_list):
    print(line)

assert(input_list==sorted(input_list))

बेंचमार्क

एक परीक्षण इनपुट तैयार करें। यह डेनिस के जवाब से लिया गया है लेकिन कम शब्दों में - पायथन 2 बहुत धीमी है ...

$ head -c 100000 /dev/zero | openssl enc -aes-256-cbc -k '' | base64 -w 4 > input

अजगर २

$ time python2 underhanded2.py < input > /dev/null 

real    1m55.267s
user    1m55.020s
sys     0m0.284s

अजगर ३

$ time python3 underhanded2.py < input > /dev/null 

real    0m0.426s
user    0m0.420s
sys     0m0.006s

अंडरहैंड कोड कहां है?

मुझे लगता है कि कुछ पाठक स्वयं चालबाज का शिकार करना चाहते हैं, इसलिए मैं एक स्पॉइलर टैग के साथ उत्तर छिपाता हूं।

चाल की गणना में पूर्णांक विभाजन है max_sequence_element। पायथन में 2 1/2शून्य का मूल्यांकन करता है और इसलिए अभिव्यक्ति हमेशा शून्य है। हालाँकि, ऑपरेटर का व्यवहार पाइथन 3 में फ्लोटिंग पॉइंट डिवीजन में बदल गया है। जैसा कि यह चर गैप अनुक्रम की लंबाई को नियंत्रित करता है, जो शेलसॉर्ट का एक महत्वपूर्ण पैरामीटर है, पायथन 2 एक सीक्वेंस का उपयोग करके समाप्त होता है जिसमें केवल पायथन होता है 3 सही अनुक्रम का उपयोग करता है। इसका परिणाम पायथन 2 के लिए एक द्विघात रन टाइम में होता है।

बोनस 1:

आप गणना में 1या उसके बाद बस एक बिंदु जोड़कर कोड को ठीक कर सकते हैं 2

बोनस 2:

कम से कम मेरी मशीन पर पायथन 2 तय कोड को चलाने पर पायथन 3 से थोड़ा तेज है ...


बहुत बढ़िया! नाइटपिक्स का समय: flagकेवल लेखन ही दिखता है, क्या आप इसे हटा नहीं सकते? इसके अलावा, rअगर आप ऐसा करते हैं तो बहुत अच्छा लगता है if lst[i+h] < lst[i]: ...। दूसरी ओर, यदि आप रखते rहैं तो स्वैप क्यों करते हैं? क्या आप बस नहीं कर सकते थे lst[i+h] = lst[i]? क्या यह सब एक जानबूझकर विकर्षण है?
जोनास कोल्कर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.