Skip to content

Commit b273462

Browse files
committed
add tree node and binary tree learning files
1 parent 80a289d commit b273462

File tree

4 files changed

+1006
-0
lines changed

4 files changed

+1006
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,339 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "a961f6a6",
6+
"metadata": {},
7+
"source": [
8+
"# Learn Binary Tree\n",
9+
"## Resource from:\n",
10+
"### https://www.baeldung.com/kotlin/binary-tree\n",
11+
"### https://stackoverflow.com/questions/4965335/how-to-print-binary-tree-diagram-in-java"
12+
]
13+
},
14+
{
15+
"cell_type": "code",
16+
"execution_count": 11,
17+
"id": "cd60f598",
18+
"metadata": {},
19+
"outputs": [],
20+
"source": [
21+
"/**\n",
22+
" * An ADT for a binary search tree.\n",
23+
" * Note that this data type is neither immutable nor thread safe.\n",
24+
" */\n",
25+
"class Node(\n",
26+
" var key: Int,\n",
27+
" var left: Node? = null,\n",
28+
" var right: Node? = null\n",
29+
") {\n",
30+
" /**\n",
31+
" * Return a node with given value. If no such node exists, return null.\n",
32+
" * @param value\n",
33+
" */\n",
34+
" fun find(value: Int): Node? = when {\n",
35+
" this.key > value -> left?.find(value)\n",
36+
" this.key < value -> right?.find(value)\n",
37+
" else -> this\n",
38+
" }\n",
39+
"\n",
40+
" /**\n",
41+
" * Insert a given value into the tree.\n",
42+
" * After insertion, the tree should contain a node with the given value.\n",
43+
" * If the tree already contains the given value, nothing is performed.\n",
44+
" * @param value\n",
45+
" */\n",
46+
" fun insert(value: Int) {\n",
47+
" if (value > this.key) {\n",
48+
" if (this.right == null) {\n",
49+
" this.right = Node(value)\n",
50+
" } else {\n",
51+
" this.right?.insert(value)\n",
52+
" }\n",
53+
" } else if (value < this.key) {\n",
54+
" if (this.left == null) {\n",
55+
" this.left = Node(value)\n",
56+
" } else {\n",
57+
" this.left?.insert(value)\n",
58+
" }\n",
59+
" }\n",
60+
" }\n",
61+
"\n",
62+
" /**\n",
63+
" * Delete the value from the given tree. If the tree does not contain the value, the tree remains unchanged.\n",
64+
" * @param value\n",
65+
" */\n",
66+
" fun delete(value: Int) {\n",
67+
" when {\n",
68+
" value > key -> scan(value, this.right, this)\n",
69+
" value < key -> scan(value, this.left, this)\n",
70+
" else -> removeNode(this, null)\n",
71+
" }\n",
72+
" }\n",
73+
"\n",
74+
" /**\n",
75+
" * Scan the tree in the search of the given value.\n",
76+
" * @param value\n",
77+
" * @param node sub-tree that potentially might contain the sought value\n",
78+
" * @param parent node's parent\n",
79+
" */\n",
80+
" private fun scan(value: Int, node: Node?, parent: Node?) {\n",
81+
" if (node == null) {\n",
82+
" System.out.println(\"value \" + value\n",
83+
" + \" seems not present in the tree.\")\n",
84+
" return\n",
85+
" }\n",
86+
" when {\n",
87+
" value > node.key -> scan(value, node.right, node)\n",
88+
" value < node.key -> scan(value, node.left, node)\n",
89+
" value == node.key -> removeNode(node, parent)\n",
90+
" }\n",
91+
"\n",
92+
" }\n",
93+
"\n",
94+
" /**\n",
95+
" * Remove the node.\n",
96+
" *\n",
97+
" * Removal process depends on how many children the node has.\n",
98+
" *\n",
99+
" * @param node node that is to be removed\n",
100+
" * @param parent parent of the node to be removed\n",
101+
" */\n",
102+
" private fun removeNode(node: Node, parent: Node?) {\n",
103+
" node.left?.let { leftChild ->\n",
104+
" run {\n",
105+
" node.right?.let {\n",
106+
" removeTwoChildNode(node)\n",
107+
" } ?: removeSingleChildNode(node, leftChild)\n",
108+
" }\n",
109+
" } ?: run {\n",
110+
" node.right?.let { rightChild -> removeSingleChildNode(node, rightChild) } ?: removeNoChildNode(node, parent)\n",
111+
" }\n",
112+
"\n",
113+
"\n",
114+
" }\n",
115+
"\n",
116+
" /**\n",
117+
" * Remove the node without children.\n",
118+
" * @param node\n",
119+
" * @param parent\n",
120+
" */\n",
121+
" private fun removeNoChildNode(node: Node, parent: Node?) {\n",
122+
" parent?.let { p ->\n",
123+
" if (node == p.left) {\n",
124+
" p.left = null\n",
125+
" } else if (node == p.right) {\n",
126+
" p.right = null\n",
127+
" }\n",
128+
" } ?: throw IllegalStateException(\n",
129+
" \"Can not remove the root node without child nodes\")\n",
130+
"\n",
131+
" }\n",
132+
"\n",
133+
" /**\n",
134+
" * Remove a node that has two children.\n",
135+
" *\n",
136+
" * The process of elimination is to find the biggest key in the left sub-tree and replace the key of the\n",
137+
" * node that is to be deleted with that key.\n",
138+
" */\n",
139+
" private fun removeTwoChildNode(node: Node) {\n",
140+
" val leftChild = node.left!!\n",
141+
" leftChild.right?.let {\n",
142+
" val maxParent = findParentOfMaxChild(leftChild)\n",
143+
" maxParent.right?.let {\n",
144+
" node.key = it.key\n",
145+
" maxParent.right = null\n",
146+
" } ?: throw IllegalStateException(\"Node with max child must have the right child!\")\n",
147+
"\n",
148+
" } ?: run {\n",
149+
" node.key = leftChild.key\n",
150+
" node.left = leftChild.left\n",
151+
" }\n",
152+
"\n",
153+
" }\n",
154+
"\n",
155+
" /**\n",
156+
" * Return a node whose right child contains the biggest value in the given sub-tree.\n",
157+
" * Assume that the node n has a non-null right child.\n",
158+
" *\n",
159+
" * @param n\n",
160+
" */\n",
161+
" private fun findParentOfMaxChild(n: Node): Node {\n",
162+
" return n.right?.let { r -> r.right?.let { findParentOfMaxChild(r) } ?: n }\n",
163+
" ?: throw IllegalArgumentException(\"Right child must be non-null\")\n",
164+
"\n",
165+
" }\n",
166+
"\n",
167+
" /**\n",
168+
" * Remove a parent that has only one child.\n",
169+
" * Removal is effectively is just coping the data from the child parent to the parent parent.\n",
170+
" * @param parent Node to be deleted. Assume that it has just one child\n",
171+
" * @param child Assume it is a child of the parent\n",
172+
" */\n",
173+
" private fun removeSingleChildNode(parent: Node, child: Node) {\n",
174+
" parent.key = child.key\n",
175+
" parent.left = child.left\n",
176+
" parent.right = child.right\n",
177+
" }\n",
178+
"\n",
179+
" fun visit(): Array<Int> {\n",
180+
" val a = left?.visit() ?: emptyArray()\n",
181+
" val b = right?.visit() ?: emptyArray()\n",
182+
" return a + arrayOf(key) + b\n",
183+
" }\n",
184+
"}"
185+
]
186+
},
187+
{
188+
"cell_type": "code",
189+
"execution_count": 12,
190+
"id": "55499b3a",
191+
"metadata": {},
192+
"outputs": [],
193+
"source": [
194+
"class BTreePrinter {\n",
195+
" fun printNode(root: Node?) {\n",
196+
" val maxLevel = maxLevel(root)\n",
197+
" printNodeInternal(listOf(root), 1, maxLevel)\n",
198+
" }\n",
199+
"\n",
200+
" private fun printNodeInternal(\n",
201+
" nodes: List<Node?>,\n",
202+
" level: Int,\n",
203+
" maxLevel: Int\n",
204+
" ) {\n",
205+
" if (nodes.isEmpty() || isAllElementsNull(nodes)) return\n",
206+
" val floor = maxLevel - level\n",
207+
" val edgeLines = 2.0.pow((floor - 1).coerceAtLeast(0).toDouble()).toInt()\n",
208+
" val firstSpaces = 2.0.pow(floor.toDouble()).toInt() - 1\n",
209+
" val betweenSpaces = 2.0.pow((floor + 1).toDouble()).toInt() - 1\n",
210+
" printWhitespaces(firstSpaces)\n",
211+
" val newNodes: MutableList<Node?> = ArrayList()\n",
212+
" for (node in nodes) {\n",
213+
" if (node != null) {\n",
214+
" print(node.key)\n",
215+
" newNodes.add(node.left)\n",
216+
" newNodes.add(node.right)\n",
217+
" } else {\n",
218+
" newNodes.add(null)\n",
219+
" newNodes.add(null)\n",
220+
" print(\" \")\n",
221+
" }\n",
222+
" printWhitespaces(betweenSpaces)\n",
223+
" }\n",
224+
" println(\"\")\n",
225+
" for (i in 1..edgeLines) {\n",
226+
" for (j in nodes.indices) {\n",
227+
" printWhitespaces(firstSpaces - i)\n",
228+
" if (nodes[j] == null) {\n",
229+
" printWhitespaces(edgeLines + edgeLines + i + 1)\n",
230+
" continue\n",
231+
" }\n",
232+
" if (nodes[j]!!.left != null) print(\"/\") else printWhitespaces(1)\n",
233+
" printWhitespaces(i + i - 1)\n",
234+
" if (nodes[j]!!.right != null) print(\"\\\\\") else printWhitespaces(1)\n",
235+
" printWhitespaces(edgeLines + edgeLines - i)\n",
236+
" }\n",
237+
" println(\"\")\n",
238+
" }\n",
239+
" printNodeInternal(newNodes, level + 1, maxLevel)\n",
240+
" }\n",
241+
"\n",
242+
" private fun printWhitespaces(count: Int) {\n",
243+
" for (i in 0 until count) print(\" \")\n",
244+
" }\n",
245+
"\n",
246+
" private fun maxLevel(node: Node?): Int {\n",
247+
" return if (node == null) 0 else Math.max(maxLevel(node.left), maxLevel(node.right)) + 1\n",
248+
" }\n",
249+
"\n",
250+
" private fun <T> isAllElementsNull(list: List<T?>): Boolean {\n",
251+
" for (`object` in list) {\n",
252+
" if (`object` != null) return false\n",
253+
" }\n",
254+
" return true\n",
255+
" }\n",
256+
"}"
257+
]
258+
},
259+
{
260+
"cell_type": "code",
261+
"execution_count": 38,
262+
"id": "109cd95e",
263+
"metadata": {},
264+
"outputs": [
265+
{
266+
"name": "stdout",
267+
"output_type": "stream",
268+
"text": [
269+
"Node with value 4 [left = 1, right = 5]\n",
270+
"Delete node with key = 3\n",
271+
"Tree content after the node elimination: 1, 2, 3, 4, 5, 6, 7\n"
272+
]
273+
}
274+
],
275+
"source": [
276+
"val tree = Node(4)\n",
277+
"val keys = arrayOf(1, 2, 3, 4, 5, 6, 7)\n",
278+
"\n",
279+
"for (key in keys) {\n",
280+
" tree.insert(key)\n",
281+
"}\n",
282+
"\n",
283+
"val node = tree.find(4)!!\n",
284+
"println(\"Node with value ${node.key} [left = ${node.left?.key}, right = ${node.right?.key}]\")\n",
285+
"println(\"Delete node with key = 3\")\n",
286+
"//node.delete(3)\n",
287+
"print(\"Tree content after the node elimination: \")\n",
288+
"println(tree.visit().joinToString { it.toString() })"
289+
]
290+
},
291+
{
292+
"cell_type": "code",
293+
"execution_count": 39,
294+
"id": "3d25e7a8",
295+
"metadata": {},
296+
"outputs": [
297+
{
298+
"name": "stdout",
299+
"output_type": "stream",
300+
"text": [
301+
" 4 \n",
302+
" / \\ \n",
303+
" / \\ \n",
304+
" / \\ \n",
305+
" / \\ \n",
306+
" 1 5 \n",
307+
" \\ \\ \n",
308+
" \\ \\ \n",
309+
" 2 6 \n",
310+
" \\ \\ \n",
311+
" 3 7 \n",
312+
" \n"
313+
]
314+
}
315+
],
316+
"source": [
317+
"BTreePrinter().printNode(tree)"
318+
]
319+
}
320+
],
321+
"metadata": {
322+
"kernelspec": {
323+
"display_name": "Kotlin",
324+
"language": "kotlin",
325+
"name": "kotlin"
326+
},
327+
"language_info": {
328+
"codemirror_mode": "text/x-kotlin",
329+
"file_extension": ".kt",
330+
"mimetype": "text/x-kotlin",
331+
"name": "kotlin",
332+
"nbconvert_exporter": "",
333+
"pygments_lexer": "kotlin",
334+
"version": "1.6.20-dev-6372"
335+
}
336+
},
337+
"nbformat": 4,
338+
"nbformat_minor": 5
339+
}

0 commit comments

Comments
 (0)