Una classica domanda sul codice-golf


11

Questa è una domanda di code-golf.

Ingresso

Un elenco di numeri interi non negativi in ​​qualsiasi formato è il più conveniente.

Produzione

Lo stesso elenco in ordine ordinato in qualsiasi formato è il più conveniente.

Restrizione

  • Il codice deve essere eseguito nel tempo O (n log n) nel peggiore dei casi in cui nè il numero di numeri interi nell'input. Ciò significa che Quicksort randomizzato è fuori ad esempio. Tuttavia, ci sono molte altre opzioni tra cui scegliere.
  • Non utilizzare alcuna libreria / funzione / simile di ordinamento. Inoltre, non utilizzare nulla che svolga la maggior parte del lavoro di ordinamento come una libreria di heap. Fondamentalmente, qualunque cosa tu attui, implementala da zero.

Puoi definire una funzione se vuoi, ma per favore mostrane un esempio in un programma completo che funziona davvero. Dovrebbe essere eseguito correttamente e rapidamente su tutti i casi di test di seguito.

Casi test

In: [9, 8, 3, 2, 4, 6, 5, 1, 7, 0]
Out:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In: [72, 59, 95, 68, 84]
Out:[59, 68, 72, 84, 95]

In: [2, 2, 1, 9, 3, 7, 4, 1, 6, 7]
Out:[1, 1, 2, 2, 3, 4, 6, 7, 7, 9]

In: [2397725, 1925225, 3304534, 7806949, 4487711, 8337622, 2276714, 3088926, 4274324,  667269]
Out:[667269,1925225, 2276714, 2397725,3088926, 3304534, 4274324, 4487711, 7806949, 8337622]

Le tue risposte

Indica l'algoritmo di ordinamento che hai implementato e la lunghezza della soluzione nel titolo della risposta.

O (n log n) algoritmi di ordinamento temporale

Esistono molti algoritmi temporali O (n log n) esistenti. Questa tabella contiene un elenco di alcuni di essi.


Alcune funzioni impostate come intersectl'ordinamento automatico dell'array. Immagino che tu voglia escludere anche quelli. Che ne dici unique(rimuovi duplicati, ordina il risultato)?
Luis Mendo,

@DonMuesli. Sì. Penso che diventi intersect"simile" se ordina automaticamente l'array. Se rimuovi i duplicati, otterrai un output errato.

A proposito di dare un input sbagliato, lascialo a me :-) Potrebbe quindi essere "rimuovere i duplicati e ordinare"?
Luis Mendo,

3
Nitpick: 0 non è un numero intero positivo. (Sotto Input )
Becher

1
Mi piace il fatto che non appena la domanda abbia a che fare con le prestazioni, tutti si allontanano dalle lingue del golf, anche se questo è ancora code-golf e la soluzione più corta continuerà a vincere.
Cyoce,

Risposte:


8

Haskell, 87 80 89

s%[]=s
(x:a)%q|x<=q!!0=x:a%q
p%q=q%p
j(x:y:s)=x%y:j s
j a=a
r[x]=x
r s=r$j s
s=r.map(:[])

Questo è un tipo di unione, implementato dal basso verso l'alto. prima impacchettiamo ogni elemento nella sua propria lista, quindi li uniamo due per due e poi li uniamo due per due, fino a quando non ci rimane un elenco.

(%)è la funzione di unione
junisce le coppie in un elenco di elenchi
runisce un elenco completo di elenchi
sè la funzione di ordinamento.

Utilizzo: esegui un interprete e inserisci s [3,5,2,6,7].

Modifica: il modo in cui univo le cose prima non era nell'ordine giusto, quindi per risolverlo avevo bisogno di altri 9 personaggi.


1
@Lembik se vuoi testare il programma e non vuoi installare Haskell, puoi usare ideone e aggiungere una riga come main = print (s [5,3,6,8]), che imposterà main per stampare il risultato dell'ordinamento.
orgoglioso haskeller il

Penso che non sia necessario []%s=s, perché se il primo elemento è [], la (x:a)corrispondenza fallisce e l'ultimo caso capovolge gli elementi, in modo che abbia s%[]successo.
nimi,

Sei il vincitore! L'unica risposta utilizzando meno byte non è stata eseguita in O (n log n).

@Lembik Bene, ho dimenticato la risposta di Jelly non conforme.
orgoglioso haskeller il

1
Ora sembra :)

5

JavaScript (ES6), 195 193 191 189 188 188 186 183 182 179 174 172 byte

Questa è un'implementazione heapsort. Mi aspetto che qualcuno realizzi un mergesort più corto, ma questo mi piace: P

Aggiornamento: R mergesort battuto. Ruby up successivo: D

S=l=>{e=l.length
W=(a,b)=>[l[a],l[b]]=[l[b],l[a]]
D=s=>{for(;(c=s*2+1)<e;s=r<s?s:e)s=l[r=s]<l[c]?c:s,W(r,s=++c<e&&l[s]<l[c]?c:s)}
for(s=e>>1;s;)D(--s)
for(;--e;D(0))W(0,e)}

Test (Firefox)


Mi sarebbe piaciuto scrivere una risposta heapsort, ma non funziona davvero bene con Haskell. Il mio prossimo tentativo sarebbe JS, ma ce l'hai fatta. Forse lo farò comunque. Idk
orgoglioso haskeller il

@proudhaskeller Ah sì .. ho appena cercato stackoverflow.com/a/2186785/2179021 .

3

Python3, 132 byte

def S(l):
 if len(l)<2:return l
 a,b,o=S(l[::2]),S(l[1::2]),[]
 while a and b:o.append([a,b][a[-1]<b[-1]].pop())
 return a+b+o[::-1]

Fusione semplice. Sono stati spesi molti byte per assicurarsi che ciò avvenga effettivamente in O (n log n), se solo l' algoritmo , ma non l' implementazione deve essere O (n log n), questo può essere abbreviato:

Python3, 99 byte

def m(a,b):
 while a+b:yield[a,b][a<b].pop(0)
S=lambda l:l[1:]and list(m(S(l[::2]),S(l[1::2])))or l

Questo non è O (n log n) perché .pop(0)è O (n), rendendo la funzione di unione O (n ^ 2). Ma questo è abbastanza artificiale, come .pop(0)avrebbe potuto facilmente essere O (1).


Grazie per questo. Intendevo sicuramente che l'algoritmo e l'implementazione dovevano essere O (n log n).

Per essere chiari, ciò significa che la versione 132 è OK ma la versione 99 byte non è conforme.

2

Julia, 166 byte

m(a,b,j=1,k=1,L=endof)=[(j<=L(a)&&k<=L(b)&&a[j]<b[k])||k>L(b)?a[(j+=1)-1]:b[(k+=1)-1]for i=1:L([a;b])]
M(x,n=endof(x))=n>1?m(M(x[1:(q=ceil(Int,n÷2))]),M(x[q+1:n])):x

La funzione primaria viene chiamata Me chiama una funzione di supporto m. Utilizza l' ordinamento di tipo merge , che ha O ( n log n ) come complessità peggiore.

Esempio di utilizzo:

x = [9, 8, 3, 2, 4, 6, 5, 1, 7, 0]
println(M(x))              # prints [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
println(M(x) == sort(x))   # prints true

Ungolfed:

function m(a, b, i=1, k=1, L=endof)
    return [(j <= L(a) && k <= L(b) && a[j] < b[k]) || k > L(b) ?
            a[(j+=1)-1] : b[(k+=1)-1] for i = 1:L([a; b])]
end

function M(x, n=endof(x))
    q = ceil(Int, n÷2)
    return n > 1 ? m(M(x[1:q]), M([q+1:n])) : x
end

Bello vedere Julia qui. Ora abbiamo bisogno anche di nim e ruggine :)

1
@Lembik Penso che Sp3000 e Doorknob siano rispettivamente i nostri esperti Nim e Rust residenti. Spero che anche loro si uniscano al divertimento. ;)
Alex A.

2

R, 181 byte, Mergesort

L=length;s=function(S)if(L(S)<2){S}else{h=1:(L(S)/2);A=s(S[h]);B=s(S[-h]);Z=c();if(A[L(A)]>B[1])while(L(A)&L(B))if(A[1]<B[1]){Z=c(Z,A[1]);A=A[-1]}else{Z=c(Z,B[1]);B=B[-1]};c(Z,A,B)}

Rientrato, con nuove righe:

L=length
s=function(S)
    if(L(S)<2){
        S
    }else{
        h=1:(L(S)/2)
        A=s(S[h])
        B=s(S[-h])
        Z=c()
        if(A[L(A)]>B[1])
#Merge helper function incorporated from here ...
            while(L(A)&L(B))
                if(A[1]<B[1]){
                    Z=c(Z,A[1])
                    A=A[-1]
                }else{
                    Z=c(Z,B[1])
                    B=B[-1]
                }
#...to here. Following line both finishes merge function and handles 'else' case:
        c(Z,A,B)
    }

Casi test:

> L=length;s=function(S)if(L(S)<2){S}else{h=1:(L(S)/2);A=s(S[h]);B=s(S[-h]);Z=c();if(A[L(A)]>B[1])while(L(A)&L(B))if(A[1]<B[1]){Z=c(Z,A[1]);A=A[-1]}else{Z=c(Z,B[1]);B=B[-1]};c(Z,A,B)}
> s(c(2397725, 1925225, 3304534, 7806949, 4487711, 8337622, 2276714, 3088926, 4274324,  667269))
 [1]  667269 1925225 2276714 2397725 3088926 3304534 4274324 4487711 7806949 8337622
> s(c(2, 2, 1, 9, 3, 7, 4, 1, 6, 7))
 [1] 1 1 2 2 3 4 6 7 7 9
> s(c(72, 59, 95, 68, 84))
 [1] 59 68 72 84 95
> s(c(9, 8, 3, 2, 4, 6, 5, 1, 7, 0))
 [1] 0 1 2 3 4 5 6 7 8 9

2

Scala, funzione 243 byte (app autonoma 315 byte), Mergesort

Questa risposta intende essere una funzione, ma può essere espansa per essere un'applicazione autonoma.

Solo funzione (243 byte):

object G{
type S=Stream[Int]
def m(f:(S,S)):S=f match{
case(x#::a,b@(y#::_))if x<=y=>x#::m(a,b)
case(a,y#::b)=>y#::m(a,b)
case(a,Empty)=>a
case(_,b)=>b}
def s(a:S):S=if(a.length>1)((q:S,w:S)=>m(s(q),s(w))).tupled(a.splitAt(a.length/2))else a
}

Applicazione stand-alone (315 byte):

object G extends App{
type S=Stream[Int]
def m(f:(S,S)):S=f match{
case(x#::a,b@(y#::_))if x<=y=>x#::m(a,b)
case(a,y#::b)=>y#::m(a,b)
case(a,Empty)=>a
case(_,b)=>b}
def s(a:S):S=if(a.length>1)((q:S,w:S)=>m(s(q),s(w))).tupled(a.splitAt(a.length/2))else a
println(s(args(0).split(",").map(_.toInt).toStream).toList)
}

Uso:

Funzione: G.s(List(**[Paste your array here]**).toStream).toList

Applicazione: sbt "run **[Paste your array here]**"

Esempio di input:

scala> G.s(List(10,2,120,1,8,3).toStream).toList

(OR)

$ sbt "run 5423,123,24,563,65,2,3,764"

Produzione:

res1: Elenco [Int] = Elenco (1, 2, 3, 8, 10, 120)

O

Elenco (2, 3, 24, 65, 123, 563, 764, 5423)

Vincoli e considerazioni:

  • Richiede scalaz (libreria molto comune, non utilizzata per l'ordinamento qui)
  • Funzionale al 100% (niente mutevole!)

Attribuzione:


2

Jelly, 29 byte, unisci l'ordinamento

Come la risposta di Python di orlp, questo usa list.pop(0)sotto il cofano, che è O(n), ma l'implementazione è formale O(n log n).

ṛð>ṛḢð¡Ḣ;ñ
ç;ȧ?
s2Z߀ç/µL>1µ¡

Provalo qui.

Spiegazione

               Define f(x, y):    (merge helper)
                 Implicitly store x in α.
ṛ    ð¡          Replace it with y this many times:
 ð>ṛḢ              (x > y)[0].
       Ḣ         Pop the first element off that list (either x or y).
        ;ñ       Append it to g(x, y).

               Define g(x, y):    (merge)
  ȧ?             If x and y are non-empty:
ç                  Return f(x, y)
                 Else:
 ;                 Return concat(x, y).

               Define main(z):    (merge sort)
       µL>1µ¡    Repeat (len(z) > 1) times:
s2                 Split z in chunks of length two.   [[9, 7], [1, 3], [2, 8]]
  Z                Transpose the resulting array.     [[9, 1, 2], [7, 3, 8]]
   ߀              Apply main() recursively to each.  [[1, 2, 9], [3, 7, 8]]
     ç/            Apply g on these two elements.     [1, 2, 3, 7, 8, 9]

Ti dispiacerebbe aggiungere qualche spiegazione per favore.

C'è molto da spiegare :) Fammi vedere se riesco a giocare a golf sull'ultima linea un po 'di più
Lynn

Quando dici che l'implementazione è O (n log n) ma usa list.pop (0) sotto il cofano, che è O (n), sono confuso. Cosa intendi?

Intendo esattamente ciò che orlp ha scritto nella sua risposta: Questo non è O (n log n) perché .pop(0)è O (n), rendendo la funzione di unione O (n ^ 2). Ma questo è abbastanza artificiale, come .pop(0)avrebbe potuto facilmente essere O (1).
Lynn,

Jelly è implementata in Python ed è implementata come .pop(0).
Lynn,

1

Rubino, 167 byte

Algoritmo di ordinamento di tipo merge golfato, che presenta il caso peggiore O (n log n)

f=->x{m=->a,b{i,j,l,y,z=0,0,[],a.size,b.size
while i<y&&j<z
c=a[i]<b[j]
l<<(c ?a[i]:b[j])
c ?i+=1:j+=1
end
l+=a[i,y]+b[j,z]}
l=x.size
l>1?m[f[x[0,l/2]],f[x[l/2,l]]]:x}

Provalo qui!

Per testare, copia e incolla il codice nella finestra e aggiungi puts f[x]in fondo, dove x è un array con l'input. (Assicurati di selezionare Ruby come lingua, ovviamente) Ad esempio,puts f[[2, 2, 1, 9, 3, 7, 4, 1, 6, 7]]


Grazie per questo! Puoi mostrare che funziona anche?

1
Ho aggiunto un link in modo da poterlo testare.
Value Ink

1

Rubino, 297 byte

Unisci ordinamento. Programma completo, anziché una funzione. Richiede due argomenti in fase di runtime: file di input e file di output, ciascuno con un elemento per riga.

if $0==__FILE__;v=open(ARGV[0]).readlines.map{|e|e.to_i}.map{|e|[e]};v=v.each_slice(2).map{|e|a,b,r=e[0],e[1],[];while true;if(!a)||a.empty?;r+=b;break;end;if(!b)||b.empty?;r+=a;break;end;r<<(a[0]<b[0]?a:b).shift;end;r}while v.size>1;open(ARGV[1],"w"){|f|f.puts(v[0].join("\n"))if !v.empty?};end

Se accorciasse il codice, dovresti considerare di adattare il codice a una funzione che ottiene un array come input e restituisce la sequenza ordinata. sembra che ti libererebbe di molti byte.
orgoglioso haskeller il

Se lo manterrai come un programma completo anziché come una funzione, potrei suggerire di utilizzare STDIN e STDOUT come input / output, rispettivamente? $stdin.readlinesè già meno byte di open(ARGV[0]).readlines, lo stesso vale per putsOveropen(ARGV[1],"w"){|f|f.puts
Value Ink

2
E cose del genere non if $0==__FILE__sono davvero necessarie in un golf da codice. Potresti anche usare un conduttore che sostituisca ciascuno ;con una nuova riga: è lo stesso conteggio byte e (probabilmente) rimuove lo scorrimento orizzontale del codice. Inoltre, ti consiglio di dare un'occhiata ai suggerimenti per giocare a golf a Ruby .
daniero,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.