Сліпий випадковий сорт


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.

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

Я оціню подання, взявши середню кількість варіантів вибору індексу понад 1000 випробувань у рівномірно випадково перетасованому списку довжиною 100 без повторних записів.

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


Ось приклад програми підрахунку балів на 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 Дійсно - ваше подання є розповсюдженням
isaacg

2
Чому ви не дозволяєте змінювати стан? Якщо це дозволити, це означає, що подання можуть краще налаштувати свої алгоритми, на відміну від сподівання, що правильні елементи будуть обрані.
Натан Меррілл

3
@NathanMerrill Якби дозволено змінити стан, переможцем буде просто сортувальна мережа, яка вже добре вивчена проблема.
Андерс Касеорг

3
@NathanMerrill Якщо ви хочете опублікувати це питання, не соромтеся. Однак це не питання.
isaacg

3
@NathanMerrill О, звичайно. Завдання «Створити найкращу сортувальну мережу», хоча цікаве питання, було вивчено багато в світі досліджень CS. Як результат, найкращі матеріали, ймовірно, полягають у виконанні науково-дослідних робіт, таких як бітонічний тип Батчера. Питання, яке я тут задав, є оригінальним, наскільки я знаю, і тому повинно бути більше місця для інновацій.
isaacg

Відповіді:


10

Пітон, оцінка = 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 підтверджено.

Пітон, оцінка = 11009

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

Мабуть, рандомізований сортування міхура не робить все набагато гірше, ніж звичайний міхур.

Оптимальні розподіли для невеликої довжини

Ні в якому разі це не може бути подовжено до довжини 100, але все одно цікаво подивитися. Я обчислював оптимальні розподіли для невеликих випадків (довжина ≤ 7), використовуючи градієнтне спускання та багато матричної алгебри. До - го стовпця показує ймовірність кожного підкачки на відстані до .

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
Ваш показник напівжиття: 4508 на 10000 проб.
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]. Ідея полягає у поєднанні одномоментних свопів із свопами на великих масштабах.

Я вручив ці значення для списків довжиною 100, і вони, ймовірно, далеко не оптимальні. Деякий машинний пошук, ймовірно, може оптимізувати розподіл по відстанях для стратегії випадкової пари-вибраного відстані.


1
Ваша оцінка: 4627 на 10000 зразків. Я знов проберу його з більшою кількістю зразків, якщо через кілька днів ви будете серед лідерів.
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


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)

Спробуйте в Інтернеті!

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


Ваша оцінка: 4583 на 10000 зразків. Я знов проберу його ще зразками, якщо через кілька днів ви будете серед лідерів
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)])

Спробуйте в Інтернеті!


Ваша оцінка: 4871 на 10000 зразків
isaacg
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.