mirror of
https://github.com/AdrianKuta/Tree-Data-Structure.git
synced 2025-04-19 23:19:03 +02:00
5: Implement post-order traversal algorithm (#16)
This commit is contained in:
parent
8a2710339a
commit
b69e838a8a
@ -1,5 +1,9 @@
|
|||||||
package com.github.adriankuta
|
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
|
import kotlin.jvm.JvmSynthetic
|
||||||
|
|
||||||
open class TreeNode<T>(val value: T) : Iterable<TreeNode<T>>, ChildDeclarationInterface<T> {
|
open class TreeNode<T>(val value: T) : Iterable<TreeNode<T>>, ChildDeclarationInterface<T> {
|
||||||
@ -18,6 +22,8 @@ open class TreeNode<T>(val value: T) : Iterable<TreeNode<T>>, ChildDeclarationIn
|
|||||||
val children: List<TreeNode<T>>
|
val children: List<TreeNode<T>>
|
||||||
get() = _children
|
get() = _children
|
||||||
|
|
||||||
|
var defaultIterator: TreeNodeIterators = PreOrder
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add new child to current node or root.
|
* Add new child to current node or root.
|
||||||
*
|
*
|
||||||
@ -139,5 +145,8 @@ open class TreeNode<T>(val value: T) : Iterable<TreeNode<T>>, ChildDeclarationIn
|
|||||||
* Output: 1 2 5 10 6 11 12 13 3 4 7 8 9
|
* Output: 1 2 5 10 6 11 12 13 3 4 7 8 9
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
override fun iterator(): Iterator<TreeNode<T>> = PreOrderTreeIterator(this)
|
override fun iterator(): Iterator<TreeNode<T>> = when (defaultIterator) {
|
||||||
|
PreOrder -> PreOrderTreeIterator(this)
|
||||||
|
PostOrder -> PostOrderTreeIterator(this)
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package com.github.adriankuta
|
package com.github.adriankuta
|
||||||
|
|
||||||
|
import com.github.adriankuta.iterators.TreeNodeIterators
|
||||||
import kotlin.jvm.JvmSynthetic
|
import kotlin.jvm.JvmSynthetic
|
||||||
|
|
||||||
typealias ChildDeclaration<T> = ChildDeclarationInterface<T>.() -> Unit
|
typealias ChildDeclaration<T> = ChildDeclarationInterface<T>.() -> Unit
|
||||||
@ -13,8 +14,13 @@ typealias ChildDeclaration<T> = ChildDeclarationInterface<T>.() -> Unit
|
|||||||
* @see [ChildDeclarationInterface.child]
|
* @see [ChildDeclarationInterface.child]
|
||||||
*/
|
*/
|
||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
inline fun<reified T> tree(root: T, childDeclaration: ChildDeclaration<T>): TreeNode<T> {
|
inline fun <reified T> tree(
|
||||||
|
root: T,
|
||||||
|
defaultIterator: TreeNodeIterators = TreeNodeIterators.PreOrder,
|
||||||
|
childDeclaration: ChildDeclaration<T>
|
||||||
|
): TreeNode<T> {
|
||||||
val treeNode = TreeNode(root)
|
val treeNode = TreeNode(root)
|
||||||
|
treeNode.defaultIterator = defaultIterator
|
||||||
treeNode.childDeclaration()
|
treeNode.childDeclaration()
|
||||||
return treeNode
|
return treeNode
|
||||||
}
|
}
|
@ -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<T>(root: TreeNode<T>) : Iterator<TreeNode<T>> {
|
||||||
|
|
||||||
|
private val stack = ArrayDeque<TreeNode<T>>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
stack.addAll(getChildrenStack(root))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hasNext(): Boolean = stack.isNotEmpty()
|
||||||
|
|
||||||
|
override fun next(): TreeNode<T> {
|
||||||
|
return stack.removeFirst()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getChildrenStack(node: TreeNode<T>): ArrayDeque<TreeNode<T>> {
|
||||||
|
val stack = ArrayDeque<TreeNode<T>>()
|
||||||
|
if(node.children.isEmpty()) {
|
||||||
|
return ArrayDeque(listOf(node))
|
||||||
|
}
|
||||||
|
node.children.forEach {
|
||||||
|
stack.addAll(getChildrenStack(it))
|
||||||
|
}
|
||||||
|
stack.addLast(node)
|
||||||
|
return stack
|
||||||
|
}
|
||||||
|
}
|
@ -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"
|
* Tree is iterated by using `Pre-order Traversal Algorithm"
|
||||||
@ -31,10 +33,12 @@ class PreOrderTreeIterator<T>(root: TreeNode<T>) : Iterator<TreeNode<T>> {
|
|||||||
override fun hasNext(): Boolean = stack.isNotEmpty()
|
override fun hasNext(): Boolean = stack.isNotEmpty()
|
||||||
|
|
||||||
override fun next(): TreeNode<T> {
|
override fun next(): TreeNode<T> {
|
||||||
|
println(stack)
|
||||||
val node = stack.removeLast()
|
val node = stack.removeLast()
|
||||||
node.children
|
node.children
|
||||||
.asReversed()
|
.asReversed()
|
||||||
.forEach { stack.addLast(it) }
|
.forEach { stack.addLast(it) }
|
||||||
|
println(stack)
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.github.adriankuta.iterators
|
||||||
|
|
||||||
|
enum class TreeNodeIterators {
|
||||||
|
PreOrder, PostOrder
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
package com.github.adriankuta
|
package com.github.adriankuta
|
||||||
|
|
||||||
|
import com.github.adriankuta.iterators.TreeNodeIterators
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertContentEquals
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertNull
|
import kotlin.test.assertNull
|
||||||
|
|
||||||
@ -46,9 +48,7 @@ class TreeNodeTest {
|
|||||||
"Pretty print test"
|
"Pretty print test"
|
||||||
)
|
)
|
||||||
|
|
||||||
println("Remove: ${curdNode.value}")
|
|
||||||
root.removeChild(curdNode)
|
root.removeChild(curdNode)
|
||||||
println("Remove: ${gingerTeaNode.value}")
|
|
||||||
root.removeChild(gingerTeaNode)
|
root.removeChild(gingerTeaNode)
|
||||||
assertEquals(
|
assertEquals(
|
||||||
"Root\n" +
|
"Root\n" +
|
||||||
@ -87,9 +87,6 @@ class TreeNodeTest {
|
|||||||
curdNode.addChild(yogurtNode)
|
curdNode.addChild(yogurtNode)
|
||||||
curdNode.addChild(lassiNode)
|
curdNode.addChild(lassiNode)
|
||||||
|
|
||||||
println(root.toString())
|
|
||||||
println(curdNode.height())
|
|
||||||
|
|
||||||
root.clear()
|
root.clear()
|
||||||
assertEquals(root.children, emptyList())
|
assertEquals(root.children, emptyList())
|
||||||
assertEquals(beveragesNode.children, emptyList())
|
assertEquals(beveragesNode.children, emptyList())
|
||||||
@ -141,4 +138,43 @@ class TreeNodeTest {
|
|||||||
}
|
}
|
||||||
assertEquals(root.prettyString(), rootExt.prettyString())
|
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() })
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user