рекурсия является функциональной
Рекурсия является функциональным наследием, и поэтому написание вашей программы в функциональном стиле даст наилучшие результаты.Это означает, что нужно избегать мутаций, нулевых проверок и других побочных эффектов.Вместо того, чтобы убивать ваш код, я просто надеюсь, что другая программа прояснит, что есть более эффективные способы решения этой проблемы ...
Мы начинаем с Empty
и Node
const Empty =
{}
const Node = (value, left = Empty, right = Empty) =>
({ value, left, right })
И путь к merge
двум узлам
const merge = (n1, n2) =>
n1 === Empty
? n2
: n2 === Empty
? n1
: Node ( n1.value + n2.value // some merging operation!
, merge (n1.left, n2.left)
, merge (n1.right, n2.right)
)
Теперь мы возьмем два дерева, t1
и t2
const t1 =
Node ('A'
, Node ('B')
, Node ('C', Node ('D'), Node ('E'))
)
const t2 =
Node ('a'
, Node ('b', Node ('x'))
, Node ('c'
, Node ('d', Node ('y'))
)
)
Чтобы увидеть, что происходитдалее, мы добавляем некоторую функцию к print
деревьям
const print = (node, pre = '', child = '') =>
node === Empty
? ""
: print (node.left, child + '┌── ', child + '. ')
+ pre + String (node.value) + '\n'
+ print (node.right, child + '└── ', child + '. ')
console.log (print (t1)
// ┌── B
// A
// . ┌── D
// └── C
// . └── E
console.log (print (t2))
// . ┌── x
// ┌── b
// a
// . . ┌── y
// . ┌── d
// └── c
Теперь для празднования - обратите внимание, что ни t1
, ни t2
не изменяются в результате вызова merge
.Совершенно новый t3
сформирован.
const t3 =
merge (t1, t2)
console.log (print (t3))
// . ┌── x
// ┌── Bb
// Aa
// . . ┌── y
// . ┌── Dd
// └── Cc
// . └── E
Запустите полную программу в вашем браузере ниже
const Empty =
{}
const Node = (value, left = Empty, right = Empty) =>
({ value, left, right })
const merge = (n1, n2) =>
n1 === Empty
? n2
: n2 === Empty
? n1
: Node ( n1.value + n2.value // some merging function!
, merge (n1.left, n2.left)
, merge (n1.right, n2.right)
)
const print = (node, pre = '', child = '') =>
node === Empty
? ""
: print (node.left, child + '┌── ', child + '. ')
+ pre + String (node.value) + '\n'
+ print (node.right, child + '└── ', child + '. ')
const t1 =
Node ('A'
, Node ('B')
, Node ('C', Node ('D'), Node ('E'))
)
const t2 =
Node ('a'
, Node ('b', Node ('x'))
, Node ('c'
, Node ('d', Node ('y'))
)
)
console.log (print (t1))
// ┌── B
// A
// . ┌── D
// └── C
// . └── E
console.log (print (t2))
// . ┌── x
// ┌── b
// a
// . . ┌── y
// . ┌── d
// └── c
const t3 =
merge (t1, t2)
console.log (print (t3))
// . ┌── x
// ┌── Bb
// Aa
// . . ┌── y
// . ┌── Dd
// └── Cc
// . └── E
функциональные средства гибкие
Очевидные улучшения этой программы включают в себя превращение merge
в функцию более высокого порядка, такую что +
не жестко запрограммирован в нашей программе
// improved merge; user-defined merging function, f
const merge = (<b>f,</b> n1, n2) =>
n1 === Empty
? n2
: n2 === Empty
? n1
: Node ( <b>f (</b>n1.value, n2.value<b>)</b> // <---
, merge (<b>f,</b> n1.left, n2.left)
, merge (<b>f,</b> n1.right, n2.right)
)
Теперь вызывающая сторона merge
может определить, как объединяются значения.В этом примере мы помещаем оба значения в массив
const t4 =
merge (<b>(v1,v2) => [v1, v2],</b> t1, t2)
console.log (print (t4))
// . ┌── x
// ┌── B,b
// A,a
// . . ┌── y
// . ┌── D,d
// └── C,c
// . └── E
Теперь, когда мы print
дерева, массивы преобразуются в строки.Другим очевидным улучшением здесь было бы настроить нашу print
функцию, аналогичную той, которую мы сделали с merge
, позволяя пользователю указать способ печати значений
// improved print; String is no longer hard-coded
const print = (node, <b>fmt = String,</b> pre = '', child = '') =>
node === Empty
? ""
: print (node.left, <b>fmt,</b> child + '┌── ', child + '. ')
+ pre + <b>fmt</b> (node.value) + '\n' // <---
+ print (node.right, <b>fmt,</b> child + '└── ', child + '. ')
Теперь мы можемукажите нашу функцию форматирования в качестве второго аргумента
console.log (print (t4<b>, JSON.stringify</b>)) // print as JSON!
// . ┌── "x"
// ┌── ["B","b"]
// ["A","a"]
// . . ┌── "y"
// . ┌── ["D","d"]
// └── ["C","c"]
// . └── "E"
В деревьях выше мы выводим ""
для Empty
узлов.Возможно, нам нужен способ их визуализации, чтобы мы могли изменить функцию print
еще раз
// improved print; displays Empty nodes as ∅
const print = (node, fmt = String, pre = '', child = '') =>
node === Empty
? <b>pre + '\u2205\n'</b> // <---
: print (node.left, fmt, child + '┌── ', child + '. ')
+ pre + fmt (node.value) + '\n'
+ print (node.right, fmt, child + '└── ', child + '. ')
console.log (print (t3))
// . . ┌── ∅
// . ┌── x
// . . └── ∅
// ┌── Bb
// . └── ∅
// Aa
// . . . ┌── ∅
// . . ┌── y
// . . . └── ∅
// . ┌── Dd
// . . └── ∅
// └── Cc
// . . ┌── ∅
// . └── E
// . . └── ∅