diff --git a/src/commonMain/kotlin/com.github.adriankuta/TreeNode.kt b/src/commonMain/kotlin/com.github.adriankuta/TreeNode.kt index d48a3a6..1b38d20 100644 --- a/src/commonMain/kotlin/com.github.adriankuta/TreeNode.kt +++ b/src/commonMain/kotlin/com.github.adriankuta/TreeNode.kt @@ -1,5 +1,9 @@ package com.github.adriankuta +import com.github.adriankuta.iterators.PostOrderTreeIterator +import com.github.adriankuta.iterators.PreOrderTreeIterator +import com.github.adriankuta.iterators.TreeNodeIterators +import com.github.adriankuta.iterators.TreeNodeIterators.* import kotlin.jvm.JvmSynthetic open class TreeNode(val value: T) : Iterable>, ChildDeclarationInterface { @@ -18,6 +22,8 @@ open class TreeNode(val value: T) : Iterable>, ChildDeclarationIn val children: List> get() = _children + var defaultIterator: TreeNodeIterators = PreOrder + /** * Add new child to current node or root. * @@ -139,5 +145,8 @@ open class TreeNode(val value: T) : Iterable>, ChildDeclarationIn * Output: 1 2 5 10 6 11 12 13 3 4 7 8 9 * ``` */ - override fun iterator(): Iterator> = PreOrderTreeIterator(this) + override fun iterator(): Iterator> = when (defaultIterator) { + PreOrder -> PreOrderTreeIterator(this) + PostOrder -> PostOrderTreeIterator(this) + } } \ No newline at end of file diff --git a/src/commonMain/kotlin/com.github.adriankuta/TreeNodeExt.kt b/src/commonMain/kotlin/com.github.adriankuta/TreeNodeExt.kt index 4f8df09..d3398d8 100644 --- a/src/commonMain/kotlin/com.github.adriankuta/TreeNodeExt.kt +++ b/src/commonMain/kotlin/com.github.adriankuta/TreeNodeExt.kt @@ -1,5 +1,6 @@ package com.github.adriankuta +import com.github.adriankuta.iterators.TreeNodeIterators import kotlin.jvm.JvmSynthetic typealias ChildDeclaration = ChildDeclarationInterface.() -> Unit @@ -13,8 +14,13 @@ typealias ChildDeclaration = ChildDeclarationInterface.() -> Unit * @see [ChildDeclarationInterface.child] */ @JvmSynthetic -inline fun tree(root: T, childDeclaration: ChildDeclaration): TreeNode { +inline fun tree( + root: T, + defaultIterator: TreeNodeIterators = TreeNodeIterators.PreOrder, + childDeclaration: ChildDeclaration +): TreeNode { val treeNode = TreeNode(root) + treeNode.defaultIterator = defaultIterator treeNode.childDeclaration() return treeNode } \ No newline at end of file diff --git a/src/commonMain/kotlin/com.github.adriankuta/iterators/PostOrderTreeIterator.kt b/src/commonMain/kotlin/com.github.adriankuta/iterators/PostOrderTreeIterator.kt new file mode 100644 index 0000000..c735e1f --- /dev/null +++ b/src/commonMain/kotlin/com.github.adriankuta/iterators/PostOrderTreeIterator.kt @@ -0,0 +1,50 @@ +package com.github.adriankuta.iterators + +import com.github.adriankuta.TreeNode + +/** + * Tree is iterated by using `Post-order Traversal Algorithm" + * 1. Check if the current node is empty or null. + * 2. Display the data part of the root (or current node). + * 3. Traverse the left subtree by recursively calling the pre-order function. + * 4. Traverse the right subtree by recursively calling the pre-order function. + * ``` + * E.g. + * 1 + * / | \ + * / | \ + * 2 3 4 + * / \ / | \ + * 5 6 7 8 9 + * / / | \ + * 10 11 12 13 + * + * Output: 1 2 5 10 6 11 12 13 3 4 7 8 9 + * ``` + */ +class PostOrderTreeIterator(root: TreeNode) : Iterator> { + + private val stack = ArrayDeque>() + + init { + stack.addAll(getChildrenStack(root)) + } + + override fun hasNext(): Boolean = stack.isNotEmpty() + + override fun next(): TreeNode { + return stack.removeFirst() + } + + private fun getChildrenStack(node: TreeNode): ArrayDeque> { + val stack = ArrayDeque>() + if(node.children.isEmpty()) { + return ArrayDeque(listOf(node)) + } + node.children.forEach { + stack.addAll(getChildrenStack(it)) + } + stack.addLast(node) + return stack + } +} \ No newline at end of file diff --git a/src/commonMain/kotlin/com.github.adriankuta/PreOrderTreeIterator.kt b/src/commonMain/kotlin/com.github.adriankuta/iterators/PreOrderTreeIterator.kt similarity index 89% rename from src/commonMain/kotlin/com.github.adriankuta/PreOrderTreeIterator.kt rename to src/commonMain/kotlin/com.github.adriankuta/iterators/PreOrderTreeIterator.kt index aba65c3..5e03c22 100644 --- a/src/commonMain/kotlin/com.github.adriankuta/PreOrderTreeIterator.kt +++ b/src/commonMain/kotlin/com.github.adriankuta/iterators/PreOrderTreeIterator.kt @@ -1,4 +1,6 @@ -package com.github.adriankuta +package com.github.adriankuta.iterators + +import com.github.adriankuta.TreeNode /** * Tree is iterated by using `Pre-order Traversal Algorithm" @@ -31,10 +33,12 @@ class PreOrderTreeIterator(root: TreeNode) : Iterator> { override fun hasNext(): Boolean = stack.isNotEmpty() override fun next(): TreeNode { + println(stack) val node = stack.removeLast() node.children .asReversed() .forEach { stack.addLast(it) } + println(stack) return node } } \ No newline at end of file diff --git a/src/commonMain/kotlin/com.github.adriankuta/iterators/TreeNodeIterators.kt b/src/commonMain/kotlin/com.github.adriankuta/iterators/TreeNodeIterators.kt new file mode 100644 index 0000000..7451c4c --- /dev/null +++ b/src/commonMain/kotlin/com.github.adriankuta/iterators/TreeNodeIterators.kt @@ -0,0 +1,5 @@ +package com.github.adriankuta.iterators + +enum class TreeNodeIterators { + PreOrder, PostOrder +} \ No newline at end of file diff --git a/src/commonTest/kotlin/com.github.adriankuta/TreeNodeTest.kt b/src/commonTest/kotlin/com.github.adriankuta/TreeNodeTest.kt index 148cf66..33c24d6 100644 --- a/src/commonTest/kotlin/com.github.adriankuta/TreeNodeTest.kt +++ b/src/commonTest/kotlin/com.github.adriankuta/TreeNodeTest.kt @@ -1,6 +1,8 @@ package com.github.adriankuta +import com.github.adriankuta.iterators.TreeNodeIterators import kotlin.test.Test +import kotlin.test.assertContentEquals import kotlin.test.assertEquals import kotlin.test.assertNull @@ -46,9 +48,7 @@ class TreeNodeTest { "Pretty print test" ) - println("Remove: ${curdNode.value}") root.removeChild(curdNode) - println("Remove: ${gingerTeaNode.value}") root.removeChild(gingerTeaNode) assertEquals( "Root\n" + @@ -87,9 +87,6 @@ class TreeNodeTest { curdNode.addChild(yogurtNode) curdNode.addChild(lassiNode) - println(root.toString()) - println(curdNode.height()) - root.clear() assertEquals(root.children, emptyList()) assertEquals(beveragesNode.children, emptyList()) @@ -141,4 +138,43 @@ class TreeNodeTest { } assertEquals(root.prettyString(), rootExt.prettyString()) } + + @Test + fun preOrderIteratorTest() { + val tree = tree("F") { + child("B") { + child("A") + child("D") { + child("C") + child("E") + } + } + child("G") { + child("I") { + child("H") + } + } + } + val expectedPreOrder = listOf("F", "B", "A", "D", "C", "E", "G", "I", "H") + assertContentEquals(expectedPreOrder, tree.toList().map { it.toString() }) + } + @Test + fun postOrderIteratorTest() { + val tree = tree("A", TreeNodeIterators.PostOrder) { + child("B") { + child("E") + } + child("C") + child("D") { + child("F") + child("G") + child("H") + child("I") + child("J") + } + } + + val expectedPreOrder = listOf("E", "B", "C", "F", "G", "H", "I", "J", "D", "A") + assertContentEquals(expectedPreOrder, tree.toList().map { it.toString() }) + } } \ No newline at end of file