随机置换非重复序列

时间:2016-05-30 15:05:11

标签: c++ r algorithm

一年前,我在R论坛中询问了a question关于如何置换序列1000次但从不允许重复元素的问题。现在仍然如此,R中的任何解决方案对我的需求来说都太慢了。

问题是这样的:

对于每个字母都是单独元素的序列,例如

"...IDPGCGDCIDPGCGCDIDPGCGDCPGCIDPFJAIAHAHAHABAHAHABKPGCPGCGCECDGCPGCGCIDIPFCPGEPAJIAEPGCECJIPGCGPGCGCGADPDJDPGCPCPGCDIPEPGCJAJMAHZABAHAHAHABHAHBKRZALOBKAHABKLAHAHAHABKLKLAKLBKABABLAHAHABKBKLOKIABKLAHAHABKLABKALKABKLKAHBAKLABKBAHABLALKABABJLKAKLKHABKCRAHAKLKAKLABKLKLBKAHAKLKECECGDCGECGEDGCDGDGECECEGDCACACAHABABCDCHAHBKCQGCGCQCQGCQCGCACACBKCDCAHACQGCPGCDACAPCQAHAHBKACHAHAHBABCGCGCAHAHAMHMABAHAKLABKCPCFCABCQCQGCGCABHAHANBKQAHAHANANABKLABAKLPCGCGCPCAHABAHAHAHAHANBKALCQCGCECAHABANAHBKAKBKAHABAHBKALBHAHABKLKCPCECALCGCAKPHBAHAHAHAHAHAHABAHAHBKAMJABAHBAHAHBKALKABKPCQBANAHANHABKHBALAHALAHANBANBHABKAHANHAHABKAHAHAHAHAMANIAHABANHABABKBKLHLKLBKLKBKBKBALAHAKLBKLBHKBABHAMABKZAHAHABLKAHABAKABKOKHAKAHAHBKAHAHAHABKLHAHBKAHABKLAHAHABKAIAIAHABKLBAIAIKLKLAHAH..."

我需要对这个序列进行10000次置换(随机混洗)。原始序列永远不会有任何重复的元素。随机采样序列需要具有与原始序列相同比例的元素,但也没有重复元素。序列长度可达50,000个元素。每个元素的总数看起来像这样:

 A    B    C    D    E    F    G    H    I    J    K    L    M    N    O    P    Q    R    Z 
6537 3156 1736  198  445  138 1129 3849  818  287 2339 1190  275 1035  222  484  242  338   59 

我尝试使用R来解决此问题。尝试的一切都太慢了,也不是很擅长找到不重复的元素。我不了解C++那么好,但有兴趣尝试通过Rcpp来使用它来获得有效的解决方案。

我认为这将是一个有趣的问题,并且在允许的情况下会为它添加赏金。

长序列示例为available here

1 个答案:

答案 0 :(得分:1)

一种方法是通过在随机位置添加新元素来构建序列中的一个元素,而不是按顺序选择每个元素。

使用以下算法:

  • 在没有非重复约束的情况下随机置换列表,以获得插入元素的随机顺序。请拨打此列表a
  • 以空列表b开头。
  • 对于e中的每个元素a
    • attempts设为零
    • 虽然attempts< max_attempts
      • p0选择一个随机位置b.size(),其中0表示第一个元素,b.size()表示最后一个元素,并检查是否可能在此位置插入e而不会导致重复。如果可能,请将e插入位置b的{​​{1}},否则请增加p然后重试
    • 如果在attempts次尝试中未插入任何元素,请从头开始重新开始

我无法证明这会产生均匀分布,但我认为它将不受任何偏差的影响,这些偏差将某些元素聚集到序列的开始或结束,其中使用顺序方法可以更加确定可能性。它可能会失败(例如,如果要为插入的第一个和第二个元素选择相同的元素),但这是便宜的,而max_attempts很短并且变得越来越不可能(假设频率分布类似于你告诉我们的一个)。 OTOH,你很容易想出会导致它失败的病态分布(例如10000 As和10000 Bs,没有其他字母)。

这可以使用列表b的stl列表和引用列表中每个元素的迭代器数组在C ++中以线性时间实现。添加新元素时,将指向该元素的迭代器添加到数组的末尾。要在列表中选择随机位置,请从数组中随机选择一个迭代器。