階梯訪問表優化

twisted-fate發表於2019-05-29

之前在 Code complete 中讀到了階梯訪問表的概念 , 寫出了第一版直接遍歷的函式把老專案裡的各種 if else 費率判斷清了個乾淨 .

階梯訪問表適合用在區間大小不固定的情況 , 如利息根據額度變化的需求

/**
 * 階梯訪問表 l 左邊界 r右邊界 v 取值
 * $table = [
 * ['l' => 1500, 'r' => 1500, 'v' => '0.23'],
 * ['l' => 2000, 'r' => 2000, 'v' => '0.25'],
 * ['l' => 2500, 'r' => 2500, 'v' => '0.29'],
 * ['l' => 2700, 'r' => 5000, 'v' => '0.30'],
 * ['l' => 5500, 'r' => 7000, 'v' => '0.50'],
 * ]
 * stairStepAccess($table , 2900) ; // 0.30
 *
 *
 * @param array $table 查詢表
 * @param mixed $target 查詢的目標資料
 * @return mixed
 * @throws Exception
 */
function stairStepAccessIterate($table, $target)
{
    foreach ($table as $row) {
        if ($row['l'] <= $target && $target <= $row['r']) {
            return $row['v'];
        }
    }

    throw new \Exception('stairStepAccess overflow '.$target);
}

然後呢最近每天都有做一道演算法題 , 自然而然的就開始思考起如何優化這個簡單的函式 , 大部分情況下表都是順序排列的, 所以使用了二分查詢重寫了中間部分程式碼


 * 階梯訪問表 l 左邊界 r右邊界 v 取值
 * $table = [
 * ['l' => 1500, 'r' => 1500, 'v' => '0.23'],
 * ['l' => 2000, 'r' => 2000, 'v' => '0.25'],
 * ['l' => 2500, 'r' => 2500, 'v' => '0.29'],
 * ['l' => 2700, 'r' => 5000, 'v' => '0.30'],
 * ['l' => 5500, 'r' => 7000, 'v' => '0.50'],
 * ]
 * stairStepAccess($table , 2900) ; // 0.30
 * 
 * 
 * @param array $table 查詢表 
 * @param mixed $target 查詢的目標資料 
 * @return mixed
 * @throws Exception
 */
function stairStepAccess($table, $target)
{
    $l = 0;
    $r = count($table) - 1;
    while ($l <= $r) {
        $mid = (int)(($l + $r) / 2);
        if ($table[$mid]['l'] <= $target && $target <= $table[$mid]['r']) {
            return $table[$mid]['v'];
        }
        if ($target > $table[$mid]['r']) {
            $l = $mid + 1;
        } else {
            $r = $mid - 1;
        }
    }
    throw new \Exception('stairStepAccess overflow value ' . $target);
}

生成了有 90 萬條資料的表 , 進行 100 萬次查詢後的效能簡單對比

階梯訪問表 PHP 函式

完結撒花 , 演算法撒浪嘿

PS : 尋求有挑戰的工作機會中 , 歡迎聯絡

相關文章