假设有如下一个数组 

   
   
   
   
  1. $list = array("A" => 5, "B" => 10, "C" => 15, "D" => 20, "E" => 50); 

表示随机ABCDE,取到A的概率是5%,B为10%,C为15%,D为20%,E为50%。

思路很简单,画一根数轴,长度是ABCDE的权值的总和,按照他们的权值,分割这个数轴。

然后随机取数轴上的一点,落在哪个区间,就取哪个值。

9055836806934EBCB4272B12502AB86D

具体算法如下

   
   
   
   
  1. function GetRandom() { 
  2.     $list = array("A" => 5, "B" => 10, "C" => 15, "D" => 20, "E" => 50); 
  3.     $sum = 0; 
  4.     $listPoint = array(0);//这个数组记录了每个切割点的值,就是记录了数轴上,5,15,30,50,100的值。 
  5.     foreach ($list as $key => $value) { 
  6.         $sum+=$value;//计算出权值的总和 
  7.         array_push($listPoint$sum);//把分割点放到数组中 
  8.     } 
  9.     $num = rand(0, $sum);//取0到sum之间一个随机值 
  10.     //echo $num . ":"; 
  11.     for ($i = 0; $i < count($listPoint) - 1; $i++) 
  12.     { 
  13.         if ($num >= $listPoint[$i] && $num <= $listPoint[$i + 1]) //判断随机值落在哪个范围内 
  14.         { 
  15.             $elem = array_slice($list$i, 1); 
  16.             return key($elem); //第i项的值 
  17.         } 
  18.     } 
  19.     echo "can't be here"

测试代码,随机取100次,看看各个字母出现的次数。 

   
   
   
   
  1. $a = 0; 
  2. $b = 0; 
  3. $c = 0; 
  4. $d = 0; 
  5. $e = 0; 
  6. for ($i = 0; $i < 100; $i++) { 
  7.     $char = GetRandom(); 
  8.     echo "$char  "
  9.     switch ($char) { 
  10.         case "A"
  11.             $a++; 
  12.             break
  13.         case "B"
  14.             $b++; 
  15.             break
  16.         case "C"
  17.             $c++; 
  18.             break
  19.         case "D"
  20.             $d++; 
  21.             break
  22.         case "E"
  23.             $e++; 
  24.             break
  25.     } 
  26. echo "A:$a
    "
  27. echo "B:$b
    "
  28. echo "C:$c
    "
  29. echo "D:$d
    "
  30. echo "E:$e
    "
  31. die(0); 
PHP实现加权随机数(Weighted Random sampling)的生成算法_第1张图片

得到的结果勉强也能接受。