首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 概率計算演算法大全:抽獎、隨機分配實戰代碼

     編輯:PHP 綜合知識

前言

概率演算法在抽獎系統、遊戲掉寶、廣告加權展示等場景極為常見。本文匯總三種經典 PHP 實現,從面向對象封裝到純函數式寫法,滿足不同業務需求。

方案一:面向對象概率類(適合複雜業務)

封裝 Probability 類,支援動態添加獎項與權重,內部維護總權重池,getOne() 方法基於隨機數落區間原理返回結果。

<?php
class Probability {
    private $data = [];
    private $chance_count = 0;

    public function __construct(array $initdata = []) {
        if (!empty($initdata)) {
            $this->data = $initdata;
            foreach ($initdata as $d) {
                $this->chance_count += $d['num'];
            }
        }
    }

    public function addData(string $name, int $chance): void {
        $this->data[] = ['name' => $name, 'num' => $chance];
        $this->chance_count += $chance;
    }

    public function getOne(): string {
        $index = rand(0, $this->chance_count);
        foreach ($this->data as $d) {
            $index -= $d['num'];
            if ($index <= 0) return $d['name'];
        }
        return '';
    }
}

// 使用示例
$pro = new Probability();
$pro->addData('iPhone', 10);
$pro->addData('Watch', 30);
$pro->addData('$18', 50);
$pro->addData('Thank you', 10);
$pro->addData('Super big', 1);

for ($i = 0; $i < 100; $i++) {
    echo $pro->getOne() . "\n";
}
?>

方案二:經典遞減區間法(高效、簡潔)

核心邏輯:計算總權重,遍歷獎項陣列,每輪生成 1~剩餘總權重的隨機數,若落在當前獎項權重內則命中,否則扣除當前權重進入下一輪。時間複雜度 O(n),極適合大數據量場景。

<?php
function get_rand(array $proArr): string {
    $result = '';
    $proSum = array_sum($proArr);
    foreach ($proArr as $key => $proCur) {
        $randNum = mt_rand(1, $proSum);
        if ($randNum <= $proCur) {
            $result = $key;
            break;
        } else {
            $proSum -= $proCur;
        }
    }
    return $result;
}

// 測試:a:20%, b:30%, c:50%
$prize_arr = ['a' => 20, 'b' => 30, 'c' => 50];
for ($i = 0; $i < 10; $i++) {
    echo get_rand($prize_arr) . " ";
}
?>

執行流程圖解(以 a:20, b:30, c:50 為例)

  1. 總權重 100,隨機數 55 > 20 → 扣除 20,剩餘 80
  2. 隨機數 33 > 30 → 扣除 30,剩餘 50
  3. 隨機數任意值 ≤ 50 → 命中 c

方案三:累加臨界值法(另一種思路)

預先計算每個獎項的累積權重臨界值,生成單一隨機數,判斷落在哪個區間。邏輯直觀,適合權重固定、頻繁抽獎的場景。

<?php
function get_rand_v2(array $arr): string {
    $pro_sum = array_sum($arr);
    $rand_num = mt_rand(1, $pro_sum);
    $tmp_num = 0;
    foreach ($arr as $k => $val) {
        if ($rand_num <= $val + $tmp_num) return $k;
        $tmp_num += $val;
    }
    return '';
}
?>

完整抽獎系統範例(含獎品池、中獎記錄、JSON 輸出)

<?php
$prize_arr = [
    ['id'=>1, 'prize'=>'平板電腦', 'v'=>1],
    ['id'=>2, 'prize'=>'數碼相機', 'v'=>5],
    ['id'=>3, 'prize'=>'音箱設備', 'v'=>10],
    ['id'=>4, 'prize'=>'4G優盤', 'v'=>12],
    ['id'=>5, 'prize'=>'10Q幣', 'v'=>22],
    ['id'=>6, 'prize'=>'下次沒準就能中哦', 'v'=>50],
];

// 構建權重陣列
foreach ($prize_arr as $val) {
    $arr[$val['id']] = $val['v'];
}

$rid = get_rand($arr); // 獲取中獎 ID
$res['yes'] = $prize_arr[$rid-1]['prize']; // 中獎獎品

// 剔除已中獎項,打亂剩餘順序
unset($prize_arr[$rid-1]);
shuffle($prize_arr);
$res['no'] = array_column($prize_arr, 'prize');

header('Content-Type: application/json');
echo json_encode($res);
?>

選型建議

  • 簡單抽獎:方案二/三,代碼量少、效能高
  • 動態獎品池、多業務復用:方案一,封裝性好、易擴展
  • 超大流量(萬級 QPS):建議方案二配合 Redis 預計算權重區間,減少 PHP 計算開銷
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved