傳統遞歸構建樹形結構在深度較大時易導致棧溢出,且性能一般。本文提供**非遞歸、基於引用賦值**的 O(n) 算法,一次遍歷即可構建父節點樹或子節點樹。
find_parent()function find_parent($ar, $id='id', $pid='pid') {
// 步驟1: 建立 ID -> 節點映射表
foreach ($ar as $v) $t[$v[$id]] = $v;
// 步驟2: 遍歷建立父節點引用
foreach ($t as $k => $item) {
if ($item[$pid]) {
// 關鍵:使用引用賦值 & 避免數據複製
if (!isset($t[$item[$pid]]['parent'][$item[$pid]])) {
$t[$item[$id]]['parent'][$item[$pid]] = &$t[$item[$pid]];
}
}
}
return $t;
}
find_child()function find_child($ar, $id='id', $pid='pid') {
foreach ($ar as $v) $t[$v[$id]] = $v;
foreach ($t as $k => $item) {
if ($item[$pid]) {
// 將當前節點作為子節點掛載到父節點
$t[$item[$pid]]['child'][$item[$id]] = &$t[$k];
}
}
return $t;
}
$data = array(
array('ID'=>1, 'PARENT'=>0, 'NAME'=>'祖父'),
array('ID'=>2, 'PARENT'=>1, 'NAME'=>'父親'),
array('ID'=>3, 'PARENT'=>1, 'NAME'=>'叔伯'),
array('ID'=>4, 'PARENT'=>2, 'NAME'=>'自己'),
array('ID'=>5, 'PARENT'=>4, 'NAME'=>'兒子'),
);
$c = find_child($data, 'ID', 'PARENT');
print_r($c);
Array
(
[1] => Array
(
[ID] => 1
[PARENT] => 0
[NAME] => 祖父
[child] => Array
(
[2] => Array
(
[ID] => 2
[PARENT] => 1
[NAME] => 父親
[child] => Array
(
[4] => Array
(
[ID] => 4
[PARENT] => 2
[NAME] => 自己
[child] => Array
(
[5] => Array
(
[ID] => 5
[PARENT] => 4
[NAME] => 兒子
)
)
)
)
)
[3] => Array
(
[ID] => 3
[PARENT] => 1
[NAME] => 叔伯
)
)
)
// ... 其餘節點同理包含 child 結構
)
| 特性 | 遞歸法 | 本文非遞歸法 |
|---|---|---|
| 時間複雜度 | O(n²) 最壞 | O(n) |
| 空間複雜度 | O(h) 棧深度 | O(n) 映射表 |
| 最大深度限制 | 受限於棧大小 | 無限制 |
| 引用共享 | 需額外處理 | 天然支援 (&引用) |
$t[$v[$id]] = $v 實現 O(1) 節點查找$item[$pid] == 0 的節點