Skip to content

Commit 3292452

Browse files
committed
some updates to BST notebook
1 parent d632995 commit 3292452

File tree

1 file changed

+114
-106
lines changed

1 file changed

+114
-106
lines changed

implementations/Data Structure - Binary Search Trees.ipynb

Lines changed: 114 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -179,21 +179,21 @@
179179
"\n",
180180
"> The trace of a traversal is called a sequentialisation of the tree. The traversal trace is a list of each visited root. No one sequentialisation according to pre-, in- or post-order describes the underlying tree uniquely. Given a tree with distinct elements, either pre-order or post-order paired with in-order is sufficient to describe the tree uniquely. ([Wikipedia](https://en.wikipedia.org/wiki/Tree_traversal#In-order_(LNR)))\n",
181181
"\n",
182-
"Note that pre/in/post order traversals can be used to implement depth first searches, while level-order traversals can be used to implement breadth first searches. Orderings may be reversed by visiting the right child before the left. Depth-first traversals can be implemented iteratively using a stack or recursively (implicitly using the call stack):"
182+
"The most straightforward way to implement pre/in/post-order traversals uses recursion. Note that below, we can easily change from pre- to in- or post- order by simply changing where we call to `print()`, and can reverse the order by swapping the left and right:"
183183
]
184184
},
185185
{
186186
"cell_type": "code",
187-
"execution_count": 3,
187+
"execution_count": 21,
188188
"metadata": {},
189189
"outputs": [
190190
{
191191
"name": "stdout",
192192
"output_type": "stream",
193193
"text": [
194-
"0 1 3 4 2 5 6 \n",
195-
"--------------\n",
196-
"0 1 3 4 2 5 6 "
194+
"Pre-order: 0 1 3 4 2 5 6 \n",
195+
"In-order: 3 1 4 0 5 2 6 \n",
196+
"Post-order: 3 4 1 5 6 2 0 \n"
197197
]
198198
}
199199
],
@@ -206,73 +206,118 @@
206206
" / \\ / \\ \n",
207207
" 3 4 5 6 \n",
208208
"\"\"\"\n",
209-
"\n",
210209
"def pre_order_recursive(node: TreeNode):\n",
211-
" if not node:\n",
212-
" return\n",
213-
" print(node.val, end =\" \")\n",
214-
" pre_order_recursive(node.left) if node.left else None\n",
215-
" pre_order_recursive(node.right) if node.right else None\n",
210+
" if not node: return\n",
211+
" print(node.val, end=\" \")\n",
212+
" pre_order_recursive(node.left)\n",
213+
" pre_order_recursive(node.right) \n",
214+
"print(f\"Pre-order:\", end=\" \")\n",
216215
"pre_order_recursive(root)\n",
216+
"print(\" \")\n",
217217
"\n",
218-
"print(\"\\n\"+(\"-\"*14))\n",
219218
"\n",
220-
"def pre_order_recursive(tree: List[int], i: int):\n",
221-
" if not (0 <= i <=len(tree)-1):\n",
222-
" return\n",
223-
" print(tree[i], end =\" \")\n",
224-
" pre_order_recursive(tree, 2*i+1) if 2*i+1 < len(tree) else None\n",
225-
" pre_order_recursive(tree, 2*i+2) if 2*i+2 < len(tree) else None\n",
226-
"pre_order_recursive(tree_as_arr, 0)"
219+
"def in_order_recursive(node: TreeNode):\n",
220+
" if not node: return\n",
221+
" in_order_recursive(node.left)\n",
222+
" print(node.val, end=\" \")\n",
223+
" in_order_recursive(node.right)\n",
224+
"print(f\"In-order:\", end=\" \")\n",
225+
"in_order_recursive(root)\n",
226+
"print(\" \")\n",
227+
"\n",
228+
"def post_order_recursive(node: TreeNode):\n",
229+
" if not node: return\n",
230+
" post_order_recursive(node.left)\n",
231+
" post_order_recursive(node.right)\n",
232+
" print(node.val, end=\" \")\n",
233+
"print(f\"Post-order:\", end=\" \")\n",
234+
"post_order_recursive(root)\n",
235+
"print(\" \")\n"
236+
]
237+
},
238+
{
239+
"cell_type": "markdown",
240+
"metadata": {},
241+
"source": [
242+
"Traversals can also be implemented explicitly using a stack. Iterative versions are not as straightforward and make for great interview questions:"
227243
]
228244
},
229245
{
230246
"cell_type": "code",
231-
"execution_count": 4,
247+
"execution_count": 51,
232248
"metadata": {},
233249
"outputs": [
234250
{
235251
"name": "stdout",
236252
"output_type": "stream",
237253
"text": [
238-
"0 1 3 4 2 5 6 \n",
239-
"--------------\n",
240-
"0 1 3 4 2 5 6 "
254+
"Pre-order: [0, 1, 3, 4, 2, 5, 6]\n",
255+
"In-order: [3, 1, 4, 0, 5, 2, 6]\n",
256+
"Post-order: [3, 4, 1, 5, 6, 2, 0]\n"
241257
]
242258
}
243259
],
244260
"source": [
261+
"\"\"\"\n",
262+
" 0\n",
263+
" / \\\n",
264+
" 1 2\n",
265+
" / \\ / \\ \n",
266+
" 3 4 5 6 \n",
267+
"\n",
268+
"\"\"\"\n",
269+
"\n",
245270
"def pre_order_iterative(node: TreeNode):\n",
271+
" traversal = []\n",
246272
" stack = [node]\n",
247273
" while stack:\n",
248274
" curr = stack.pop()\n",
249-
" print(curr.val, end =\" \")\n",
250-
" # Note that right is pushed first when using a stack explicitly,\n",
251-
" # causing it to be evaluated after left.\n",
252-
" stack.append(curr.right) if curr.right else None \n",
253-
" stack.append(curr.left) if curr.left else None\n",
254-
"pre_order_iterative(root)\n",
255-
"\n",
256-
"print(\"\\n\"+(\"-\"*14))\n",
257-
"\n",
258-
"def pre_order_iterative(tree: List[int]):\n",
259-
" if not tree:\n",
260-
" return\n",
261-
" stack = [0]\n",
262-
" while stack:\n",
263-
" i = stack.pop()\n",
264-
" print(i, end =\" \")\n",
265-
" stack.append(2*i+2) if 2*i+2 < len(tree) else None \n",
266-
" stack.append(2*i+1) if 2*i+1 < len(tree) else None\n",
267-
"pre_order_iterative(tree_as_arr)"
275+
" if curr:\n",
276+
" traversal.append(curr.val)\n",
277+
" stack.append(curr.right)\n",
278+
" stack.append(curr.left)\n",
279+
" return traversal\n",
280+
"print(f\"Pre-order: {pre_order_iterative(root)}\") \n",
281+
"\n",
282+
"def in_order_iterative(node: TreeNode):\n",
283+
" traversal = []\n",
284+
" stack = []\n",
285+
" while node or stack:\n",
286+
" if node:\n",
287+
" stack.append(node)\n",
288+
" node = node.left\n",
289+
" else:\n",
290+
" node = stack.pop()\n",
291+
" traversal.append(node.val)\n",
292+
" node = node.right\n",
293+
" return traversal \n",
294+
"print(f\"In-order: {in_order_iterative(root)}\")\n",
295+
"\n",
296+
"def post_order_iterative(node: TreeNode):\n",
297+
" traversal = []\n",
298+
" stack = []\n",
299+
" prev_node = None\n",
300+
" while stack or node:\n",
301+
" if node:\n",
302+
" stack.append(node)\n",
303+
" node = node.left\n",
304+
" else:\n",
305+
" peek = stack[-1] \n",
306+
" if peek.right and prev_node != peek.right:\n",
307+
" node = peek.right\n",
308+
" else:\n",
309+
" traversal.append(peek.val)\n",
310+
" prev_node = stack.pop()\n",
311+
" return traversal\n",
312+
" \n",
313+
"print(f\"Post-order: {post_order_iterative(root)}\")"
268314
]
269315
},
270316
{
271317
"cell_type": "markdown",
272318
"metadata": {},
273319
"source": [
274-
"Note that in the above, we can easily change from pre- to in- or post- order by simply reordering the calls to \n",
275-
"`print()` and visitng the children."
320+
"Level order traversal is implemented iteratively, but using a queue (most easily via `collections.deque()` in Python), and can be used for breadth-first searches:"
276321
]
277322
},
278323
{
@@ -284,66 +329,51 @@
284329
"name": "stdout",
285330
"output_type": "stream",
286331
"text": [
287-
"3 1 4 0 5 2 6 "
332+
"0 1 2 3 4 5 6 "
288333
]
289334
}
290335
],
291336
"source": [
292-
"def in_order_recursive(node: TreeNode):\n",
293-
" if not node:\n",
294-
" return\n",
295-
" in_order_recursive(node.left) if node.left else None\n",
296-
" print(node.val, end =\" \")\n",
297-
" in_order_recursive(node.right) if node.right else None\n",
298-
"in_order_recursive(root)"
337+
"from collections import deque\n",
338+
"\n",
339+
"def level_order_iterative(node: TreeNode):\n",
340+
" q = deque([node])\n",
341+
" while q:\n",
342+
" curr = q.popleft()\n",
343+
" print(curr.val, end =\" \")\n",
344+
" q.append(curr.left) if curr.left else None\n",
345+
" q.append(curr.right) if curr.right else None \n",
346+
"level_order_iterative(root)"
299347
]
300348
},
301349
{
302350
"cell_type": "markdown",
303351
"metadata": {},
304352
"source": [
305-
"Level order traversal is implemented iteratively, but using a queue (most easily via `collections.deque()` in Python):"
353+
"Also, remember that each type of traversal can be implemented using an array instead of a node type if given, though this tends to be more wasteful if the BST isn't complete:"
306354
]
307355
},
308356
{
309357
"cell_type": "code",
310-
"execution_count": 6,
358+
"execution_count": 52,
311359
"metadata": {},
312360
"outputs": [
313361
{
314362
"name": "stdout",
315363
"output_type": "stream",
316364
"text": [
317-
"0 1 2 3 4 5 6 \n",
318-
"--------------\n",
319-
"0 1 2 3 4 5 6 "
365+
"0 1 3 4 2 5 6 "
320366
]
321367
}
322368
],
323369
"source": [
324-
"from collections import deque\n",
325-
"\n",
326-
"def level_order_iterative(node: TreeNode):\n",
327-
" q = deque([node])\n",
328-
" while q:\n",
329-
" curr = q.popleft()\n",
330-
" print(curr.val, end =\" \")\n",
331-
" q.append(curr.left) if curr.left else None\n",
332-
" q.append(curr.right) if curr.right else None \n",
333-
"level_order_iterative(root)\n",
334-
"\n",
335-
"print(\"\\n\"+(\"-\"*14))\n",
336-
"\n",
337-
"def level_order_iterative(tree: List[int]):\n",
338-
" if not tree:\n",
370+
"def pre_order_arr(tree: List[int], i: int):\n",
371+
" if not (0 <= i <=len(tree)-1):\n",
339372
" return\n",
340-
" q = deque([0])\n",
341-
" while q:\n",
342-
" i = q.popleft()\n",
343-
" print(i, end =\" \")\n",
344-
" q.append(2*i+1) if 2*i+1 < len(tree) else None\n",
345-
" q.append(2*i+2) if 2*i+2 < len(tree) else None \n",
346-
"level_order_iterative(tree_as_arr)"
373+
" print(tree[i], end =\" \")\n",
374+
" pre_order_arr(tree, 2*i+1)\n",
375+
" pre_order_arr(tree, 2*i+2)\n",
376+
"pre_order_arr(tree_as_arr, 0)"
347377
]
348378
},
349379
{
@@ -376,17 +406,9 @@
376406
},
377407
{
378408
"cell_type": "code",
379-
"execution_count": 16,
409+
"execution_count": null,
380410
"metadata": {},
381-
"outputs": [
382-
{
383-
"name": "stdout",
384-
"output_type": "stream",
385-
"text": [
386-
"3 1 4 0 5 2 6 "
387-
]
388-
}
389-
],
411+
"outputs": [],
390412
"source": [
391413
"\"\"\"\n",
392414
" 0\n",
@@ -439,7 +461,7 @@
439461
},
440462
{
441463
"cell_type": "code",
442-
"execution_count": 17,
464+
"execution_count": null,
443465
"metadata": {},
444466
"outputs": [],
445467
"source": [
@@ -499,18 +521,9 @@
499521
},
500522
{
501523
"cell_type": "code",
502-
"execution_count": 24,
524+
"execution_count": null,
503525
"metadata": {},
504-
"outputs": [
505-
{
506-
"name": "stdout",
507-
"output_type": "stream",
508-
"text": [
509-
"1\n",
510-
"8\n"
511-
]
512-
}
513-
],
526+
"outputs": [],
514527
"source": [
515528
"def bst_min(node):\n",
516529
" if not node:\n",
@@ -541,11 +554,6 @@
541554
"- If `n` has no right child, search upwards until we reach a node `l` who is the left of child of its parent; `l.parent` is the successor."
542555
]
543556
},
544-
{
545-
"cell_type": "markdown",
546-
"metadata": {},
547-
"source": []
548-
},
549557
{
550558
"cell_type": "markdown",
551559
"metadata": {},

0 commit comments

Comments
 (0)