在Python词典中,((j * 5)+1)%2 ** i如何遍历所有2 ** i

时间:2016-05-22 19:43:42

标签: python algorithm dictionary linear-probing

我正在研究python如何实现字典。 python字典实现中的一个等式涉及使用等式

的空字典槽的伪随机探测
j = ((j*5) + 1) % 2**i

解释为here

我已经阅读了这个问题How are Python's Built In Dictionaries Implemented,并且基本上了解了字典是如何实现的。

我不明白为什么/如何使用等式:

j = ((j*5) + 1) % 2**i   

循环遍历2**i的所有余数。例如,如果i = 3的总起始大小为8. j,则会在整个周期内完成:

0
1
6
7
4
5
2
3
0

如果起始大小为16,它将经历循环:

0 1 6 15 12 13 2 11 8 9 14 7 4 5 10 3 0

这对于探测字典中的所有插槽非常有用。 但为什么会有效呢?为什么j = ((j*5)+1)有效但j = ((j*6)+1)j = ((j*3)+1)这两种情况都会陷入较小的周期。

我希望能够更直观地了解这一点,而不是方程式正常运作以及它们使用它的原因

1 个答案:

答案 0 :(得分:13)

与Jasper暗示的伪随机数生成器使用的原理相同,即linear congruential generators。线性同余生成器是遵循关系X_(n+1) = (a * X_n + c) mod m的序列。来自维基页面,

  

一般LCG的周期最多为m,而某些因子的选择a远小于此。当且仅当以下情况时,LCG将为所有种子值设置一个完整的期限:

     
      
  1. mc相对较为优秀。
  2.   
  3. a - 1可被m的所有素数因子整除。
  4.   如果a - 1可被m整除,则
  5. 4可被4整除。
  6.   

很明显,5是满足这些要求的最小a,即

  1. 2 ^ i和1是相对素数。
  2. 4可以被2整除。
  3. 4可以被4整除。
  4. 同样有趣的是,5并不是满足这些条件的唯一数字。 9也会奏效。将m设为16,使用j=(9*j+1)%16得出

    0 1 10 11 4 5 14 15 8 9 2 3 12 13 6 7
    

    这三个条件的证据可以在第5页的the original Hull-Dobell paper中找到,还有一些其他可能感兴趣的PRNG相关定理。