Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/heroku/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 洗牌算法之间的差异_Algorithm_Shuffle_Array Algorithms - Fatal编程技术网

Algorithm 洗牌算法之间的差异

Algorithm 洗牌算法之间的差异,algorithm,shuffle,array-algorithms,Algorithm,Shuffle,Array Algorithms,假设我们要编写一个方法来生成一副洗牌。现在让它变得非常简单,不考虑西装,所以我们有52张卡片 一种算法是: 填充一个包含52个元素的数组,第一个元素为1,第二个元素为2,依此类推 编写一个for循环,循环X次,在每次迭代中,选择两张随机卡并交换它们 X越大,随机洗牌的次数就越多 另一种算法: 像前面一样填充数组 编写一个for循环,循环26次,在每次迭代中选择两个随机数,并将这两个数放在另一个52元素数组的连续前端,该数组存储新选择的数 在每次迭代中,从原始阵列中移除添加到新阵列中的两张卡

假设我们要编写一个方法来生成一副洗牌。现在让它变得非常简单,不考虑西装,所以我们有52张卡片

一种算法是:

  • 填充一个包含52个元素的数组,第一个元素为1,第二个元素为2,依此类推
  • 编写一个for循环,循环X次,在每次迭代中,选择两张随机卡并交换它们
  • X越大,随机洗牌的次数就越多
另一种算法:

  • 像前面一样填充数组
  • 编写一个for循环,循环26次,在每次迭代中选择两个随机数,并将这两个数放在另一个52元素数组的连续前端,该数组存储新选择的数
  • 在每次迭代中,从原始阵列中移除添加到新阵列中的两张卡
我知道有更好的洗牌算法,但关于这两个,哪一个更好,为什么?

更好的是:

  • 在某个临时数组中生成52个数字
  • 使用临时阵列作为密钥,使用卡片订购阵列
  • 在C#中,它看起来

    Random r = new Random(DateTime.Now.Miliseconds);
    string [] cards = new string[52]{"1","2",.....};
    int [] temp = new int[52];
    for(int i=0;i<52;i++)
    {
        temp[i]=r.Next();
    }
    
    Array.Sort(temp,cards);
    
    Random r=new Random(DateTime.Now.毫秒);
    string[]cards=新字符串[52]{“1”、“2”、…};
    int[]temp=新int[52];
    
    对于(int i=0;i你必须定义你所说的“更好”是什么意思。第一种算法的问题是,某些元素可能永远不会改变位置。例如,如果你从来没有随机获得过较低的数字,那么第一张牌将按顺序排列

    第二种算法将使您获得更多的随机化。但是,如果您只运行一次,那么项目在其最终位置将可能是可预测的

    我要么多次运行算法2,要么像洗真牌一样洗牌

    1: Split the deck into two arrays of 26
    2: Take the top card from one of the arrays at random and put it into a new array of size 52
    3: Keep doing this until one array is empty, put the remaining cards of the other array into the size 52 array
    4: Repeat
    

    这将为您带来一个很好的随机化

    第二个算法似乎是一个由两个实现展开的算法。这种随机洗牌的特性是在所有可能的结果中选择一个均匀分布。大多数人会称之为“公平”或“完美”洗牌。如果您的随机数生成器提供无偏结果,则无需为额外的随机性重复该操作

    第一个算法可能渐近地接近我不知道什么样的分布。我会出于各种原因避免它。主要是因为我不知道X需要多大才能产生一个好的洗牌,但我确信它超过52。除了simula之外,我想不出这个算法有什么好的应用洗牌不充分


    第一种算法正在运行,这在某些情况下是有益的,但如果您想这样做,您可以修改第二种算法,使其以类似的方式运行。

    第一种算法产生高度偏差分布,因为它可能会使一些卡处于初始位置,并容易出现“双交换”问题(交换相同的两张卡两次,导致初始卡状态)

    第二种算法是的展开版本,但有一个小例外:它不再是线性的,因为从列表中删除项本身就是线性操作,并且在每次迭代中都会执行,因此总体算法复杂度为O(n^2)

    有效的版本如下:

    在伪代码中(因为您没有提到选择的语言)

    和python实现,以防万一:)


    “更好”根据什么标准?这不取决于第一种算法中
    X
    的值吗?第一种算法能够生成一个更随机的集,但第二种算法在运行时间和空间复杂度方面是固定的。如果X是26?或52?在这两种情况下,X与第二种算法相比如何?您仍然需要定义criteria:你说的“更好”是什么意思?“更好”应该更随机像下面提到的sh1一样,第二种算法是Fisher-Yates算法。只要他的代码忽略在一次迭代中两个随机数相同的实例(我没有写出完整的数学公式,但我认为概率仍然是一个均匀分布的随机数)。我看不出第二个算法如何能够执行双重交换。它将值从一个数组移动到另一个数组。这看起来像是一个模拟。正如注释上的Wikipedia文章所述,这种方法是O(n logn)及时,而Durstenfeld对Fisher-Yates的实施时间为O(n)。
    for i from n − 1 downto 1 do
       j ← random integer with 0 ≤ j ≤ i
       exchange a[j] and a[i]
    
    import random
    n = 52
    arr = [i for i in range(1,n+1)]
    
    for i in range(n-1, 1, -1):
        elem_to_swap = random.randint(0, i)
        arr[elem_to_swap], arr[i] = arr[i], arr[elem_to_swap]