Skip to content

Commit

Permalink
add tree node and binary tree learning files
Browse files Browse the repository at this point in the history
  • Loading branch information
indramahkota committed Jan 2, 2022
1 parent 80a289d commit b273462
Show file tree
Hide file tree
Showing 4 changed files with 1,006 additions and 0 deletions.
339 changes: 339 additions & 0 deletions .ipynb_checkpoints/Binary Tree-checkpoint.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,339 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "a961f6a6",
"metadata": {},
"source": [
"# Learn Binary Tree\n",
"## Resource from:\n",
"### https://www.baeldung.com/kotlin/binary-tree\n",
"### https://stackoverflow.com/questions/4965335/how-to-print-binary-tree-diagram-in-java"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "cd60f598",
"metadata": {},
"outputs": [],
"source": [
"/**\n",
" * An ADT for a binary search tree.\n",
" * Note that this data type is neither immutable nor thread safe.\n",
" */\n",
"class Node(\n",
" var key: Int,\n",
" var left: Node? = null,\n",
" var right: Node? = null\n",
") {\n",
" /**\n",
" * Return a node with given value. If no such node exists, return null.\n",
" * @param value\n",
" */\n",
" fun find(value: Int): Node? = when {\n",
" this.key > value -> left?.find(value)\n",
" this.key < value -> right?.find(value)\n",
" else -> this\n",
" }\n",
"\n",
" /**\n",
" * Insert a given value into the tree.\n",
" * After insertion, the tree should contain a node with the given value.\n",
" * If the tree already contains the given value, nothing is performed.\n",
" * @param value\n",
" */\n",
" fun insert(value: Int) {\n",
" if (value > this.key) {\n",
" if (this.right == null) {\n",
" this.right = Node(value)\n",
" } else {\n",
" this.right?.insert(value)\n",
" }\n",
" } else if (value < this.key) {\n",
" if (this.left == null) {\n",
" this.left = Node(value)\n",
" } else {\n",
" this.left?.insert(value)\n",
" }\n",
" }\n",
" }\n",
"\n",
" /**\n",
" * Delete the value from the given tree. If the tree does not contain the value, the tree remains unchanged.\n",
" * @param value\n",
" */\n",
" fun delete(value: Int) {\n",
" when {\n",
" value > key -> scan(value, this.right, this)\n",
" value < key -> scan(value, this.left, this)\n",
" else -> removeNode(this, null)\n",
" }\n",
" }\n",
"\n",
" /**\n",
" * Scan the tree in the search of the given value.\n",
" * @param value\n",
" * @param node sub-tree that potentially might contain the sought value\n",
" * @param parent node's parent\n",
" */\n",
" private fun scan(value: Int, node: Node?, parent: Node?) {\n",
" if (node == null) {\n",
" System.out.println(\"value \" + value\n",
" + \" seems not present in the tree.\")\n",
" return\n",
" }\n",
" when {\n",
" value > node.key -> scan(value, node.right, node)\n",
" value < node.key -> scan(value, node.left, node)\n",
" value == node.key -> removeNode(node, parent)\n",
" }\n",
"\n",
" }\n",
"\n",
" /**\n",
" * Remove the node.\n",
" *\n",
" * Removal process depends on how many children the node has.\n",
" *\n",
" * @param node node that is to be removed\n",
" * @param parent parent of the node to be removed\n",
" */\n",
" private fun removeNode(node: Node, parent: Node?) {\n",
" node.left?.let { leftChild ->\n",
" run {\n",
" node.right?.let {\n",
" removeTwoChildNode(node)\n",
" } ?: removeSingleChildNode(node, leftChild)\n",
" }\n",
" } ?: run {\n",
" node.right?.let { rightChild -> removeSingleChildNode(node, rightChild) } ?: removeNoChildNode(node, parent)\n",
" }\n",
"\n",
"\n",
" }\n",
"\n",
" /**\n",
" * Remove the node without children.\n",
" * @param node\n",
" * @param parent\n",
" */\n",
" private fun removeNoChildNode(node: Node, parent: Node?) {\n",
" parent?.let { p ->\n",
" if (node == p.left) {\n",
" p.left = null\n",
" } else if (node == p.right) {\n",
" p.right = null\n",
" }\n",
" } ?: throw IllegalStateException(\n",
" \"Can not remove the root node without child nodes\")\n",
"\n",
" }\n",
"\n",
" /**\n",
" * Remove a node that has two children.\n",
" *\n",
" * The process of elimination is to find the biggest key in the left sub-tree and replace the key of the\n",
" * node that is to be deleted with that key.\n",
" */\n",
" private fun removeTwoChildNode(node: Node) {\n",
" val leftChild = node.left!!\n",
" leftChild.right?.let {\n",
" val maxParent = findParentOfMaxChild(leftChild)\n",
" maxParent.right?.let {\n",
" node.key = it.key\n",
" maxParent.right = null\n",
" } ?: throw IllegalStateException(\"Node with max child must have the right child!\")\n",
"\n",
" } ?: run {\n",
" node.key = leftChild.key\n",
" node.left = leftChild.left\n",
" }\n",
"\n",
" }\n",
"\n",
" /**\n",
" * Return a node whose right child contains the biggest value in the given sub-tree.\n",
" * Assume that the node n has a non-null right child.\n",
" *\n",
" * @param n\n",
" */\n",
" private fun findParentOfMaxChild(n: Node): Node {\n",
" return n.right?.let { r -> r.right?.let { findParentOfMaxChild(r) } ?: n }\n",
" ?: throw IllegalArgumentException(\"Right child must be non-null\")\n",
"\n",
" }\n",
"\n",
" /**\n",
" * Remove a parent that has only one child.\n",
" * Removal is effectively is just coping the data from the child parent to the parent parent.\n",
" * @param parent Node to be deleted. Assume that it has just one child\n",
" * @param child Assume it is a child of the parent\n",
" */\n",
" private fun removeSingleChildNode(parent: Node, child: Node) {\n",
" parent.key = child.key\n",
" parent.left = child.left\n",
" parent.right = child.right\n",
" }\n",
"\n",
" fun visit(): Array<Int> {\n",
" val a = left?.visit() ?: emptyArray()\n",
" val b = right?.visit() ?: emptyArray()\n",
" return a + arrayOf(key) + b\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "55499b3a",
"metadata": {},
"outputs": [],
"source": [
"class BTreePrinter {\n",
" fun printNode(root: Node?) {\n",
" val maxLevel = maxLevel(root)\n",
" printNodeInternal(listOf(root), 1, maxLevel)\n",
" }\n",
"\n",
" private fun printNodeInternal(\n",
" nodes: List<Node?>,\n",
" level: Int,\n",
" maxLevel: Int\n",
" ) {\n",
" if (nodes.isEmpty() || isAllElementsNull(nodes)) return\n",
" val floor = maxLevel - level\n",
" val edgeLines = 2.0.pow((floor - 1).coerceAtLeast(0).toDouble()).toInt()\n",
" val firstSpaces = 2.0.pow(floor.toDouble()).toInt() - 1\n",
" val betweenSpaces = 2.0.pow((floor + 1).toDouble()).toInt() - 1\n",
" printWhitespaces(firstSpaces)\n",
" val newNodes: MutableList<Node?> = ArrayList()\n",
" for (node in nodes) {\n",
" if (node != null) {\n",
" print(node.key)\n",
" newNodes.add(node.left)\n",
" newNodes.add(node.right)\n",
" } else {\n",
" newNodes.add(null)\n",
" newNodes.add(null)\n",
" print(\" \")\n",
" }\n",
" printWhitespaces(betweenSpaces)\n",
" }\n",
" println(\"\")\n",
" for (i in 1..edgeLines) {\n",
" for (j in nodes.indices) {\n",
" printWhitespaces(firstSpaces - i)\n",
" if (nodes[j] == null) {\n",
" printWhitespaces(edgeLines + edgeLines + i + 1)\n",
" continue\n",
" }\n",
" if (nodes[j]!!.left != null) print(\"/\") else printWhitespaces(1)\n",
" printWhitespaces(i + i - 1)\n",
" if (nodes[j]!!.right != null) print(\"\\\\\") else printWhitespaces(1)\n",
" printWhitespaces(edgeLines + edgeLines - i)\n",
" }\n",
" println(\"\")\n",
" }\n",
" printNodeInternal(newNodes, level + 1, maxLevel)\n",
" }\n",
"\n",
" private fun printWhitespaces(count: Int) {\n",
" for (i in 0 until count) print(\" \")\n",
" }\n",
"\n",
" private fun maxLevel(node: Node?): Int {\n",
" return if (node == null) 0 else Math.max(maxLevel(node.left), maxLevel(node.right)) + 1\n",
" }\n",
"\n",
" private fun <T> isAllElementsNull(list: List<T?>): Boolean {\n",
" for (`object` in list) {\n",
" if (`object` != null) return false\n",
" }\n",
" return true\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 38,
"id": "109cd95e",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Node with value 4 [left = 1, right = 5]\n",
"Delete node with key = 3\n",
"Tree content after the node elimination: 1, 2, 3, 4, 5, 6, 7\n"
]
}
],
"source": [
"val tree = Node(4)\n",
"val keys = arrayOf(1, 2, 3, 4, 5, 6, 7)\n",
"\n",
"for (key in keys) {\n",
" tree.insert(key)\n",
"}\n",
"\n",
"val node = tree.find(4)!!\n",
"println(\"Node with value ${node.key} [left = ${node.left?.key}, right = ${node.right?.key}]\")\n",
"println(\"Delete node with key = 3\")\n",
"//node.delete(3)\n",
"print(\"Tree content after the node elimination: \")\n",
"println(tree.visit().joinToString { it.toString() })"
]
},
{
"cell_type": "code",
"execution_count": 39,
"id": "3d25e7a8",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" 4 \n",
" / \\ \n",
" / \\ \n",
" / \\ \n",
" / \\ \n",
" 1 5 \n",
" \\ \\ \n",
" \\ \\ \n",
" 2 6 \n",
" \\ \\ \n",
" 3 7 \n",
" \n"
]
}
],
"source": [
"BTreePrinter().printNode(tree)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Kotlin",
"language": "kotlin",
"name": "kotlin"
},
"language_info": {
"codemirror_mode": "text/x-kotlin",
"file_extension": ".kt",
"mimetype": "text/x-kotlin",
"name": "kotlin",
"nbconvert_exporter": "",
"pygments_lexer": "kotlin",
"version": "1.6.20-dev-6372"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Loading

0 comments on commit b273462

Please sign in to comment.