Algorithm 均匀分布的随机变长编码数

Algorithm 均匀分布的随机变长编码数,algorithm,random,prng,Algorithm,Random,Prng,假设我使用可变长度编码呈现数据,当我可以检索数据时,解析某个虚拟b树,并在到达该项时停止(类似于Huffman编码)。项目数量未知(在最佳情况下,只有上限已知)。是否有生成均匀分布数字的算法?问题是,在这种情况下,基于硬币的算法将给出不一致的结果,例如,如果有一个数字编码为101,而有一个数字编码为10010101,那么后者与前者相比将很少出现 更新:换句话说,当每个元素都可以用任意数量的位寻址时,我有一组最大N个元素(但可能更少)(并且根据信息理论,如果一个元素被编码为101,那么其他元素就不

假设我使用可变长度编码呈现数据,当我可以检索数据时,解析某个虚拟b树,并在到达该项时停止(类似于Huffman编码)。项目数量未知(在最佳情况下,只有上限已知)。是否有生成均匀分布数字的算法?问题是,在这种情况下,基于硬币的算法将给出不一致的结果,例如,如果有一个数字编码为101,而有一个数字编码为10010101,那么后者与前者相比将很少出现

更新:换句话说,当每个元素都可以用任意数量的位寻址时,我有一组最大N个元素(但可能更少)(并且根据信息理论,如果一个元素被编码为101,那么其他元素就不能用相同的前缀编码)。所以它更像是B-树,当我根据一点向左或向右移动时,在某个时刻我到达数据项。我想用这种技术得到一个随机数序列,但它们的分布应该是一致的(上面的例子说明了为什么随机选择左-右不起作用,数字101和10010101)

谢谢


Max

我能想到三种基本方法,其中一种涉及频繁调整,另一种涉及保留额外信息。我认为做这些事情中的一件或另一件是不可避免的。我将从一个额外的信息开始:

在每个节点中,存储一个数字
count
,该数字表示其子节点的数量。对于每个节点,您需要有一个介于1和
count
之间的数字,以便该节点通过将其与左侧子节点的计数进行比较来告诉您是向左还是向右。以下是算法:

n := random integer between 1 and root.count
node := route
while node.count != 1
     if n <= node.left.count
          node = node.left
     else
          node = node.right
          n = n - node.left.count
当然,这方面的时间分析非常可怕。基本上,while循环将平均运行(2^(B+1)-1)/N次。所以,在最坏的情况下,O((2^N)/N)是可怕的。在最好的情况下,B的顺序是log(N),因此它大约是O(1),但这要求树相当平衡,而它可能不是。不过,如果您真的不需要额外的空间,这个方法可以做到这一点

我真的不认为在不存储一些信息的情况下,您可以比上一种方法做得更好。这听起来很吸引人,能够遍历树,在运行时做出随机决策,但如果不存储有关结构的额外信息,您将无法做到这一点。每次做出分支决策时,左侧可能只有一个节点,右侧可能有一百万个节点,或者左侧可能有一百万个节点,右侧可能只有一个节点。因为这两种情况都是可能的,你不知道哪种情况是可能的,所以根本没有办法在双方之间做出随机的决定。显然,50-50不起作用,任何其他选择都会有类似的问题


因此,如果您不需要额外的空间,第二种方法可以工作,但速度较慢。如果您不介意添加一些额外的空间,那么第一种方法将有效且快速。正如我前面所说的,如果你不打算改变树,你会选择很多随机节点,那么咬紧牙关,只需遍历树,将所有叶节点粘贴在一个自增长的数组或向量中,然后从中进行选择。

这个问题不太清楚。要从哪个集合中选择随机元素?我认为你需要提供更多的细节才能得到答案。如果你知道整个树的结构,那就很容易了。也就是说,如果您知道根在某个节点上的每个子树(元素数)的大小,则可以使用权重进行统一采样。但是,您声明项目的数量未知。也许您可以使用其他一些“足够好”的度量来进行这种加权采样?子树的大小可能非常大,或者换句话说,完全遍历可能会很昂贵,这是事先未知的。我可以承受一些拒绝,所以当一些随机遍历将导致在某些条件下重新启动时,我已经完成了您尝试执行的操作,但是了解了树结构。您可以在构建树时保留子树的计数。看看为什么你不能在你的集合中选取一个随机元素并对其进行编码?Keith,谢谢你的详细回复和两种方法。第二个看起来确实很有希望。这花了一些时间去理解,但最终它是直截了当的。我将把这个应用到我的内部逻辑中,也许标记为一个解决方案。基思,经过一些思考,我重新制定了你的方法。我可以像往常一样随机解析这棵树,但在最后阶段,我可以看到上界还有多少位,并且根据从这个范围中提取的随机数,我决定接受我的轨迹还是重新开始。感谢您提供了很好的解决方案,即使我不确定它是否能达到我期望的性能,但无论如何,它总比什么都没有好
function num_to_binary_list(n,digits) =
  if digits == 0 return ()
  if n mod 2 == 0 return 0 :: num_to_digits(n/2,digits-1)
  else return 1 :: num_to_digits((n-1)/2,digits-1)

function binary_list_to_node_label_list(l) =
  if l.head() == 0 return l.tail()
  else return binary_list_to_node_label_list(l.tail())

function check_node_label_list_against_tree(str,node) =
  if node == null return false,null
  if str.isEmpty() 
    if node.isLeaf() return true,node
    else return false,null
  if str.head() == 0 return check_node_label_list_against_tree(str.tail(),node.left)
  else check_node_label_list_against_tree(str.tail,node.right)

function generate_random_node tree b =
  found := false
  while (not found)
    x := random(0,2**(b+1)-2) // We're assuming that this random selects inclusively
    node_label := binary_list_to_node_label(num_to_binary_list(x,b+1))
    found,node := check_node_label_list_against_tree(node_label,tree)
  return node