/* * MIT License * * Copyright (c) 2019 norangebit * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ package it.norangeb.algorithms.exam import arrow.core.None import arrow.core.Option import arrow.core.toOption import it.norangeb.algorithms.datastructures.queue.Queue import it.norangeb.algorithms.datastructures.queue.ResizingArrayQueue import kotlin.math.abs class DistanceToLeafTree, V> { private var root: Option> = None operator fun set(key: K, value: V) { root = set(key, value, root) } private fun set( key: K, value: V, node: Option> ): Option> = node.fold( { Node(key, value) }, { when { key == it.key -> it.clone(value = value) key > it.key -> it.clone(right = set(key, value, it.right)) else -> it.clone(left = set(key, value, it.left)) } }).toOption() operator fun get(key: K): Option = get(key, root).map { it.value } private fun get( key: K, node: Option> ): Option> = node.flatMap { when { key == it.key -> node key > it.key -> get(key, it.right) else -> get(key, it.left) } } fun distanceToLeaf(key: K): Option = get(key, root).map { if (it.isLeaf()) 0 else distanceToLeaf(it) } private fun distanceToLeaf(node: Node): Int { val toExplore: Queue, Int>> = ResizingArrayQueue() node.left.map { toExplore.enqueue(Pair(it, 1)) } node.right.map { toExplore.enqueue(Pair(it, 1)) } while (!toExplore.isEmpty()) { toExplore.dequeue().map { elem -> if (elem.first.isLeaf()) return elem.second elem.first.left.map { toExplore.enqueue(Pair(it, elem.second + 1)) } elem.first.right.map { toExplore.enqueue(Pair(it, elem.second + 1)) } } } return -1 } private data class Node( val key: K, val value: V, val left: Option> = None, val right: Option> = None ) { fun clone( key: K = this.key, value: V = this.value, left: Option> = this.left, right: Option> = this.right ) = Node(key, value, left, right) fun isLeaf() = left == None && right == None } }