การประกวดรหัสชุดเลิกรา: การจัดเรียงที่ไม่ด่วน [ปิด]


28

งาน

เขียนโปรแกรมในภาษาที่คุณเลือกซึ่งอ่านบรรทัดอินพุตจากอินพุตมาตรฐานจนถึง EOF จากนั้นเขียนลงในเอาต์พุตมาตรฐานตามลำดับ ASCII คล้ายกับsortโปรแกรมบรรทัดคำสั่ง ตัวอย่างสั้น ๆ ที่ไม่มีการใช้เล่ห์เหลี่ยมใน Python คือ:

import sys

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

ส่วนที่ซ่อนเร้น

คล้ายกับThe OS Warเป้าหมายของคุณคือการพิสูจน์ว่าแพลตฟอร์มที่คุณโปรดปรานนั้น“ ดีกว่า” โดยให้โปรแกรมของคุณทำงานช้าลงมากขึ้นบนแพลตฟอร์มการแข่งขัน เพื่อประโยชน์ในการประกวดครั้งนี้ "แพลตฟอร์ม" ประกอบด้วยการรวมกันของ:

  • หน่วยประมวลผล
    • สถาปัตยกรรม (x86, Alpha, ARM, MIPS, PowerPC, ฯลฯ )
    • พยาน (64- บิตกับ 32- บิตกับ 16- บิต)
    • ใหญ่ - กับ - เอนเดียนน้อย
  • ระบบปฏิบัติการ
    • Windows กับ Linux เทียบกับ Mac OS ฯลฯ
    • เวอร์ชั่นต่าง ๆ ของระบบปฏิบัติการเดียวกัน
  • การใช้ภาษา
    • ผู้จำหน่ายคอมไพเลอร์ / ล่ามที่แตกต่างกัน (เช่น MSVC ++ กับ GCC)
    • คอมไพเลอร์ / ล่ามรุ่นเดียวกันหลายรุ่น

แม้ว่าคุณจะสามารถทำได้ตามข้อกำหนดโดยการเขียนโค้ดเช่น:

#ifndef _WIN32
    Sleep(1000);
#endif

คำตอบดังกล่าวไม่ควร upvoted เป้าหมายคือจะบอบบาง ตามหลักแล้วโค้ดของคุณควรมีลักษณะไม่ขึ้นกับแพลตฟอร์มเลย หากคุณไม่ได้มี#ifdefงบ (หรือเงื่อนไขขึ้นอยู่กับos.nameหรือSystem.Environment.OSVersionหรืออะไรก็ตาม) ที่พวกเขาควรจะมีเหตุผลที่น่าเชื่อถือ (ขึ้นอยู่กับการโกหกของหลักสูตร)

รวมไว้ในคำตอบของคุณ

  • รหัส
  • แพลตฟอร์ม "ที่ชื่นชอบ" และ "ไม่ชอบ" ของคุณ
  • อินพุตสำหรับทดสอบโปรแกรมของคุณ
  • เวลาทำงานบนแต่ละแพลตฟอร์มสำหรับอินพุตเดียวกัน
  • คำอธิบายว่าทำไมโปรแกรมรันช้ามากบนแพลตฟอร์มที่ไม่ชอบ

4
มันยากกว่าที่ฉันคิด คำตอบเดียวที่ฉันสามารถทำได้คือมีความยาวและชัดเจนเล็กน้อยหรือสั้นมากและชัดเจนมาก :-(
squeamish ossifrage

2
ฉันลงคะแนนให้ปิดคำถามนี้เป็นหัวข้อนอกเพราะความท้าทายที่ไม่ได้อยู่ในหัวข้อบนเว็บไซต์นี้อีกต่อไป meta.codegolf.stackexchange.com/a/8326/20469
cat

คำตอบ:


29

C

CleverSort

CleverSort เป็นอัลกอริธึมการเรียงสตริงแบบสองขั้นตอนที่ทันสมัย

ในขั้นตอนที่ 1 จะเริ่มต้นด้วยการเรียงลำดับบรรทัดอินพุตล่วงหน้าโดยใช้การเรียง Radixและสองไบต์แรกของแต่ละบรรทัด การเรียงลำดับ Radix นั้นไม่สามารถเปรียบเทียบกันได้และใช้งานได้ดีกับสตริง

ในขั้นตอนที่ 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 โดยเปิดการปรับให้เหมาะสมและสร้างรายการขนาดใหญ่แบบสุ่ม (เพียง 100,000 สาย) ของ 4 ไบต์ทุกบรรทัด:

$ 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

ไม่โทรมเกินไป

เครื่องหมายเล็ก ๆ น้อย ๆ ของ endian

$ time ./cleversort < input > /dev/null

real    0m27.598s
user    0m27.559s
sys     0m0.003s

Boo, Endian น้อย! Boo!

ลักษณะ

การเรียงลำดับการแทรกนั้นค่อนข้างมีประสิทธิภาพสำหรับรายการที่เกือบจะเรียงลำดับแล้ว แต่มันไม่มีประสิทธิภาพมากนักสำหรับการเรียงลำดับแบบสุ่ม

ส่วนที่ underhanded ของ CleverSort คือมาโครFIRSTSHORT :

#define FIRSTSHORT(N) *((uint16_t *) input[N])

บนเครื่องที่มีขนาดใหญ่การสั่งซื้อสตริงจำนวนเต็ม 8 บิตสองรูปแบบทางพจนานุกรมหรือแปลงเป็นจำนวนเต็ม 16 บิตและสั่งซื้อในภายหลังให้ผลลัพธ์เดียวกัน

โดยธรรมชาติแล้วสิ่งนี้สามารถเกิดขึ้นได้กับเครื่องจักรเล็ก ๆ น้อย ๆ เช่นกัน แต่ควรมีมาโคร

#define FIRSTSHORT(N) (input[N][0] | (input[N][1] >> 8))

ซึ่งทำงานได้ตามที่คาดหวังในทุกแพลตฟอร์ม

"เกณฑ์มาตรฐานขนาดใหญ่" ข้างต้นเป็นผลมาจากการใช้มาโครที่เหมาะสม

ด้วยแมโครที่ไม่ถูกต้องและเครื่องเล็ก ๆ น้อย ๆ รายการจะถูกจัดเรียงไว้ล่วงหน้าด้วยอักขระตัวที่สองของทุกบรรทัดทำให้เกิดการเรียงลำดับแบบสุ่มจากมุมมองของพจนานุกรม การเรียงลำดับการแทรกทำงานได้แย่มากในกรณีนี้


16

Python 2 กับ Python 3

เห็นได้ชัดว่า Python 3 นั้นมีขนาดของคำสั่งเร็วกว่า Python 2 หลาย ๆ ลองมาปรับใช้อัลกอริทึมShellsort นี้เป็นตัวอย่าง:

รหัส

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

เกณฑ์มาตรฐาน

เตรียมอินพุตทดสอบ สิ่งนี้นำมาจากคำตอบของ Dennis แต่มีคำน้อยกว่า - Python 2 ช้ามาก ...

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

Python 2

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

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

Python 3

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

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

รหัสลับอยู่ที่ไหน

ฉันคิดว่าผู้อ่านบางคนอาจต้องการตามล่าหลอกตัวเองดังนั้นฉันจึงซ่อนคำตอบด้วยแท็กสปอยเลอร์

max_sequence_elementเคล็ดลับคือการแบ่งจำนวนเต็มในการคำนวณของ ใน Python 2 1/2หาค่าเป็นศูนย์และดังนั้นการแสดงออกจึงเป็นศูนย์เสมอ อย่างไรก็ตามพฤติกรรมของผู้ปฏิบัติงานเปลี่ยนเป็นการแบ่งเป็นทศนิยมใน Python 3 เนื่องจากตัวแปรนี้ควบคุมความยาวของลำดับช่องว่างซึ่งเป็นพารามิเตอร์ที่สำคัญของ Shellsort, Python 2 สิ้นสุดลงโดยใช้ลำดับที่มีเพียงหนึ่งหมายเลขในขณะที่ Python 3 ใช้ลำดับที่ถูกต้อง สิ่งนี้ส่งผลให้รันไทม์กำลังสองสำหรับ Python 2

โบนัส 1:

คุณสามารถแก้ไขรหัสได้โดยเพิ่มจุดหลังจาก1หรือ2ในการคำนวณ

โบนัส 2:

อย่างน้อยในเครื่องของฉัน Python 2 จะเร็วกว่า Python 3 เล็กน้อยเมื่อเรียกใช้รหัสคงที่ ...


เล่นดี! เวลา Nitpix: flagดูเหมือนเป็นแบบเขียนอย่างเดียวคุณไม่สามารถลบมันได้หรือ นอกจากนี้ดูเหมือนว่าฟุ่มเฟือยถ้าคุณทำr if lst[i+h] < lst[i]: ...ในทางกลับกันถ้าคุณเก็บไว้rทำไมแลกเปลี่ยน คุณทำlst[i+h] = lst[i]ไม่ได้เหรอ ทั้งหมดนี้เป็นสิ่งที่ทำให้ไขว้เขวโดยเจตนาหรือไม่?
Jonas Kölker
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.