請搭配 D10 - 樹狀搜尋問題 實作篇 閱讀。
從演算法的角度上來看,假設 N 為樹的節點數量,「結構化」與「函數式」兩種時作方式在空間複雜度,以及時間複雜度上都是相等的 O(N)。
function getNameById(target:string){
let queue = [tree]
while(queue.length > 0){
let node = queue[0]
if(node.id === target){
return node.text // 如果是目標點就結束並返回
}
for(let child of node.children){
queue.push(child)
}
queue.shift()
}
return undefined
}
然而透過實際執行的流程來看,結構式會在執行的時候,在找到目標的當下。就會跳出迴圈、結束函示,直接顯示結果。
const getNameById = (target:string)=>(tree:Tree):string | undefined =>
tree.id === target
? tree.text
: tree.children
.map(getNameById(target)) // 全部遍歷過
.find(text=>text!==undefined)
函數式程式設計中,上面的做法卻會把目標全部遍歷過再找出結果。這種效能差距雖然在函式只有一個的時候看不出來,但是隨著層層疊疊的函式呼叫,累積起來也可能造成很可觀的效能損失。
const getNameById = (target:string)=>(tree:Tree):string | undefined =>
tree.id === target
? tree.text
: tree.children
.map(getNameById(target))
.find(text=>text!==undefined)
即使在 index 0 就找到,還是必須把後面的流程全部跑完,想想實在是不舒服! 因此我們可以再對函數式的實作做一些小小的優化
const getNameById = (target:string)=>(tree:Tree):string | undefined =>
tree.id === target
? tree.text
: tree.children
.reduce(
(accumulator,current)=>
accumulator??getNameById(target)(current),
"" as string | undefined
)
藉由 reduce 取代 map,就可以達到類似結構式程式設計的實作中 early return 的效果囉!