可扩展加权洗牌算法选型:满足权重调整一致性需求
场景设定
集合中的条目具备可由管理员设置的权重属性。权重更高的条目在向普通访客展示的随机列表中更有可能处于靠前位置。每个条目无论权重高低,都有机会(哪怕概率极低)出现在列表的任意位置。
需要何种算法才能确保:无论集合规模如何,调整条目的权重都能得到一致的效果?
我深知自己能力有限,但不愿默认基础算法(尝试方案1)所隐含的概率结构是合理的。我的思路是否存在误区?方法是否有缺陷?结论是否可靠?
成功判定参数
- 权重越高,越有可能处于靠前位置。
- 每个条目至少有极低概率出现在列表的任意位置。(这排除了“等级分类”或“排名配额”类方案,此类方案可能导致低等级条目永不出现在列表中,或单个高等级条目必处于前列。)
- **集合规模不应影响不同权重之间的相对作用效果。**集合规模当然会影响单个条目的整体概率。具体而言,在集合
[a:2, b:2, c:2, d:2, e:3, f:3]中,b与e的概率差异,应与集合[a:2, b:2, c:3, d:3, e:3, f:3](长度相同、权重总和不同)以及集合[a:1, b:2, e:3, f:6](长度不同、权重总和相同)中的差异一致。 - **仅权重的差值起作用,而非权重的绝对数值。**在集合
[3,3,17,17]中,将最后一个条目权重提升至19的效果,应与将第一个条目权重提升至5的效果相同;集合[1,3]的表现应与[3,5]相似。这样用户无需了解整个集合即可高效调整权重。
尝试方案
1: 线性权重(标准方法)
function linear_ratio($weight_set, $weight) { $sum = 0; foreach ($weight_set as $item) $sum += $item; return $weight / $sum; }
- [通过] 权重越高,越有可能处于靠前位置。
- [通过] 权重最高的条目仍有机会处于末尾位置。
- [通过] 无论集合规模多大,权重3与3+2的相对概率始终一致。
- [不通过] 3→5是167%的变化,而17→19仅为112%的变化。
2: 指数权重
function exponential_ratio($weight_set, $weight) { $sum = 0; foreach ($weight_set as $item) $sum += (2 ** $item); $weight = 2 ** $weight; return $weight / $sum; }
该方案解决了第4个参数的问题,但底数(2)是任意设定的,却会带来指数级的影响。
- [通过] 权重越高,越有可能处于靠前位置。
- [通过] 权重最高的条目仍有机会处于末尾位置。
- [通过] 无论集合规模多大,权重3与3+2的相对概率始终一致。
- [通过] 3→5是400%的变化,17→19同样是400%的变化。
3: 以集合规模为参数
function based_exponential_ratio($weight_set, $weight) { $set_size = count($weight_set); $sum = 0; foreach ($weight_set as $item) $sum += $set_size ** $item; $weight = $set_size ** $item; return $weight / $sum; }
这只是将一个问题(任意底数)替换为另一个问题。对于包含100个条目的集合,新增1个条目本不应产生太大影响,但集合规模+1会使权重的效果呈指数级增长(从而降低随机性)。
4: 以集合规模的数量级为参数
我在意的是在100个条目的集合中新增500个条目这种情况。那当集合规模变化一个数量级时,是否需要关注?“取集合规模的自然对数,再将其提升至权重次方”?我的思维模型只能推进到这一步,但我认为对数的指数运算可能会适得其反。
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

