Sắp xếp ngẫu nhiên mù


18

Đây là một mẫu khá phổ biến để sắp xếp các thuật toán:

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]

Các thuật toán này hoạt động tốt vì các chỉ số ijđược chọn cẩn thận, dựa trên trạng thái của danh sách l.

Tuy nhiên, điều gì sẽ xảy ra nếu chúng ta không thể nhìn thấy lvà phải chọn một cách mù quáng? Làm thế nào nhanh chóng chúng ta có thể sắp xếp danh sách sau đó?


Thử thách của bạn là viết một hàm tạo ra một cặp chỉ số ngẫu nhiên, chỉ với độ dài là l. Cụ thể, bạn phải xuất hai chỉ số i, j, với 0 <= i < j < len(l). Chức năng của bạn sẽ hoạt động trên bất kỳ độ dài nào của danh sách, nhưng nó sẽ được ghi vào danh sách có độ dài 100.

Điểm của bạn là số lựa chọn chỉ số trung bình cần thiết để sắp xếp danh sách xáo trộn ngẫu nhiên thống nhất theo mẫu trên, trong đó các chỉ số được chọn theo chức năng của bạn.

Tôi sẽ chấm điểm các bài nộp, lấy số lượng lựa chọn chỉ số trung bình trên 1000 thử nghiệm trên một danh sách được xáo trộn ngẫu nhiên thống nhất có độ dài 100 mà không có mục lặp lại.

Tôi bảo lưu quyền chạy thử nghiệm ít hơn nếu bài nộp rõ ràng không cạnh tranh hoặc không chấm dứt và tôi sẽ chạy nhiều thử nghiệm hơn để phân biệt các đối thủ cạnh tranh hàng đầu để tìm một người chiến thắng. Nếu nhiều lần gửi hàng đầu vẫn nằm trong phạm vi lỗi ở giới hạn tài nguyên tính toán của tôi, tôi sẽ tuyên bố gửi trước đó cho người chiến thắng, cho đến khi có thể mang lại các tài nguyên tính toán tiếp theo.


Đây là một chương trình tính điểm ví dụ, bằng 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

Hàm của bạn có thể không duy trì bất kỳ trạng thái có thể thay đổi nào, tương tác với các biến toàn cục, ảnh hưởng đến danh sách l, v.v. Đầu vào duy nhất của hàm phải là độ dài của danh sách lvà phải xuất ra một cặp số nguyên theo thứ tự trong phạm vi [0, len(l)-1](hoặc phù hợp với ngôn ngữ của bạn liệt kê danh sách). Hãy hỏi xem có gì được cho phép trong các bình luận không.

Đệ trình có thể bằng bất kỳ ngôn ngữ sử dụng miễn phí nào. Vui lòng bao gồm khai thác điểm nếu chưa được đăng cho ngôn ngữ của bạn. Bạn có thể đăng một số điểm tạm thời, nhưng tôi sẽ để lại nhận xét với số điểm chính thức.

Ghi điểm là số bước trung bình của một danh sách được sắp xếp trên danh sách được xáo trộn ngẫu nhiên có độ dài 100. Chúc may mắn.


2
@JoKing Thật vậy - bài đăng của bạn là một bản phân phối
isaacg

2
Tại sao bạn không cho phép trạng thái đột biến? Cho phép điều đó có nghĩa là việc đệ trình có thể tinh chỉnh thuật toán của họ tốt hơn, trái với hy vọng rằng các mục phù hợp sẽ được chọn.
Nathan Merrill

3
@NathanMerrill Nếu trạng thái có thể thay đổi được cho phép, người chiến thắng sẽ chỉ là một mạng sắp xếp vốn đã là một vấn đề được nghiên cứu kỹ lưỡng.
Anders Kaseorg

3
@NathanMerrill Nếu bạn muốn đăng câu hỏi đó, cứ thoải mái. Đó không phải là câu hỏi này, tuy nhiên.
isaacg

3
@NathanMerrill Ồ, chắc chắn rồi. Thử thách "Thiết kế mạng phân loại tốt nhất", trong khi một câu hỏi thú vị, đã được nghiên cứu rất nhiều trong thế giới nghiên cứu CS. Do đó, các bài nộp tốt nhất có lẽ chỉ bao gồm việc triển khai các tài liệu nghiên cứu, chẳng hạn như loại bitonic của Batcher. Câu hỏi tôi đã hỏi ở đây là nguyên bản theo như tôi biết, và vì vậy nên có nhiều chỗ cho sự đổi mới.
isaacg

Câu trả lời:


10

Con trăn, điểm = 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 xác nhận.

Con trăn, điểm = 11009

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

Rõ ràng một loại bong bóng ngẫu nhiên không làm tất cả tồi tệ hơn nhiều so với một loại bong bóng bình thường.

Phân phối tối ưu cho chiều dài nhỏ

Không có cách nào điều này có thể được mở rộng đến chiều dài 100, nhưng thật thú vị khi xem xét bằng mọi cách. Tôi đã tính toán các phân phối tối ưu cho các trường hợp nhỏ (độ dài 7) bằng cách sử dụng độ dốc và nhiều đại số ma trận. Các k thứ show cột xác suất của mỗi hoán đổi ở khoảng cách 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

Điểm của bạn:
11009

2
Bạn có thể giải thích nửa đời 3 của bạn trả lời một chút không? Là điểm chỉ để thiên vị số ngẫu nhiên về phía trước của danh sách?
Tối đa

1
Các bản phân phối tối ưu cho chiều dài nhỏ rất thú vị - Tôi nhận thấy rằng xu hướng về trung tâm là hữu ích, đặc biệt là cho khoảng cách trao đổi lớn hơn.
isaacg

@Max Toàn bộ vấn đề là về xu hướng các số ngẫu nhiên theo những cách hữu ích; cách này đã xảy ra là hữu ích. Lưu ý rằng đó hlà khoảng cách giữa các yếu tố hoán đổi; nó không đại diện cho mặt trước hoặc mặt sau.
Anders Kaseorg

1
Điểm nửa đời của bạn: 4508 trên 10000 mẫu.
isaacg

7

Điểm: 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)

Hãy thử trực tuyến!

Đầu ra các chỉ số ngẫu nhiên có khoảng cách xa nhau được chọn thống nhất từ [1,1,4,16]. Ý tưởng là có sự kết hợp của các giao dịch hoán đổi 1 bước với các giao dịch hoán đổi ở quy mô lớn hơn.

Tôi đã điều chỉnh bằng tay các giá trị này cho các danh sách có độ dài 100 và chúng có thể không còn tối ưu. Một số tìm kiếm máy có thể có thể tối ưu hóa phân phối theo khoảng cách cho chiến lược khoảng cách cặp ngẫu nhiên với lựa chọn khoảng cách.


1
Điểm của bạn: 4627 trên 10.000 mẫu. Tôi sẽ chạy lại với nhiều mẫu hơn nếu bạn nằm trong số các nhà lãnh đạo sau một vài ngày.
isaacg

3

Điểm: 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])

Hãy thử trực tuyến!

Giải pháp này chỉ chọn các giá trị riêng biệt cho xyngẫu nhiên từ phạm vi và trả về chúng theo thứ tự được sắp xếp. Theo như tôi có thể nói, điều này thực hiện tốt hơn so với việc chọn xsau đó chọn ytừ các giá trị còn lại.


Điểm của bạn: 28493
isaacg


2

Con trăn, điểm ≈ 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

Đã thử với một loạt các giá trị epsilon, 0,25 dường như là tốt nhất.

Điểm 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

Một cách tiếp cận khác. Không tốt bằng, và nó chết khủng khiếp với chiều dài không chia hết cho số lượng phân khúc, nhưng vẫn vui vẻ để xây dựng.


Điểm số của bạn: Khoảng cách theo cấp số nhân: 5055. Phân đoạn ngẫu nhiên: 8901
isaacg

1

Điểm: 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)

Hãy thử trực tuyến!

Tôi không biết tại sao. Tôi vừa thử các trình tự được liệt kê trên wikipedia artical cho shellsort . Và cái này có vẻ hoạt động tốt nhất. Nó nhận được số điểm tương tự với một xnor được đăng .


Điểm của bạn: 4583 trên 10.000 mẫu. Tôi sẽ chạy lại nó với nhiều mẫu hơn nếu bạn nằm trong số các nhà lãnh đạo trong một vài ngày.
isaacg

Ngoài ra, tôi đang chạy một chương trình nhanh hơn có cùng phân phối, vì vậy tôi có thể nhận được nhiều mẫu hơn.
isaacg

2
@isaacg Để có hiệu suất thử nghiệm tốt hơn, việc chuyển candidatesra khỏi chức năng như một biến toàn cục sẽ hoạt động.
tsh

1
Cảm ơn, điều đó nhanh hơn nhiều so với những gì tôi đang làm.
isaacg

1

Con trăn 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)])

Hãy thử trực tuyến!


Điểm của bạn: 4871 trên 10000 mẫu
isaacg
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.