Ağaç geçişi, bilgisayar biliminde bir ağaç veri yapısındaki her düğümün sistematik olarak ziyaret edilmesini içeren temel bir kavramdır. Ağaç geçişi aracılığıyla, düğümleri önceden belirlenmiş bir sırayla işleyebilir, ifadeleri arama, sıralama ve değerlendirme gibi işlemleri kolaylaştırabiliriz.
Bu makalede en yaygın kullanılan ağaç geçiş yöntemlerinden üçünü inceleyeceğiz: inorder, preorder ve postorder.
JavaScript'te uygulanan açık ve özlü örnekler sayesinde bu geçiş tekniklerini sağlam bir şekilde anlayacaksınız.
Ağaç geçiş algoritmalarına dalmadan önce ikili ağaç için kullanacağımız yapıyı tanımlayalım. Ağaç, her düğümün bir değer içerdiği ve sol ve sağ alt düğümlerine referanslar içerdiği düğümlerden oluşacaktır.
function TreeNode(val = 0, left = null, right = null) { this.val = val; this.left = left; this.right = right; }
Artık ağaç yapısını tanımladığımıza göre üç ağaç geçiş yöntemini keşfetmeye devam edebiliriz.
Sıralı geçiş, bir ikili ağaçtaki düğümleri ziyaret etmenin bir sonraki modelini takip eder - algoritma önce sol alt ağacı geçer, ardından mevcut düğümü ziyaret eder ve son olarak sağ alt ağacı geçer. Bu, ağacın sıralanmış bir veri yapısını temsil etmesi durumunda düğümlerin artan sırada ziyaret edilmesini sağlar.
A / \ BC / \ / \ DEFG // Inorder traversal result: D -> B -> E -> A -> F -> C -> G
Geçerli düğümün boş olup olmadığını kontrol edin. Eğer öyleyse geri dönün.
Sol alt ağaçtaki işlevi yinelemeli olarak çağırın.
Geçerli düğümü ziyaret edin.
Sağ alt ağaçtaki işlevi yinelemeli olarak çağırın.
function inorderRecursive(tree) { const result = []; function inorderTraverse(node) { if (!node) return; inorderTraverse(node.left); result.push(node.val); inorderTraverse(node.right); } inorderTraverse(tree); return result; }
Boş bir yığın başlatın ve geçerli düğümü ağacın köküne ayarlayın.
Yığın boş değilken veya geçerli düğüm boş değilken yineleyin.
Boş bir sol çocuğa ulaşana kadar tüm sol düğümleri yığının üzerine itin.
Yığından bir düğüm açın, onu ziyaret edin ve mevcut düğümü sağ alt düğüme ayarlayın.
Yığın boşalana ve geçerli düğüm boş olana kadar 2. adımı tekrarlayın.
function inorderRecursive(tree) { const stack = []; const result = []; let currentNode = tree; while (currentNode || stack.length) { while (currentNode) { stack.push(currentNode); currentNode = currentNode.left; } const node = stack.pop(); result.push(node.val); currentNode = node.right; } return result; }
Ön sipariş geçişinde, algoritma önce mevcut düğümü ziyaret eder, ardından sol alt ağacı geçer ve son olarak sağ alt ağacı geçer. Bu sıralama, düğümlerin kökten başlayıp yapraklara doğru "yukarıdan aşağıya" bir şekilde ziyaret edilmesini sağlar.
A / \ BC / \ / \ DEFG // Preorder traversal result: A -> B -> D -> E -> C -> F -> G
Geçerli düğümün boş olup olmadığını kontrol edin. Eğer öyleyse geri dönün.
Geçerli düğümü ziyaret edin.
Sol alt ağaçtaki işlevi yinelemeli olarak çağırın.
Sağ alt ağaçtaki işlevi yinelemeli olarak çağırın.
function preorderRecursive(tree) { const result = []; function preorderTraverse(node) { if (!node) return; result.push(node.val); preorderTraverse(node.left); preorderTraverse(node.right); } preorderTraverse(tree); return result; }
Boş bir yığınla başlayın ve kök düğümü yığının üzerine itin.
Ön sipariş geçiş sonucunu depolamak için boş bir dizi başlatın.
Yığın boşalana kadar çalışacak bir while döngüsü girin.
Yığından bir düğüm açın ve değerini sonuç dizisine ekleyerek onu ziyaret edin.
Düğümün sağ çocuğu varsa sağ çocuğu yığına itin.
Düğümün bir sol çocuğu varsa, sol çocuğu yığının üzerine itin.
Yığın boşalana kadar 3-6 arasındaki adımları tekrarlayın.
function preorderTraversal(root) { if (!root) return []; const stack = [root]; const result = []; while (stack.length) { const node = stack.pop(); result.push(node.val); if (node.right) stack.push(node.right); if (node.left) stack.push(node.left); } return result; }
Bu geçişte, algoritma önce sol alt ağacı, ardından sağ alt ağacı geçer ve son olarak mevcut düğümü ziyaret eder. Bu sıralama, düğümlerin yapraklardan başlayıp köke doğru "aşağıdan yukarıya" bir şekilde ziyaret edilmesini sağlar.
A / \ BC / \ / \ DEFG // Postorder traversal result: D -> E -> B -> F -> G -> C -> A
Geçerli düğümün boş olup olmadığını kontrol edin. Eğer öyleyse geri dönün.
Sol alt ağaçtaki işlevi yinelemeli olarak çağırın.
Sağ alt ağaçtaki işlevi yinelemeli olarak çağırın.
Geçerli düğümü ziyaret edin.
function postorderRecursive(tree) { const result = []; function postorderTraverse(node) { if (!node) return; postorderTraverse(node.left); postorderTraverse(node.right); result.push(node.val); } postorderTraverse(tree); return result; }
Boş bir yığınla başlayın ve kök düğümü yığının üzerine itin.
Sipariş sonrası geçiş sonucunu depolamak için boş bir dizi başlatın.
Yığın boşalana kadar çalışacak bir while döngüsü girin.
Yığından en üstteki düğümü alın (çıkarmadan).
Düğümün sol çocuğu varsa, sol çocuğu yığına itin ve geçerli düğümün sol çocuğunu null olarak ayarlayın.
Düğümün sağ çocuğu varsa, sağ çocuğu yığına itin ve geçerli düğümün sağ çocuğunu null olarak ayarlayın.
Düğümün ne sağ ne de sol çocuğu varsa bu bir yaprak düğümdür. Düğümü yığından çıkarın ve değerini sonuç dizisine ekleyin.
Yığın boşalana kadar 4-7 arasındaki adımları tekrarlayın.
function postorderTraversal(root) { if (!root) return []; const stack = [root]; const result = []; while (stack.length) { const node = stack[stack.length - 1]; if (node.left) { stack.push(node.left); node.left = null; } else if (node.right) { stack.push(node.right); node.right = null; } else { result.push(stack.pop().val); } } return result; }
Umarım artık JavaScript'te inorder, preorder ve postorder geçişi arasındaki farkları net bir şekilde anlamışsınızdır. Sağlanan bilgi ve örneklerle artık bu teknikleri kendi görev ve projelerinize etkili bir şekilde uygulayabilecek donanıma sahipsiniz.