盲目随机排序


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]

这些算法,因为指数运行良好i,并j都经过精心挑选,根据该列表的状态l

但是,如果我们看不到l,而不得不盲目选择,该怎么办?那我们可以多快排序列表呢?


您面临的挑战是编写一个仅给出给定长度的输出随机索引对的函数l。具体来说,您必须输出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等。您函数的唯一输入必须是list的长度l,并且必须输出该范围内的有序整数对[0, len(l)-1](或适用于您语言的整数)。列表索引)。随意询问评论中是否允许某些内容。

提交内容可以使用任何免费使用的语言。如果尚未发布使用您的语言的评分工具,请添加评分工具。您可以发布一个临时分数,但我会发表官方分数的评论。

计分是在长度为100的均匀随机混排的列表上排序列表的平均步骤数。祝您好运。


2
@JoKing确实-您提交的内容是分发的
-isaacg,

2
你为什么不允许可变状态?允许它意味着提交者可以更好地微调其算法,而不是希望选择正确的项目。
内森·美林

3
@NathanMerrill如果允许可变状态,则获胜者将只是一个已经经过充分研究的问题的分类网络
Anders Kaseorg '18

3
@NathanMerrill如果您想发布该问题,请随意。但是,这不是这个问题。
isaacg

3
@NathanMerrill哦,当然。“设计最佳的分类网络”这一挑战是一个有趣的问题,但在CS研究领域已经进行了很多研究。结果,最好的论文可能只是研究论文的实现,例如Batcher的bitonic sort。就我所知,我在这里提出的问题是原创的,因此应该有更多的创新空间。
isaacg

Answers:


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

半条命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

3

Python,得分:39525

def get_indices(l):
    x = random.choice(range(l-1))
    y = random.choice(range(x+1,l))
    return [x,y]

[0,l1)x
x[x+1,l)y

在线尝试。


您的分数:39525
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

尝试了一堆epsilon值,最好是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列出的序列。而这似乎是最好的。与xnor发布的得分相似。


您的分数:10,000个样本中的4583。如果几天之后您成为领导者,我将使用更多示例再次运行它。
isaacg

另外,我正在运行一个速度更快的程序,该程序对相同的分布进行采样,因此我可以获得更多的采样。
isaacg

2
@isaacg为了获得更好的测试性能,将candidates函数作为全局变量移出应该可行。
tsh

1
谢谢,这比我正在做的要快得多。
isaacg

1

蟒蛇 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
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.