İşlevi özyinelemeli olamaz. Bunun nedeni, insert
numaralı özyinelemeli çağrınızın hesaplamayı bitirmemesidir, bunlar alt-ifade olarak kullanılır, bu durumda new Node(...)
. Örneğin. Eğer sadece alt elemanı arıyor olsaydınız, kuyruğunu tekrar tekrar yapmak kolay olurdu. Eğer düğümlerin her birinde insert
arayarak, aşağı ağaç inen konum olarak, ama sen bir dibe değiştirmek sonra ağaç yeniden beri, geri köküne yolunu hatırlamak zorunda:
Olası bir çözüm: Yığın değil, açık yolu açıkça unutmayın. s örneğin basitleştirilmiş veri yapısını kullanalım:
sealed trait Tree;
case object EmptyTree extends Tree;
case class Node(elem: Int, left:Tree, right:Tree) extends Tree;
Şimdi bir yol ne olduğunu tanımlamak: Biz sağ veya sol gitsem daha bilgilerle birlikte düğümlerin bir listesi. Kök her zaman listenin sonundadır, başlangıçta yaprak.
// Find a path down the tree that leads to the leaf where `v` would belong.
private def path(tree: Tree, v: Int): Path = {
@tailrec
def loop(t: Tree, p: Path): Path =
t match {
case EmptyTree => p
case [email protected](w, l, r) =>
if (v < w) loop(l, (n, false) :: p)
else loop(r, (n, true) :: p)
}
loop(tree, Nil)
}
ve olarak değerle yeni bir ağaç bir yol ve bir değer alır ve yeniden yapılandırır bir işlevi:
type Path = List[(Node, Boolean)]
Şimdi bir değer verilir bir yol hesaplar bir kuyruk özyinelemeli fonksiyon yapabilir yolun alt kısmında yeni düğüm: // Given a path reconstruct a new tree with `v` inserted at the bottom
// of the path.
private def rebuild(path: Path, v: Int): Tree = {
@tailrec
def loop(p: Path, subtree: Tree): Tree =
p match {
case Nil => subtree
case (Node(w, l, r), false) :: q => loop(q, Node(w, subtree, r))
case (Node(w, l, r), true) :: q => loop(q, Node(w, l, subtree))
}
loop(path, Node(v, EmptyTree, EmptyTree))
}
ekleme kolay o zaman:
def insert(tree: Tree, v: Int): Tree =
rebuild(path(tree, v), v)
Bu sürümün özellikle verimli olmadığına dikkat edin. Muhtemelen yolu saklamak için Seq
'u kullanarak veya daha da verimli bir yığın kullanarak daha verimli hale getirebilirsiniz. Ancak List
ile fikir güzelce ifade edilebilir.
Feragatname: Sadece kodu derledim, hiç test etmedim.
Notlar:
- Bu fonksiyonel bir ağaçta ilerleme zippers kullanmanın özel bir örnektir. Fermuarlar ile aynı fikri her türlü ağacın üzerine uygulayabilir ve ağacı çeşitli yönlerde yürütebilirsiniz.
- Ağacın daha büyük elemanlar için yararlı olmasını istiyorsanız (büyük olasılıkla bunu yapıyorsanız, taşmaları taşıyorsanız), self-balanced ürününü kullanmanızı kesinlikle öneririz. Yani, ağacın yapısını, derinliğin her zaman O (log n) olması için güncelleştirin. Daha sonra işlemleriniz her durumda hızlı olacaktır, yığın taşmaları hakkında endişelenmenize gerek kalmayacak ve yığın tabanlı, kuyruksuz tekrarlanan sürümünüzü kullanabilirsiniz. Muhtemelen, kendi kendini dengeleyen bir ağacın en kolay çeşidi AA tree'dur.
"Nil" in "yeniden oluşturma" durumunda, nereden gelmiyor? –
@ The.Anti.9 Bunu işaretlediğiniz için teşekkürler, düzeltdim. Bu bir hataydı, “alt ağaç” olmalıydı (bazı değişkenleri daha açıklayıcı olarak değiştirdim ve bunu unutmuştum). –