Thanosソートアルゴリズムを実装する


93

ソートアルゴリズムは次のようになります。

リストはソートされていませんが、すべてのアイテムの半分をスナップします(リストからそれらを削除します)。リストが並べ替えられるか、アイテムが1つだけ残るまで続行します(デフォルトで並べ替えられます)。このソートアルゴリズムは、実装に基づいて異なる結果をもたらす場合があります。

アイテムの削除手順は、決定する実装次第ですが、リストは、アイテムの削除手順の1回のパスの後、以前の半分の長さにする必要があります。アルゴリズムは、リストの長さが半分になるまで、または記載されていない場合、前半またはリスト、リストの後半、すべての奇数アイテム、すべて偶数アイテムを一度に1つずつ削除することを決定できます。

入力リストには、2 ^ n個のアイテムの完全に分割可能なリストだけでなく、任意の量のアイテム(理由として、最大1000個のアイテム)を含めることができます。リストが奇数の場合は、(n + 1)/ 2または(n-1)/ 2のいずれかのアイテムを削除する必要があります。ハードコーディングされているか、実行時にランダムに決定されます。自分で決めてください:宇宙に奇妙な量の生物が含まれていたら、サノスはどうするでしょうか?

前のアイテムよりも小さいアイテムがない場合、リストはソートされます。入力で重複が発生したり、出力で重複が発生したりする場合があります。

プログラムは、整数の配列(stdinを介して、または個々の項目または配列パラメーターとしてパラメーターとして)を受け取り、ソートされた配列を返す(またはstdoutに出力する)必要があります。

例:

// A sorted list remains sorted
[1, 2, 3, 4, 5] -> [1, 2, 3, 4, 5]

// A list with duplicates may keep duplicates in the result
[1, 2, 3, 4, 3] -> [1, 3, 3] // Removing every second item
[1, 2, 3, 4, 3] -> [3, 4, 3] -> [4, 3] -> [3] // Removing the first half
[1, 2, 3, 4, 3] -> [1, 2] // Removing the last half

[1, 2, 4, 3, 5] 異なる結果を与える可能性があります:

// Removing every second item:
[1, 2, 4, 3, 5] -> [1, 4, 5]

または:

// Removing the first half of the list
[1, 2, 4, 3, 5] -> [3, 5] // With (n+1)/2 items removed
[1, 2, 4, 3, 5] -> [4, 3, 5] -> [3, 5] // With (n-1)/2 items removed

または:

// Removing the last half of the list
[1, 2, 4, 3, 5] -> [1, 2] // With (n+1)/2 items removed
[1, 2, 4, 3, 5] -> [1, 2, 4] // With (n-1)/2 items removed

または:

// Taking random items away until half (in this case (n-1)/2) of the items remain
[1, 2, 4, 3, 5] -> [1, 4, 3] -> [4, 3] -> [4]

複数の異なるスナップアルゴリズムに対して実際に複数のスナップを必要とするテストケースを作成すると、非常に役立ちます。
無関係な文字列

22
答えの半分をソートして削除する必要はありませんか?
Sumner18

4
推奨されるテストケース:[9, 1, 1, 1, 1]。私自身のアルゴリズムはこの入力で失敗しました
コナーオブライエン

回答:





12

Brachylog(v2)、6バイト

≤₁|ḍt↰

オンラインでお試しください!

これは関数の提出です。通常どおり、左から入力、右へ出力。(TIOリンクは、関数を完全なプログラムに自動的にラップするコマンドライン引数を使用するため、実際に機能を確認できます。)

説明

≤₁|ḍt↰
≤₁       Assert that {the input} is sorted {and output it}
  |      Handler for exceptions (e.g. assertion failures):
   ḍ     Split the list into two halves (as evenly as possible)
    t    Take the last (i.e. second) half
     ↰   Recurse {and output the result of the recursion}

ボーナスラウンド

≤₁|⊇ᵇlᵍḍhtṛ↰

オンラインでお試しください!

スナップはランダムにするためのものですよね?以下は、生き残る要素をランダムに選択するプログラムのバージョンです(各ラウンドで半分が生き残ることを保証します)。

≤₁|⊇ᵇlᵍḍhtṛ↰
≤₁            Assert that {the input} is sorted {and output it}
  |           Handler for exceptions (e.g. assertion failures):
   ⊇ᵇ         Find all subsets of the input (preserving order)
     lᵍ       Group them by length
       ḍht    Find the group with median length:
         t      last element of
        h       first
       ḍ        half (split so that the first half is larger)
          ṛ   Pick a random subset from that group
           ↰  Recurse

我々は要素の順序を変更することができれば、これはかなり短くなりますが、whyeverソートアルゴリズムはしたいと思うことを


12
無限の石ごとに1バイト。
ジェクリン

@djechlin無限バイトは、あなたが頭、特に顎に行かなければならない理由です。
グレートダック

10

Perl 6、30バイト

$!={[<=]($_)??$_!!.[^*/2].&$!}

オンラインでお試しください!

リストがソートされるまでリストの後半を削除する再帰関数。

説明:

$!={                         }    # Assign the function to $!
    [<=]($_)??                    # If the input is sorted
              $_                  # Return the input
                !!                # Else
                  .[^*/2]         # Take the first half of the list (rounding up)
                         .&$!     # And apply the function again


8

Java 10、106 97バイト

L->{for(;;L=L.subList(0,L.size()/2)){int p=1<<31,f=1;for(int i:L)f=p>(p=i)?0:f;if(f>0)return L;}}

@OlivierGrégoireのおかげで-9バイト。

オンラインでお試しください。

繰り返しごとにリストの最初の半分だけを残し、リストサイズが奇数の場合はアイテムを削除します。n+12

説明:

L->{               // Method with Integer-list as both parameter and return-type
  for(;;           //  Loop indefinitely:
      L=L.subList(0,L.size()/2)){
                   //    After every iteration: only leave halve the numbers in the list
    int p=1<<31,   //   Previous integer, starting at -2147483648
        f=1;       //   Flag-integer, starting at 1
    for(int i:L)   //   Inner loop over the integer in the list:
      f=p>(p=i)?   //    If `a>b` in a pair of integers `a,b`:
         0         //     Set the flag to 0
        :          //    Else (`a<=b`):
         f;        //     Leave the flag the same
    if(f>0)        //   If the flag is still 1 after the loop:
      return L;}}  //    Return the list as result

n->{for(;n.reduce((1<<31)+0d,(a,b)->a==.5|b<a?.5:b)==.5;n=n.skip(n.count()/2));return n;} はストリームを使用して短くなりますがjava.lang.IllegalStateException: stream has already been operated upon or closed、ストリームを返した後にエラーを回避する方法を見つけることができませんでした
Ignoranceの具体化

@EmbodimentofIgnoranceこれreduceは、ストリームを閉じる端末操作であるために発生します。reduce同じストリームで2回呼び出すことはできません。ただし、新しいストリームを作成できます。
オリビエグレゴワール


@OlivierGrégoireその順序はとても単純に見えるので、私はそれを見ることができます。:)ありがとう!
Kevin Cruijssen

1
心配する必要はありません。それは明らかではありませんでした。それを見つける前に少なくとも10のバージョンをテストしました;)
オリビエグレゴワール

8

Wolfram言語(Mathematica)、30バイト

#//.x_/;Sort@x!=x:>x[[;;;;2]]&

オンラインでお試しください!

@Doorknobは12バイトを節約しました


1
前半を取得する代わりに、他のすべての要素(x[[;;;;2]])を取得することで、いくつかのバイトを節約できます。
ドアノブ

@Doorknobはい、もちろん…
J42161217

を使用することでいくらか節約できると考えましたがOrderedQ、機能させることができませんでした
グレッグマーティン

@GregMartin私がOrderedQ最初のアプローチで使用した(編集を参照)
J42161217



6

05AB1E8 7 バイト

[Ð{Q#ιн

@Emignaのおかげで-1バイト。

反復ごとにすべての奇数の0インデックス付きアイテムを削除するため、リストサイズが奇数の場合はアイテムを削除します。n12

オンラインそれを試してみてくださいまたはいくつかのより多くのテストケースを検証する(またはステップバイステップの各反復のために、これらのテストケースを検証します)。

@Grimyによる7 バイトの代替

ΔÐ{Ê>äн

繰り返しごとに最後のアイテム(または、リストサイズが奇数の場合はアイテム)を削除します。n2n12

オンラインそれを試してみてくださいまたはいくつかのより多くのテストケースを検証する(またはステップバイステップの各反復のために、これらのテストケースを検証します)。

説明:

[        # Start an infinite loop:
 Ð       #  Triplicate the list (which is the implicit input-list in the first iteration)
  {Q     #  Sort a copy, and check if they are equal
    #    #   If it is: Stop the infinite loop (and output the result implicitly)
  ι      #  Uninterweave: halve the list into two parts; first containing all even-indexed
         #  items, second containing all odd-indexed items (0-indexed)
         #   i.e. [4,5,2,8,1] → [[4,2,1],[5,8]]
   н     #  And only leave the first part

Δ        # Loop until the result no longer changes:
 Ð       #  Triplicate the list (which is the implicit input-list in the first iteration)
       #  Sort a copy, and check if they are NOT equal (1 if truthy; 0 if falsey)
    >    #  Increase this by 1 (so 1 if the list is sorted; 2 if it isn't sorted)
     ä   #  Split the list in that many parts
      н  #  And only leave the first part
         # (and output the result implicitly after it no longer changes)

3
他のすべての要素戦略に切り替える場合のι代わりに使用できます。
エミグナ

1
「残り半分を削除する」戦略を使用した代替案7ΔÐ{Ê>äн
グリミー

@Grimyそれはとてもいいアプローチでもあります。それを私の投稿に追加しますか(もちろんあなたにクレジットを付けます)、それとも別の回答として投稿しますか?
ケビンクルーッセン

自由に追加してください。
グリミー

6

TI-BASIC(TI-84)、47 42 45 44バイト

@SolomonUckoのおかげで-1バイト!

Ans→L1:Ans→L2:SortA(L1:While max(L1≠Ans:iPart(.5dim(Ans→dim(L2:L2→L1:SortA(L1:End:Ans

入力リストはですAns
出力は入力されAns、暗黙的に出力されます。

説明:

Ans→L1                  ;store the input into two lists
Ans→L2
SortA(L1                ;sort the first list
                        ; two lists are needed because "SortA(" edits the list it sorts
While max(L1≠Ans        ;loop until both lists are strictly equal
iPart(.5dim(Ans→dim(L2  ;remove the latter half of the second list
                        ; removes (n+1)/2 elements if list has an odd length
L2→L1                   ;store the new list into the first list (updates "Ans")
SortA(L1                ;sort the first list
End
Ans                     ;implicitly output the list when the loop ends

注: TI-BASICはトークン化された言語です。文字数がバイト数と等しくありませ


私はあなたが交換することができると思うnot(min(L1=Ansmax(L1≠Ans、バイトを保存します。
ソロモンウッコ


3

Haskell57 55バイト(ASCIIのみのおかげ)

f x|or$zipWith(>)x$tail x=f$take(div(length x)2)x|1>0=x

オンラインでお試しください!


元のコード:

f x|or$zipWith(>)x(tail x)=f(take(div(length x)2)x)|1>0=x

オンラインでお試しください!


ゴルフをしていない:

f xs | sorted xs = f (halve xs)
     | otherwise = xs

sorted xs = or (zipWith (>) xs (tail xs))

halve xs = take (length xs `div` 2) xs

1
PPCGへようこそ!
Rɪᴋᴇʀ




3

オクターブ、49バイト

l=input('');while(~issorted(l))l=l(1:2:end);end;l

オンラインでお試しください!これは、より退屈なほうが良い旅でした。以下の2つのさらに興味深いエントリに注意してください。

50バイト

function l=q(l)if(~issorted(l))l=q(l(1:2:end));end

オンラインでお試しください!面白くない命令型ソリューションの代わりに、1バイトだけ追加して再帰的ソリューションを実行できます。

53バイト

f(f=@(g)@(l){l,@()g(g)(l(1:2:end))}{2-issorted(l)}())

オンラインでお試しください!うん。再帰的な匿名関数。私の質問に対する @ceilingcatの素晴らしい回答のおかげです。引数リストで自身を定義することにより、再帰的な匿名関数を返す匿名関数。私は匿名関数が好きです。うーん


2

MATL、11バイト

tv`1L)ttS-a

オンラインでお試しください!

これは、1つおきのアイテムを削除することで機能します。

説明

t      % Take a row vector as input (implicit). Duplicate
v      % Vertically concatenate the two copies of the row vector. When read with
       % linear indexing (down, then across), this effectively repeats each entry
`      % Do...while
  1L)  %   Keep only odd-indexed entries (1-based, linear indexing)
  t    %   Duplicate. This will leave a copy for the next iteration
  tS   %   Duplicate, sort
  -a   %   True if the two arrays differ in any entry
       % End (implicit). A new iteration starts if the top of the stack is true
       % Display (implicit). Prints the array that is left on the stack

2
最初にソートされたリストの破損:[1、2、3、4、5]は[
Falco

@Falcoありがとう!現在修正済み
ルイスメンドー




2

6 5バイト

Zgarbのおかげで1バイト節約

ΩΛ<Ċ2

オンラインでお試しください!

説明

ΩΛ<Ċ2
Ω         Repeat until
 Λ<         all adjacent pairs are sorted (which means the list is sorted)
   Ċ2         drop every second element from the list

これは6バイトではなく11バイトです。› echo -n "ΩΛ<(←½" | wc --bytes 11
Mike Holler


他の多くのゴルフの言語@MikeHoller、ハスクは、複数の異なる文字にアクセスするために、カスタムコードページを使用しています。github.com/barbuz/Husk/wiki/Codepage
レオ

ありがとう、今日は何かを学んだ:)
マイク・ホラー

1
Ċ2代わりに使用(←½して、バイトを保存します。
Zgarb


2

ジュリア1.0、30バイト

-x=x>sort(x) ? -x[1:2:end] : x

オンラインでお試しください!

ソートされていない場合、配列の2番目の要素をすべて取得します。


-20バイトのようなASCII演算子を使用します。また、ほとんどの場合、文字はカウントしません:| それは、ヘッダーから削除された場合ので、それは素敵なことだ
ASCIIのみの

変更しました。2バイトありがとう!
niczky12

2

C ++(gcc)、103バイト

コメントすることはできませんが、インクルードを減らし、autoを使用することでmovaticaからバージョンを改善しました。

-2バイト:ceilingcat
-2バイト:ASCIIのみ

#include<regex>
auto f(auto l){while(!std::is_sorted(l.begin(),l.end()))l.resize(l.size()/2);return l;}

オンラインでお試しください!


1
使用できない理由はl.size()/2何ですか?
ASCIIのみ

はい、それはそのように機能しません:)
peterzuger

1
どういう意味ですか?サイズのリストを返す(n+1)/2(n-1)/2、両方とも有効です。うーん....
ASCIIのみ

おっと、その感謝は
わかりません

1

VDM-SL、99バイト

f(i)==if forall x in set inds i&x=1or i(x-1)<=i(x) then i else f([i(y)|y in set inds i&y mod 2=0]) 

以前にvdmで送信したことがないため、言語固有のルールについては不明です。だから私はを受け取り、seq of int返す関数定義として提出しましたseq of int

実行する完全なプログラムは次のようになります。

functions
f:seq of int +>seq of int
f(i)==if forall x in set inds i&x=1or i(x-1)<=i(x) then i else f([i(y)|y in set inds i&y mod 2=0]) 

1

Pyth、10バイト

.W!SIHhc2Z

こちらからオンラインでお試しください。これにより、各反復で後半が削除され、切り捨てられます。前半を削除するように変更するには、切り上げて、に変更heます。

.W!SIHhc2ZQ   Q=eval(input())
              Trailing Q inferred
  !SIH        Condition function - input variable is H
   SIH          Is H invariant under sorting?
  !             Logical not
      hc2Z    Iteration function - input variable is Z
       c2Z      Split Z into 2 halves, breaking ties to the left
      h         Take the first half
.W        Q   With initial value Q, execute iteration function while condition function is true

リストの他のすべての要素を取得する方が短くなります。交換してくださいhc%。これにより、末尾のラムダ変数を削除し、ZPythに暗黙的に入力させて、合計2バイトを節約できます。
hakr14

1

C ++(gcc)139 137 116バイト

ceilingcatに-2バイト、PeterZugerに-21バイト

#include<regex>
auto f(std::vector<int>l){while(!std::is_sorted(l.begin(),l.end()))l.resize(-~l.size()/2);return l;}

ソートされるまで、ベクトルのサイズを前半に変更します。

オンラインでお試しください!


1
インポートはバイトカウントに含める必要があるため、includes を追加する必要があります
無知の

ありがとう、私はそれらを追加します。
movatica

1

K(oK)22 20バイト

解決:

{(*2 0N#x;x)x~x@<x}/

オンラインでお試しください!

ソートされるまで入力を繰り返します...ソートされない場合は、最初のn / 2項目を取ります。

{(*2 0N#x;x)x~x@<x}/ / the solution
{                 }/ / lambda that iterates
                <x   / indices that sort x ascending (<)
              x@     / apply (@) these indices back to x
            x~       / matches (~) x? returns 0 or 1
 (       ; )         / 2-item list which we index into
          x          / original input (ie if list was sorted)
       #x            / reshape (#) x
   2 0N              / as 2 rows
  *                  / take the first one      

編集:

  • ngnのおかげで-2バイト

1
(.5*#x)#x->*2 0N#x
ngn

私はやろ2 0Nうと考えましたが、もっと長くなると思いました(テストなし)、ありがとう!
ストリートスター


0

網膜、38バイト

\d+
*
/(_+),(?!\1)/+`,_+(,?)
$1
_+
$.&

オンラインでお試しください!カンマ区切りの数字を取ります。説明:

\d+
*

単項に変換します。

/(_+),(?!\1)/+`

リストがソートされていない間に繰り返します...

,_+(,?)
$1

...すべての偶数要素を削除します。

_+
$.&

10進数に変換します。


0

C(gcc)、66バイト

繰り返しごとにリストの後半を切り取ります(n/2+1長さが奇数の場合は要素)。

オンラインでお試しください!

入力のint後に、その長さが続く配列の先頭へのポインターとして受け取ります。配列の新しい長さを返すことにより出力します(インプレースでソートします)。

t(a,n,i)int*a;{l:for(i=0;i<n-1;)if(a[i]>a[++i]){n/=2;goto l;}a=n;}

ゴルフされていないバージョン:

t(a, n, i) int *a; { // take input as a pointer to an array of int, followed by its length; declare a loop variable i
  l: // jump label, will be goto'ed after each snap
  for(i = 0; i < n - 1; ) { // go through the whole array …
    if(a[i] > a[++i]) { // … if two elements are in the wrong order …
      n /= 2; // … snap off the second half …
      goto l; // … and start over
    }
  }
  a = n; // implicitly return the new length
}

提案~i+nの代わりにi<n-1
ceilingcat
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.