2015-03-01 4 views
-1

Определите функцию, которая принимает непустой список и возвращает элемент списка, выбранный случайным образом и с равной вероятностью. (Не используйте встроенную процедуру списка-ref.)Racket random list-ref function

Я застрял на этом. Я чувствую, что вам нужно будет подсчитать, сколько раз функция запускается рекурсивно и сравнивает ее со случайным числом, которое вы получаете, но я не знаю, как это сделать в BSL +. Любая помощь будет действительно велика.

+0

Какой код вы старались? –

ответ

2

Здесь является решением. Чтобы получить мяч, первый элемент списка выбирается в качестве кандидата для возврата. Затем для каждого элемента остальных элементов в списке мы произвольно выбираем, следует ли заменить кандидата.

Например: для списка с двумя элементами '(a) сначала выбирается элемент' a. Монета переворачивается: с вероятностью вместо этого возвращается 50% 'b.

Проверьте код, чтобы увидеть, как работает алгоритм для больших списков:

(define (pick-random xs) 
    (pick-random/helper (rest xs) (first xs) 1)) 

(define (pick-random/helper xs chosen k) 
    (cond 
    [(empty? xs) chosen] 
    [else ; with probability 1/(k+1) choose the first element of xs 
    (if (= (random (+ k 1)) 0) 
     (pick-random/helper (rest xs) (first xs) (+ k 1)) 
     (pick-random/helper (rest xs) chosen  (+ k 1)))])) 

Если вы хотите, чтобы Google теории, этот тип алгоритма принадлежит «алгоритмов выборки».

+0

Это работает, но я не уверен, почему. Почему вы выбрали (случайный (k + 1)) в отличие от (+ 1 (случайный (длина xs)))? – Ryan

+0

(длина xs) занимает время, пропорциональное длине списка. Если вы пробегаете список и держите длину звонка (в более коротком и коротком списке), ваш алгоритм займет время O (n + (n-1) + (n-2) + ... + 1) = O (n^2). Использование случайного на k + 1 будет O (1). – soegaard

+0

Хорошо, это имеет смысл. Я думал, что есть способ сделать это один раз и установить его как по умолчанию, а не запускать его каждый раз в рекурсии. – Ryan

0

Я беру комментарий о том, что не использую list-ref как направление, чтобы думать о проблеме рекурсивно.

Предположение о том, что «равная вероятность» не учитывает недостатки наивных программных RNG.

Обратите внимание, что мы используем []-notation в определении функции, чтобы сказать, что шаги, если не указано иное, будет иметь значение (по умолчанию) из (random (длина LST)). Это означает, что изначально он будет иметь случайное количество «шагов» в список.

#lang racket 

(define (random-element lst [steps (random (length lst))]) 
    (if (= steps 0) 
     (first lst) 
     (random-element (rest lst) 
         (sub1 steps)))) 

Поскольку шаги внутренне определены (как (шаги SUB1), вычесть один из шагов), он всегда будет иметь явное значение кроме случаев, когда функция применяется как так:

(random-element '(42 1337 128 256)) 
; 256 
+0

Это хорошо, но [] нотация не выполняется в BSL +. (случайный элемент lst) может иметь только одну переменную lst, поэтому я предполагаю, что вам понадобится вспомогательная функция, установленная на случайную вероятность, но для того, чтобы программа работала, вам нужно * оба * sub1 от вспомогательной функции и возврата (random-element (rest lst)), но программирование Racket позволяет только вернуть одно, а не два. – Ryan

+0

На самом деле вы можете вернуть несколько вещей с помощью [значений] (http://docs.racket-lang.org/reference/values.html?q=values#%28def._%28%28quote._~23 ~ 25kernel% 29._values% 29% 29). – GoNZooo