Une question classique de code de golf de tri


11

C'est une question de code-golf.

Contribution

Une liste d'entiers non négatifs dans n'importe quel format est la plus pratique.

Production

La même liste dans l'ordre trié dans n'importe quel format est la plus pratique.

Restriction

  • Votre code doit s'exécuter en temps O (n log n) dans le pire des casnest le nombre d'entiers en entrée. Cela signifie que le tri rapide aléatoire est sorti par exemple. Cependant, il existe de nombreuses autres options parmi lesquelles choisir.
  • N'utilisez pas de bibliothèque de tri / fonction / similaire. N'utilisez pas non plus ce qui fait la plupart du travail de tri pour vous comme une bibliothèque de tas. Fondamentalement, quoi que vous implémentiez, implémentez-le à partir de zéro.

Vous pouvez définir une fonction si vous le souhaitez, mais veuillez en montrer un exemple dans un programme complet qui fonctionne réellement. Il devrait fonctionner correctement et rapidement sur tous les cas de test ci-dessous.

Cas de 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]

Vos réponses

Veuillez indiquer l'algorithme de tri que vous avez mis en œuvre et la longueur de votre solution dans le titre de votre réponse.

O (n log n) algorithmes de tri temporel

Il existe de nombreux algorithmes de temps O (n log n). Ce tableau contient une liste de certains d'entre eux.


Certaines fonctions définies, telles que intersectle tri automatique du tableau. Je suppose que vous voulez aussi les exclure. Que diriez-vous unique(supprimer les doublons, trier le résultat)?
Luis Mendo

@DonMuesli Je le fais .. Je pense que cela intersectrelève de "similaire" s'il trie automatiquement le tableau. Si vous supprimez les doublons, vous obtiendrez une sortie incorrecte.

A propos de donner une mauvaise entrée, laissez-moi :-) Est-ce que "supprimer les doublons et trier" pourrait alors être utilisé?
Luis Mendo

3
Nitpick: 0 n'est pas un entier positif. (Sous entrée )
bécher

1
J'aime comment dès que la question a quelque chose à voir avec la performance, tout le monde s'éloigne des langues de golf même si c'est toujours du code-golf et que la solution la plus courte gagnera toujours.
Cyoce

Réponses:


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(:[])

Il s'agit d'un tri par fusion, implémenté de bas en haut. nous emballons d'abord chaque élément dans sa propre liste, puis les fusionnons deux par deux, puis les fusionnons à nouveau deux par deux, jusqu'à ce que nous nous retrouvions avec une seule liste.

(%)est la fonction de fusion
jfusionne les paires dans une liste de listes
rfusionne une liste complète de listes
sest la fonction de tri.

Utilisation: lancez un interprète et entrez s [3,5,2,6,7].

Edit: la façon dont je fusionnais les choses avant n'était pas le bon ordre, donc pour y remédier, j'avais besoin de 9 caractères supplémentaires.


1
@Lembik si vous voulez tester le programme et que vous ne voulez pas installer Haskell, vous pouvez utiliser ideone et ajouter une ligne comme celle-ci main = print (s [5,3,6,8]), qui sera définie comme principale pour imprimer le résultat du tri.
fier haskeller

Je pense que vous n'avez pas besoin []%s=s, car si le premier élément est [], la (x:a)correspondance échoue et le dernier cas retourne les éléments, donc ça s%[]réussit.
nimi

Tu es le vainqueur! La seule réponse utilisant moins d'octets ne s'est pas exécutée dans O (n log n).

@Lembik Bien, j'ai oublié que la réponse de Jelly n'était pas conforme.
fier haskeller

1
C'est maintenant qu'il semble :)

5

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

Il s'agit d'une implémentation heapsort. Je m'attends à ce que quelqu'un propose une fusion plus courte, mais j'aime celle-ci: P

Mise à jour: R mergesort battu. Ruby up next: 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)


J'aurais aimé écrire une réponse heapsort, mais cela ne fonctionne pas vraiment bien avec Haskell. Mon prochain essai serait JS, mais vous l'avez fait. Peut-être que je le ferai quand même. Idk
fier haskeller

@proudhaskeller Ah oui .. je viens de chercher stackoverflow.com/a/2186785/2179021 .

3

Python3, 132 octets

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]

Mergesort simple. Beaucoup d'octets ont été dépensés pour s'assurer que cela fonctionne réellement dans O (n log n), si seulement l' algorithme , mais pas l' implémentation doit être O (n log n), cela peut être raccourci:

Python3, 99 octets

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

Ce n'est pas O (n log n) car .pop(0)c'est O (n), ce qui rend la fonction de fusion O (n ^ 2). Mais c'est assez artificiel, comme cela .pop(0)aurait pu facilement être O (1).


Merci pour ça. Je voulais vraiment dire que l'algorithme et l'implémentation devraient être O (n log n).

Pour être clair, cela signifie que la version 132 est OK mais que la version 99 octets n'est pas conforme.

2

Julia, 166 octets

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 fonction principale est appelée Met elle appelle une fonction d'assistance m. Il utilise le tri par fusion , dont O ( n log n ) est la complexité la plus défavorable.

Exemple d'utilisation:

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

Non golfé:

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

C'est bon de voir Julia ici. Maintenant, nous avons aussi besoin de nim et de rouille :)

1
@Lembik Je pense que Sp3000 et Doorknob sont nos experts résidents Nim et Rust, respectivement. J'espère qu'ils rejoindront aussi le plaisir. ;)
Alex A.

2

R, 181 octets, 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)}

En retrait, avec de nouvelles lignes:

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

Cas de 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, fonction 243 octets (application autonome 315 octets), Mergesort

Cette réponse est destinée à être une fonction, mais peut être étendue pour être une application autonome.

Fonction uniquement (243 octets):

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
}

Application autonome (315 octets):

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

Usage:

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

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

Exemple d'entrée:

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

(OR)

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

Production:

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

OU

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

Contraintes et considérations:

  • Nécessite scalaz (bibliothèque très courante, non utilisée pour le tri ici)
  • Est 100% fonctionnel (rien de mutable!)

Attribution:


2

Gelée, 29 octets, tri par fusion

Comme la réponse Python d'orlp, cela utilise list.pop(0)sous le capot, ce qui est O(n), mais l'implémentation est formelle O(n log n).

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

Essayez-le ici.

Explication

               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]

Pourriez-vous ajouter quelques explications, s'il vous plaît.

Il y a beaucoup à expliquer :) Laissez-moi voir si je peux jouer un peu plus sur la dernière ligne
Lynn

Lorsque vous dites que l'implémentation est O (n log n) mais qu'elle utilise list.pop (0) sous le capot, qui est O (n), je suis confus. Que voulez-vous dire?

Je veux dire exactement ce que orlp a écrit dans sa réponse: ce n'est pas O (n log n) car .pop(0)c'est O (n), ce qui rend la fonction de fusion O (n ^ 2). Mais c'est assez artificiel, comme cela .pop(0)aurait pu facilement être O (1).
Lynn

Jelly est implémenté en Python et est implémenté en tant que .pop(0).
Lynn

1

Rubis, 167 octets

Algorithme de tri par fusion golfé, qui a le pire des cas 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}

Testez-le ici!

Pour tester, copiez et collez le code dans la fenêtre et ajoutez puts f[x]en bas, où x est un tableau avec l'entrée. (Assurez-vous que vous sélectionnez Ruby comme langue, bien sûr) Par exemple,puts f[[2, 2, 1, 9, 3, 7, 4, 1, 6, 7]]


Merci pour ça! Pouvez-vous le montrer aussi?

1
J'ai ajouté un lien pour que vous puissiez le tester.
Value Ink

1

Rubis, 297 octets

Tri par fusion. Programme complet, au lieu d'une fonction. Nécessite deux arguments à l'exécution: fichier d'entrée et fichier de sortie, chacun avec un élément par ligne.

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

Si cela raccourcissait votre code, vous devriez envisager d'adapter le code à une fonction qui obtient un tableau en entrée et renvoie la séquence triée. semble que cela vous débarrasserait de beaucoup d'octets.
fier haskeller

Si vous souhaitez le conserver en tant que programme complet au lieu d'une fonction, puis-je suggérer d'utiliser STDIN et STDOUT comme entrée / sortie, respectivement? $stdin.readlinesest déjà moins d'octets que open(ARGV[0]).readlines, même avec putsplusopen(ARGV[1],"w"){|f|f.puts
Value Ink

2
Et des trucs comme if $0==__FILE__c'est vraiment inutile dans un golf de code. Vous pouvez également condenser le remplacement de chacun ;par une nouvelle ligne - c'est le même nombre d'octets et (probablement) supprime le défilement horizontal du code. En outre, je vous recommande de consulter des conseils pour jouer au golf à Ruby .
daniero
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.