August 27, 2024

P66 - Layout a binary tree (3).

Yet another layout strategy is shown in the illustration below. This tree can be constructed with "nkmcaedgupq".toList().toTree().

Binary tree

The method yields a very compact layout while maintaining a certain symmetry in every node. Find out the rules and write the corresponding method. Hint: Consider the horizontal distance between a node and its successor nodes.

How tight can you pack together two subtrees to construct the combined binary tree? Use the same conventions as in problem P64 and P65. Note: This is a difficult problem. Don't give up too early!

> Node('a', Node('b', End, Node('c')), Node('d')).layoutBinaryTree3()
T[2,1]('a T[1,2]('b . T[2,3]('c . .)) T[3,2]('d . .))

Which layout do you like most?

kotlin

package org.kotlin99.binarytrees

import com.natpryce.hamkrest.assertion.assertThat
import com.natpryce.hamkrest.equalTo
import org.junit.Test
import org.kotlin99.binarytrees.P64Test.Companion.toPrettyString
import org.kotlin99.binarytrees.Tree.End
import org.kotlin99.binarytrees.Tree.Node

fun <T> Tree<T>.layout3(parentX: Int? = null, shiftFromParent: Int = 0, y: Int = 1): Tree<Positioned<T>> {
    return when (this) {
        End        -> End
        is Node<T> -> {
            fun haveNoPositionOverlap(tree1: Tree<Positioned<*>>, tree2: Tree<Positioned<*>>): Boolean =
                (tree1.nodes().map { it.value.point }.intersect(tree2.nodes().map { it.value.point })).isEmpty()

            var shift = 1
            while (shift < 100) {
                var x = parentX?.plus(shiftFromParent)
                val positionedLeft = left.layout3(x, -shift, y + 1)

                if (parentX == null && positionedLeft is Node<Positioned<T>>) {
                    x = positionedLeft.value.point.x + shift
                } else if (parentX == null) {
                    x = 1
                }

                val positionedRight = right.layout3(x, shift, y + 1)

                if (haveNoPositionOverlap(positionedLeft, positionedRight)) {
                    return Node(Positioned(value, x!!, y), positionedLeft, positionedRight)
                }

                shift += 1
            }
            throw IllegalStateException()
        }
    }
}


class P66Test {

    @Test fun `layout binary tree (3)`() {
        assertThat(
            Node("a").layout3().toPrettyString(),
            equalTo("""
                | 012
                |0···
                |1·a·
                |2···
            """.trimMargin()))

        assertThat(
            Node("a", Node("b")).layout3().toPrettyString(),
            equalTo("""
                | 0123
                |0····
                |1··a·
                |2·b··
                |3····
            """.trimMargin()))

        assertThat(
            Node("a", Node("b", Node("c"))).layout3().toPrettyString(),
            equalTo("""
                | 01234
                |0·····
                |1···a·
                |2··b··
                |3·c···
                |4·····
                """.trimMargin()))

        assertThat(
            Node("a", Node("b", Node("c", Node("d")))).layout3().toPrettyString(),
            equalTo("""
                | 012345
                |0······
                |1····a·
                |2···b··
                |3··c···
                |4·d····
                |5······
            """.trimMargin()))

        assertThat(
            Node("a", End, Node("b", End, Node("c"))).layout3().toPrettyString(),
            equalTo("""
                | 01234
                |0·····
                |1·a···
                |2··b··
                |3···c·
                |4·····
            """.trimMargin()))

        assertThat(
            Node("a", Node("b", End, Node("d")), Node("c")).layout3().toPrettyString(),
            equalTo("""
                | 01234
                |0·····
                |1··a··
                |2·b·c·
                |3··d··
                |4·····
            """.trimMargin()))

        assertThat(
            Node("a", Node("b", Node("d"), Node("e")), Node("c", Node("f"), Node("g"))).layout3().toPrettyString(),
            equalTo("""
                | 012345678
                |0·········
                |1····a····
                |2··b···c··
                |3·d·e·f·g·
                |4·········
            """.trimMargin()))
    }

    @Test fun `illustration example`() {
        assertThat(
            "nkmcaedgupq".toList().toTree().layout3().toPrettyString(),
            equalTo("""
                | 012345678
                |0·········
                |1·····n···
                |2···k···u·
                |3··c·m·p··
                |4·a·e···q·
                |5··d·g····
                |6·········
            """.trimMargin()))
    }
}
Be first to comment
Leave a reply