Класичне питання сортування коду-гольфу


11

Це питання з кодовим гольфом.

Вхідні дані

Список невід’ємних цілих чисел у будь-якому форматі є найзручнішим.

Вихідні дані

Той самий список у відсортованому порядку в будь-якому форматі є найзручнішим.

Обмеження

  • Ваш код повинен працювати в O (n log n) час у гіршому випадку, де nкількість вхідних чисел. Це означає, що, наприклад, рандомізований кваксорт. Однак є багато інших варіантів на вибір.
  • Не використовуйте будь-яку бібліотеку сортування / функцію / подібне. Також не використовуйте нічого, що робить для вас більшу частину сортування як бібліотека купи. В основному, що б ви не реалізували, реалізуйте це з нуля.

Ви можете визначити функцію, якщо вам подобається, але тоді, будь ласка, покажіть її приклад у повній програмі, яка фактично працює. Він повинен успішно та швидко працювати на всіх наведених нижче тестових випадках.

Тестові справи

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]

Ваші відповіді

Будь ласка, вкажіть запроваджений алгоритм сортування та довжину вашого рішення у назві вашої відповіді.

Алгоритми сортування часу O (n log n)

Існує багато алгоритмів часу O (n log n). У цій таблиці є список деяких з них.


Деякі встановлені функції, такі як intersectавтоматичне сортування масиву. Я думаю, ти теж хочеш їх виправити. Як щодо unique(видалити дублікати, сортувати результат)?
Луїс Мендо

@DonMuesli Я це роблю .. Я думаю, що intersectпідпадає під "подібний", якщо він автоматично сортує масив. Якщо ви видалите дублікати, ви отримаєте неправильний висновок.

Про неправильне введення, залиште це мені :-) Чи можна тоді "видалити дублікати і сортувати"?
Луїс Мендо

3
Nitpick: 0 - не додатне ціле число. (Under Input )
стакан

1
Мені подобається, як тільки питання має відношення до продуктивності, всі відпливають від мов гольфу, хоча це все-таки кодовий гольф і найкоротше рішення все одно виграє.
Кіос

Відповіді:


8

Хаскелл, 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(:[])

Це сортування злиття, реалізоване знизу вгору. спочатку ми пакуємо кожен елемент у свій власний список, а потім об'єднуємо їх два-два, і знову об'єднуємо їх два-два, поки нам не залишиться один список.

(%)є функція
jзлиття об'єднує пари в списку списків
rзливається повний список списків
s- це функція сортування.

Використання: запустіть перекладач та введіть s [3,5,2,6,7].

Редагувати: те, як я раніше об'єднував речі, не був правильним порядком, тож щоб виправити це, мені знадобилося ще 9 символів.


1
@Lembik, якщо ви хочете протестувати програму, а ви не хочете встановлювати Haskell, ви можете використовувати ideone та додати рядок типу main = print (s [5,3,6,8]), який буде основним для друку результату сортування.
гордий haskeller

Я думаю, вам це не потрібно []%s=s, тому що якщо перший елемент є [], (x:a)збіг виходить з ладу, а останній випалює елементи, так що це s%[]вдається.
німі

Ви переможець! Єдина відповідь, що використовує меншу кількість байтів, не працювала в O (n log n).

@Lembik Правильно, я забув, що відповідь Jelly не відповідала.
гордий haskeller

1
Зараз це здається :)

5

JavaScript (ES6), 195 193 191 189 188 186 183 182 179 174 172 байт

Це велика реалізація. Я очікую, що хтось придумає коротший об'єднання, але мені це подобається: P

Оновлення: побито R об'єднання. Рубіть далі: 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)}

Тест (Firefox)


Я б хотів написати відповідь на велику думку, але це не дуже добре справляється з Haskell. Наступною моєю спробою буде JS, але ти це зробив. Можливо, я все одно буду це робити. ІДК
горде haskeller

@proudhaskeller Ага так .. я просто шукав stackoverflow.com/a/2186785/2179021 .

3

Python3, 132 байти

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]

Простий злиття. Багато байтів було витрачено на те, щоб переконатися, що це насправді працює в O (n log n), як тільки алгоритм , але не реалізація повинен бути O (n log n), це можна скоротити:

Python3, 99 байт

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

Це не O (n log n), оскільки .pop(0)O (n), що робить функцію злиття O (n ^ 2). Але це досить штучно, як це .pop(0)міг легко бути O (1).


Дякую за це. Я, безумовно, мав на увазі, що алгоритм і реалізація повинні бути O (n log n).

Щоб було зрозуміло, це означає, що з 132 версією нормально, але 99-байтна версія не відповідає.

2

Юлія, 166 байт

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

Основна функція називається Mі викликає функцію помічника m. Він використовує сортування злиття , яке має O ( n log n ) як найгірший складний випадок.

Приклад використання:

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

Безголівки:

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

Приємно бачити Юлію тут. Тепер нам потрібні нім і іржа :)

1
@Lembik Я думаю, що Sp3000 та Doorknob - наші резиденти, експерти Nim та Rust відповідно. Сподіваємось, вони також приєднуються до забави. ;)
Олексій А.

2

R, 181 байт, 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)}

Відступ з новими рядками:

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

Тестові приклади:

> 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, функція 243 байт (автономний додаток 315 байт), Mergesort

Ця відповідь призначена як функція, але може бути розширена, щоб бути окремим додатком.

Тільки функція (243 байти):

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
}

Автономний додаток (315 байт):

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

Використання:

Функція: G.s(List(**[Paste your array here]**).toStream).toList

Застосування: sbt "run **[Paste your array here]**"

Приклад введення:

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

(OR)

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

Вихід:

res1: Список [Int] = Список (1, 2, 3, 8, 10, 120)

АБО

Список (2, 3, 24, 65, 123, 563, 764, 5423)

Обмеження та міркування:

  • Потрібен скалаз (дуже поширена бібліотека, тут не використовується для сортування)
  • На 100% функціональний (нічого не змінюється!)

Віднесення:


2

Желе, 29 байт, сортуйте сорт

Як і відповідь Python від Orlp, це використовується list.pop(0)під кришкою, що є O(n), але реалізація формально O(n log n).

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

Спробуйте тут.

Пояснення

               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]

Не хотіли б додати пояснення, будь ласка.

Є багато що пояснити :) Дозвольте мені побачити, чи зможу я покататись на останній лінії трохи більше
Лінн

Коли ви говорите, що реалізація - це O (n log n), але вона використовує list.pop (0) під кришкою, що є O (n) Я плутаюся. Що ви маєте на увазі?

Я маю на увазі саме те, що orlp написав у своїй відповіді: Це не O (n log n), тому що .pop(0)O (n), що робить функцію злиття O (n ^ 2). Але це досить штучно, як це .pop(0)міг легко бути O (1).
Лінн

Jelly реалізований в Python і реалізований як .pop(0).
Лінн

1

Рубі, 167 байт

Алгоритм сортування об'єднаних полів, який має найгірший випадок 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}

Тестуйте його тут!

Щоб перевірити, скопіюйте та вставте код у вікно та додайте puts f[x]внизу, де x - масив із введенням. (Переконайтеся, що ви вибрали Ruby як мову, звичайно). Наприклад,puts f[[2, 2, 1, 9, 3, 7, 4, 1, 6, 7]]


Дякую за це! Чи можете ви показати, що він також працює?

1
Я додав посилання, щоб ви могли його протестувати.
Значення чорнила

1

Рубін, 297 байт

Об’єднання сортування. Повна програма, а не функція. Потрібні два аргументи під час виконання: вхідний і вихідний файл, кожен з одним елементом у рядку.

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

Якщо це скоротить ваш код, слід розглянути можливість адаптації коду до функції, яка отримує масив як вхідний і повертає відсортовану послідовність. Здається, ви позбудетеся від багатьох байтів.
гордий haskeller

Якщо ви збираєтесь зберігати його як повну програму замість функції, чи можу я запропонувати використовувати STDIN та STDOUT як вхід / вихід відповідно? $stdin.readlinesвже менше байт , ніж open(ARGV[0]).readlines, то ж саме з putsбільшopen(ARGV[1],"w"){|f|f.puts
Значення Ink

2
І такі речі, як if $0==__FILE__насправді, непотрібні в гольф-коді. Ви також можете замінити кожен ;на новий рядок - це той самий кількість байтів і (можливо) видаляє горизонтальну прокрутку коду. Також рекомендую ознайомитись із порадами щодо гольфу в Рубі .
daniero
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.