2011-03-19 32 views
5

我很抱歉打擾你我知道this question已被問了很多,但從來沒有與Ada ......我想知道是否有在Ada標準庫中的一種方法生成一個唯一的隨機數列表(你永遠不會選擇兩倍相同的數字)在O(n) 在某種程度上Ada中的Knuth-Fisher-Yates算法的實現?Ada區間中唯一隨機數的列表

+2

我不知道已經有這個任何庫,但中K-F-Y算法看起來很容易實現。 – 2011-03-19 13:06:50

回答

5

有一個實施Fisher–Yates洗牌here的討論。基本上,您需要在每次迭代中使用不同範圍的Discrete_Random,如here所示; Float_Random是另一種選擇,如A.5.2(50), Note 16中所述。如果偏差不重要,這個example可能就足夠了。

在任何情況下,洗牌O(n)的,但選擇可以O(1)

附錄:複製創建該集取決於implementation。例如,Containers.Hashed_Sets, A.18.8(88/2)Containers.Ordered_Sets, A.18.9(116/2)

+0

Isnt處理/生成數字O(n)呢?畢竟需要檢查數字是否唯一? (在數組上重複線性搜索) – NWS 2011-03-21 09:24:30

+0

@NWS:好點。我不小心使用了_dealing_這個詞;我的意思是選擇。 IIUC的獨特性與初始設定一致,複雜程度取決於實施情況。 – trashgod 2011-03-21 11:23:25

+0

回到問題,如果我們生成並放入排序列表中,_Before_我們洗牌的數字可能會減少一點:)。 – NWS 2011-03-21 12:03:32

2

既然你想: 一)隨機數從0到1000 和 b)該數字不是根據你提供的鏈接重複 ,你可以這樣做比較容易。

只需使用值的範圍填充數組,然後在隨機選擇的元素上執行一些交換;這保證了這兩個要求都得到了保證。

+0

+1這是直接的方法,但選擇「某些交換次數」可能是偏差的來源。 – trashgod 2011-03-20 15:26:40

+0

這是真的。但是,您可以通過使用循環/範圍等於陣列範圍(可能使用MOD)的RNG並將該索引與所有元素的「current」元素進行交換,從而減少這一點。 那麼偏見會來自的主要原因是RNG本身。 – Shark8 2011-03-24 01:51:28

+0

在[引用的示例](http://home.roadrunner.com/~jbmatthews/war.html)中,[bias](http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle# Implementation_errors)取決於「在每次迭代中從整個有效數組索引的整個範圍中選擇」j「。可悲的是,它遠遠超出了PRNG的偏見。 – trashgod 2011-03-24 03:48:09

1

我冒昧地編碼它。 您需要使用Ada.Numerics.Discrete_Random。

Generic 
     Low, High : Integer; 
    Package Initialization is 
     SubType Element is Integer Range Low..High; 
     Function Incrementor Return Element; 
     Type Element_Array is Array(Element) of Element; 

     Values : Element_Array; 
     Procedure Print; 
    End Initialization; 

    Package Body Initialization is 
     Count : Element := Element'Last; 

     Function Incrementor Return Element is 
     begin 
     Return Result : Element:= Count do 
      Null; 
      Count:= Element'Pred(Result); 
     Exception 
       When Constraint_Error => Count:= Element'Last; 
     End Return; 
     end Incrementor; 

     Procedure Swap(Index_1, Index_2 : In Integer) is 
     Temp : Constant Element:= Values(Integer(Index_1)); 
     begin 
     Values(Integer(Index_1)):= Values(Integer(Index_2)); 
     Values(Integer(Index_2)):= Temp; 
     end Swap; 

     Procedure Print is 
     begin 
     Put_Line("Length: " & Values'Length'Img); 
     Put("("); 
     For Index in Values'First..Integer'Pred(Values'Last) loop 
      Put(Values(Index)'Img & ','); 
     end loop; 
     Put(Values(Values'Last)'Img); 
     Put_Line(")"); 
     end Print; 


    Begin 
     Shuffle: 
     Declare 
     Package Random_Element is New 
     Ada.Numerics.Discrete_Random(Element); 
     Number : Random_Element.Generator; 
     Use Random_Element; 
     Begin 
     Values:= Element_Array'(Others => Incrementor); 
     Reset(Number); 
     For Index in Element'Range loop 
      Swap(Integer(Index), Integer(Random(Number))); 
     end loop; 
     End Shuffle; 
    End Initialization; 

你還可以用像測試一下:

Test: 
    Declare 
     Package Q is new 
    Initialization(Low => 0, High => 1000); 
    Begin 
     Q.Print; 
    End Test; 
+0

因爲它選擇「在每次迭代有效數組索引的整個範圍,」我恐怕這有相同的[偏見](http://en.wikipedia.org/wiki/費舍爾%E2%80%93Yates_shuffle#Implementation_errors)。 – trashgod 2011-03-24 03:53:15

+0

但總而言之,選擇一個無效索引是錯誤的。 – Shark8 2011-03-27 22:11:59

+0

選擇不在範圍之外;它只是比其他人更容易洗牌。您必須在每次迭代中從_remaining_元素中進行選擇。這[文章](http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#Implementation_errors)終於幫助我看到了。 – trashgod 2011-03-28 02:35:47