ブラインドランダムソート


18

ソートアルゴリズムの非常に一般的なパターンを次に示します。

def sort(l):
    while not is_sorted(l):
         choose indices i, j
         assert i < j
         if l[i] > l[j]:
             l[i], l[j] = l[j], l[i]

これらのアルゴリズムは、インデックスijがリストの状態に基づいて慎重に選択されるため、うまく機能しますl

しかし、が表示されずl、盲目的に選択しなければならなかった場合はどうなりますか?それではリストをどれくらい速くソートできますか?


あなたの課題は、の長さのみを指定して、インデックスのランダムなペアを出力する関数を書くことですl。具体的には、出力2つのインデックス、しなければならないi, j、と0 <= i < j < len(l)。関数は任意の長さのリストで機能するはずですが、長さ100のリストでスコアリングされます。

スコアは、上記のパターンに従って一様にランダムにシャッフルされたリストをソートするために必要なインデックス選択の平均数であり、インデックスは関数に従って選択されます。

長さ100の均一にランダムにシャッフルされたリストで、繰り返しのエントリなしで、1000回を超える試行のインデックス選択の平均数を取得して、提出物を採点します。

提出物が明らかに非競争的または終了しない場合、私はより少ないトライアルを実行する権利を留保します。複数の上位の提出物が計算リソースの限界でエラーの範囲内に残っている場合、さらなる計算リソースを負担できるようになるまで、以前の提出物を勝者と宣言します。


Pythonのスコアリングプログラムの例を次に示します。

import random
def is_sorted(l):
    for x in range(len(l)-1):
        if l[x] > l[x+1]:
            return False
    return True

def score(length, index_chooser):
    steps = 0
    l = list(range(length))
    random.shuffle(l)

    while not is_sorted(l):
        i, j = index_chooser(length)
        assert (i < j)
        if l[i] > l[j]:
            l[i], l[j] = l[j], l[i]
        steps += 1
    return steps

あなたの関数は、相互作用のグローバル変数と、任意の可変状態を維持するリストには影響しないかもしれないl、などあなたの関数の唯一の入力は、リストの長さでなければならないl、そしてそれは、出力範囲の整数の順序対をしなければならない[0, len(l)-1](または、あなたの言語のための適切なリストのインデックス作成)。コメントで何か許可されているかどうかお気軽にお問い合わせください。

投稿は、自由に使用できる言語で行うことができます。あなたの言語にまだ投稿されていない場合は、スコアリングハーネスを含めてください。暫定スコアを投稿することもできますが、公式スコアとともにコメントを残します。

スコアリングは、長さ100の一様にランダムにシャッフルされたリスト上のソート済みリストへの平均ステップ数です。幸運を祈ります。


2
@JoKing Indeed-あなたの提出物はディストリビューションです
-isaacg

2
可変状態を許可しないのはなぜですか?それを許可するということは、正しいアイテムが選ばれることを期待するのではなく、提出物がアルゴリズムをより良く微調整できることを意味します。
ネイサンメリル

3
@NathanMerrill可変状態が許可された場合、勝者はすでによく研究されている問題であるソーティングネットワークになります
アンデルスカセオルグ

3
@NathanMerrillその質問を投稿したい場合は、お気軽に。ただし、これはこの質問ではありません。
isaacg

3
@NathanMerrillああ、確かに。「最高の選別ネットワークを設計する」という課題は興味深い質問ですが、CS研究の世界では多くのことが研究されてきました。結果として、最良の提出物は、おそらくバッチャーのバイトニックソートなどの研究論文の実装のみで構成されます。ここで私が尋ねた質問は、私が知る限り独創的なものであり、イノベーションの余地がもっとあるはずです。
isaacg

回答:


10

Python、スコア= 4508

def half_life_3(length):
    h = int(random.uniform(1, (length / 2) ** -3 ** -0.5) ** -3 ** 0.5)
    i = random.randrange(length - h)
    return i, i + h

Half-Life 3が確認されました。

Python、スコア= 11009

def bubble(length):
    i = random.randrange(length - 1)
    return i, i + 1

どうやら、ランダム化されたバブルソートは、通常のバブルソートよりもそれほど悪いことはしません。

長さが短い場合の最適な分布

これを長さ100に拡張する方法はありませんが、とにかく見るのは面白いです。勾配降下法と多数の行列代数を使用して、小さなケース(長さ≤7)の最適な分布を計算しました。K列示す距離における各スワップの確率番目K

length=1
score=0.0000

length=2
1.0000
score=0.5000

length=3
0.5000 0.0000
0.5000
score=2.8333

length=4
0.2957 0.0368 0.0000 
0.3351 0.0368 
0.2957 
score=7.5106

length=5
0.2019 0.0396 0.0000 0.0000 
0.2279 0.0613 0.0000 
0.2279 0.0396 
0.2019 
score=14.4544

length=6
0.1499 0.0362 0.0000 0.0000 0.0000 
0.1679 0.0558 0.0082 0.0000 
0.1721 0.0558 0.0000 
0.1679 0.0362 
0.1499 
score=23.4838

length=7
0.1168 0.0300 0.0041 0.0000 0.0000 0.0000 
0.1313 0.0443 0.0156 0.0000 0.0000 
0.1355 0.0450 0.0155 0.0000 
0.1355 0.0443 0.0041 
0.1313 0.0300 
0.1168 
score=34.4257

あなたのスコア:11009
isaacg

2
半減期3の答えを少し説明してください。乱数をリ​​ストの先頭に向けるだけのポイントですか?
最大

1
長さが短い場合の最適な分布は非常に興味深いです-特にスワップ距離が大きい場合、中心に向かってバイアスをかけると便利です。
isaacg

@Max問題全体は、便利な方法で乱数にバイアスをかけることです。この方法はたまたま有用でした。h交換された要素間の距離であることに注意してください。前面または背面を表すものではありません。
アンダースカセオルグ

1
半減期スコア:10000サンプルで4508。
isaacg

7

スコア:4627

def rand_step(n):
	step_size = random.choice([1, 1, 4, 16])
	
	if step_size > n - 1:
		step_size = 1 
	
	start = random.randint(0, n - step_size - 1)
	return (start, start + step_size)

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

からの距離が一様に選択されるランダムなインデックスを出力し[1,1,4,16]ます。アイデアは、1段階のスワップと大規模なスワップを組み合わせることです。

長さ100のリストに対してこれらの値を手動で調整しましたが、おそらく最適とはほど遠いでしょう。一部のマシン検索は、おそらく、選択された距離を持つランダムペア戦略のために、距離にわたる分布を最適化できます。


1
あなたのスコア:10,000サンプルで4627。数日後にリーダーになった場合は、より多くのサンプルでもう一度実行します。
isaacg

3

スコア:28493

def x_and_y(l):
    x = random.choice(range(l))
    y = random.choice(range(l))
    while y == x and l != 1: y = random.choice(range(l))
    return sorted([x,y])

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

この溶液は、わずかのための異なる値を選択xし、yランダム範囲とソート順に戻り、そこから。私の知る限り、これは残りの値からx選択yして選択するよりもパフォーマンスが優れています。


あなたのスコア:28493
isaacg


2

Python、スコア≈5000

def exponentialDistance(n):
    epsilon = 0.25
    for dist in range(1, n):
        if random.random() < epsilon:
            break
    else:
        dist = 1
    low = random.randrange(0, n - dist)
    high = low + dist
    return low, high

多数のイプシロン値を試してみたところ、0.25が最良のようです。

スコア≈8881

def segmentedShuffle(n):
    segments = 20
    segmentLength = (n - 1) // segments + 1

    if random.random() < 0.75:
        a = b = 0
        while a == b or a >= n or b >= n:
            segment = random.randrange(segments)
            a = random.randrange(segmentLength) + segment * segmentLength
            b = random.randrange(segmentLength) + segment * segmentLength
        return sorted([a, b])

    highSegment = random.randrange(1, segments)
    return highSegment * segmentLength - 1, highSegment * segmentLength

別のアプローチ。それほど良くはなく、セグメントの数で割り切れない長さで恐ろしく死にますが、それでも構築するのは楽しいです。


あなたのスコア:指数距離:5055。セグメント化されたシャッフル:8901
isaacg

1

スコア:4583

def rand_shell(l):
    steps = [1, 3, 5, 9, 17, 33, 65, 129]
    candidates = [(left, left + step)
            for (step, nstep) in zip(steps, steps[1:])
            for left in range(0, l - step)
            for i in range(nstep // step)
    ]
    return random.choice(candidates)

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

理由はわかりません。shellsortのウィキペディアarticalにリストされているシーケンスを試しました。そして、これは最もうまくいくようです。xnorが投稿たものと同様のスコアを取得します。


あなたのスコア:10,000サンプルで4583。数日のうちにリーダーになったら、サンプルを増やしてもう一度実行します。
isaacg

また、同じディストリビューションをサンプリングする高速なプログラムを実行しているため、より多くのサンプルを取得できます。
isaacg

2
@isaacgテストのパフォーマンスを向上candidatesさせるには、グローバル変数としての関数の外に移動する必要があります。
tsh

1
おかげで、それは私がやっていたよりもはるかに高速です。
isaacg

1

Python 2、4871

import random
def index_chooser(length):
    e= random.choice([int(length/i) for i in range(4,length*3/4)])
    s =random.choice(range(length-e))
    return [s,s+e]
def score(length, index_chooser):
    steps = 0
    l = list(range(length))
    random.shuffle(l)
    while True:
        for x in range(length-1):
            if l[x] > l[x+1]:
                break
        else:
            return steps
        i, j = index_chooser(length)
        assert(i < j)
        if l[i] > l[j]:
            l[i], l[j] = l[j], l[i]
        steps += 1

print sum([score(100, index_chooser) for t in range(100)])

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


あなたのスコア:10000サンプルの4871
isaacg
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.