feat: stack-safe traversal + lazy Sequence + navigation/functional extensions

Core additive work for v3.4 (non-breaking):

- Rewrite nodeCount(), height(), clear() and the post-order iterator iteratively
  so deep/degenerate trees no longer throw StackOverflowError (verified to 50k deep).
- Add lazy Sequence traversal: asSequence(order), pre/post/levelOrderSequence().
- Add navigation extensions: isLeaf, degree, root(), ancestors(), siblings(),
  leaves(), descendants().
- Add functional extensions: findNode, filterNodes, anyNode, allNodes, countNodes,
  foldNodes, mapValues, deepCopy, structurallyEquals (all stack-safe).
- Add tests for stack-safety, the new APIs, and previously-uncovered
  height/depth/nodeCount/path (incl. exception paths). 40 tests green on JVM.
This commit is contained in:
2026-06-06 13:35:39 +02:00
parent 6de95f7976
commit c45c5b7afa
10 changed files with 473 additions and 29 deletions

View File

@@ -0,0 +1,46 @@
package com.github.adriankuta.datastructure.tree
import com.github.adriankuta.datastructure.tree.iterators.TreeNodeIterators
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
class TreeNodeSequenceTest {
private fun sample() = tree(1) {
child(2) {
child(4)
child(5)
}
child(3) {
child(6)
}
}
@Test
fun preOrderSequence() =
assertContentEquals(listOf(1, 2, 4, 5, 3, 6), sample().preOrderSequence().map { it.value }.toList())
@Test
fun postOrderSequence() =
assertContentEquals(listOf(4, 5, 2, 6, 3, 1), sample().postOrderSequence().map { it.value }.toList())
@Test
fun levelOrderSequence() =
assertContentEquals(listOf(1, 2, 3, 4, 5, 6), sample().levelOrderSequence().map { it.value }.toList())
@Test
fun asSequenceDefaultsToPreOrder() =
assertContentEquals(listOf(1, 2, 4, 5, 3, 6), sample().asSequence().map { it.value }.toList())
@Test
fun asSequenceHonorsExplicitOrder() =
assertContentEquals(
listOf(1, 2, 3, 4, 5, 6),
sample().asSequence(TreeNodeIterators.LevelOrder).map { it.value }.toList(),
)
@Test
fun sequenceShortCircuitsLazily() =
assertEquals(4, sample().preOrderSequence().map { it.value }.first { it == 4 })
}