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

巧用 01 字串高效表示離散集合:從年齡區間到隨機抽樣的實戰技巧

     編輯:PHP 相關知識

在處理「不連續、離散的集合數據」時,傳統方案多用字符串拼接(如 10-20|25|29-40)或多字段存儲。但隨著業務複雜度提升,解析、查詢、存儲開銷逐漸成為瓶頸。本文介紹一種極簡高效的替代方案——01 字串(位圖/Bitmap)編碼,並通過三個實戰場景演示其優勢與權衡。

核心思想:一個位代表一個元素的存在性

假設業務範圍為 1-100 歲,用 100 個字符的字串表示,第 i 位為 1 表示存在年齡 i,0 表示不存在。例如:

0111111000  =>  代表 2-7 歲(索引 1-6 為 1)
0110111010  =>  代表 2-3、5-7、9 歲

這本質上是 位圖(Bitmap)的字符串化表達,將集合運算轉化為字符串/位運算,極大簡化邏輯。

場景一:靈活表示年齡區間集合

需求:支援 10-20、25、29-40 這類任意離散區間組合。

傳統方案痛點: 需自定義解析規則,篩選時需拆分字符串、遍歷區間、逐個判斷,代碼冗長且易出錯。

01 字串方案:

// 初始化:100 個 0
$ageBitmap = str_repeat('0', 100);

// 設置區間函數
function setRange(&$bitmap, $start, $end) {
    for ($i = $start; $i <= $end; $i++) {
        $bitmap[$i - 1] = '1';  // 字符串可直接按索引修改(PHP 7.1+)
    }
}

// 使用
setRange($ageBitmap, 10, 20);
setRange($ageBitmap, 25, 25);
setRange($ageBitmap, 29, 40);

// 判斷某年齡是否包含:O(1)
function hasAge($bitmap, $age) {
    return $bitmap[$age - 1] === '1';
}

優勢: 設置/查詢均為 O(1) 或 O(區間長度),無需解析邏輯,代碼極簡。

場景二:大範圍隨機抽樣結果存儲與傳輸

需求:從 1-200 中隨機選取若干數字,需在前後端傳輸或持久化。

傳統方案: 1|5|100|199 字符串,數量越多越長,解析仍需 explode + 遍歷。

01 字串方案: 固定 200 字符,1 表示被選中。網絡傳輸固定長度,解析極快:

// 生成:隨機選 10 個數
$bitmap = str_repeat('0', 200);
$selected = [];
while (count($selected) < 10) {
    $n = mt_rand(1, 200);
    if ($bitmap[$n-1] === '0') {
        $bitmap[$n-1] = '1';
        $selected[] = $n;
    }
}

// 傳輸:直接發送 $bitmap 字符串(200 bytes)
// 接收端判斷:$bitmap[99] === '1' 即知 100 被選中

場景三:超大稀疏 ID 集合的映射壓縮

需求:表示 [1926, 19658, 12, 5638, 8975, 965, 369, 5126, 5698, 14556] 這類稀疏、跨度極大的 ID 集合。直接用 19658 位字串極其浪費。

映射壓縮方案:

  1. 建立映射表:[1=>1926, 2=>19658, 3=>12, ...]
  2. 用 10 位 01 字串表示選中狀態:1010000010 代表選中 1、3、9 號映射項
  3. 傳輸時僅發送映射表(首次/變更時)+ 01 字串(高頻)
// 映射表(雙方約定或首次下發)
$map = [1926, 19658, 12, 5638, 8975, 965, 369, 5126, 5698, 14556];

// 狀態字串(高頻變更、傳輸)
$state = '1010000010';  // 選中 1926、12、5698

// 解碼
$selectedIds = [];
for ($i = 0; $i < strlen($state); $i++) {
    if ($state[$i] === '1') $selectedIds[] = $map[$i];
}
// 結果:[1926, 12, 5698]

此法極大節省頻寬,尤其適合 WebSocket 長連接、MQTT 物聯網場景的高頻狀態同步。

擴展應用:時間段、權限集、標籤系統

  • 日程可用時段: 一天 288 個 5 分鐘槽位 → 288 字符 01 字串
  • RBAC 權限集: 64 權限點 → 64 位字串,或直接用 64 位整數位運算(更高效)
  • 文章標籤: 固定標籤庫 1000 個 → 1000 位字串,支持極快的「包含任一標籤」判斷

優缺點總結與選型建議

維度01 字串傳統字符串/JSON數據庫關聯表
存儲空間固定、極小(位級)隨數據量線性增長標準化、可索引
查詢/判斷速度極快(O(1) 索引/位運算)需解析遍歷需 JOIN/子查詢
開發複雜度低(核心邏輯極簡)中(需解析器)高(遷移、維護)
適用場景範圍固定、高頻讀寫、離散集合結構不固定、低頻關聯查詢複雜、需事務
局限性範圍不可動態擴展、稀疏需映射通用性強最通用

建議: 當集合範圍明確(如 1-100 歲、1-288 時段、固定權限點)、讀寫頻率高、且主要操作是「判斷屬於/不屬於」「並集/交集/差集」時,01 字串是極佳選擇。若範圍動態變化大、或需複雜關聯查詢,仍建議用標準關聯表或 JSON 字段(MySQL 5.7+/PostgreSQL 支援 JSON 索引)。


位圖思想不僅限於字符串,PHP 還提供 gmp_init()、gmp_setbit() 等 GMP 大整數函數,可直接進行位運算(AND/OR/XOR),性能更強。對於千萬級位圖,建議使用 Redis Bitmap(SETBIT/GETBIT/BITOP)實現分佈式高性能集合運算。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved