一个经典的排序代码高尔夫球问题


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(删除重复项,对结果进行排序)?
Luis Mendo

@DonMuesli我做.. intersect如果自动对数组进行排序,我认为它属于“相似”类。如果删除重复项,将给出错误的输出。

关于输入错误,请交给我:-)然后可以使用“删除重复项和排序”吗?
路易斯·门多

3
Nitpick:0不是正整数。(输入下
烧杯

1
我喜欢这个问题与性能有何关系,每个人都会偏离高尔夫球语言,即使这仍然是代码问题,而且最短的解决方案仍然会获胜。
Cyoce

Answers:


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]),这将使main设置为打印排序结果。
骄傲的haskeller

我认为您不需要[]%s=s,因为如果第一个元素为[],则(x:a)匹配失败,最后一种情况将元素翻转,从而s%[]成功。
nimi

你是赢家!使用较少字节的唯一答案不是在O(n log n)中运行。

@Lembik对,我忘了果冻的答案不符合要求。
骄傲的haskeller

1
现在看来:)

5

的JavaScript(ES6),195 193 191 189 188 186个 183 182 179 174 172字节

这是一个堆排序实现。我希望有人提出一个更短的mergesort,但我喜欢这个:P

更新:R mergesort被殴打。接下来的Ruby: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,但是您已经做到了。也许我仍然会这样做。IDK
傲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]

简单的mergesort。花了很多字节来确保它实际上以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。它使用合并排序,其最坏情况下的复杂度为On 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专家。希望他们也加入其中。;)
Alex A.

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:List [Int] = List(1、2、3、8、10、120)

要么

清单(2、3、24、65、123、563、764、5423)

约束和注意事项:

  • 需要scalaz(非常常见的库,此处未用于排序)
  • 具有100%的功能(没有任何可变性!)

归因:


2

果冻,29个字节,合并排序

就像orlp的Python答案一样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

Ruby,167个字节

Golfed合并排序算法,具有最坏情况的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

Ruby,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,与同putsopen(ARGV[1],"w"){|f|f.puts
价值油墨

2
if $0==__FILE__在代码高尔夫中,这样的东西实际上是不必要的。您可能还希望用;换行符替换每个行-字节数相同,并且(可能)删除代码的水平滚动。另外,我建议您查看Ruby中打高尔夫球的技巧
daniero
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.