|
179 | 179 | "\n", |
180 | 180 | "> 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", |
181 | 181 | "\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:" |
183 | 183 | ] |
184 | 184 | }, |
185 | 185 | { |
186 | 186 | "cell_type": "code", |
187 | | - "execution_count": 3, |
| 187 | + "execution_count": 21, |
188 | 188 | "metadata": {}, |
189 | 189 | "outputs": [ |
190 | 190 | { |
191 | 191 | "name": "stdout", |
192 | 192 | "output_type": "stream", |
193 | 193 | "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" |
197 | 197 | ] |
198 | 198 | } |
199 | 199 | ], |
|
206 | 206 | " / \\ / \\ \n", |
207 | 207 | " 3 4 5 6 \n", |
208 | 208 | "\"\"\"\n", |
209 | | - "\n", |
210 | 209 | "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", |
216 | 215 | "pre_order_recursive(root)\n", |
| 216 | + "print(\" \")\n", |
217 | 217 | "\n", |
218 | | - "print(\"\\n\"+(\"-\"*14))\n", |
219 | 218 | "\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:" |
227 | 243 | ] |
228 | 244 | }, |
229 | 245 | { |
230 | 246 | "cell_type": "code", |
231 | | - "execution_count": 4, |
| 247 | + "execution_count": 51, |
232 | 248 | "metadata": {}, |
233 | 249 | "outputs": [ |
234 | 250 | { |
235 | 251 | "name": "stdout", |
236 | 252 | "output_type": "stream", |
237 | 253 | "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" |
241 | 257 | ] |
242 | 258 | } |
243 | 259 | ], |
244 | 260 | "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", |
245 | 270 | "def pre_order_iterative(node: TreeNode):\n", |
| 271 | + " traversal = []\n", |
246 | 272 | " stack = [node]\n", |
247 | 273 | " while stack:\n", |
248 | 274 | " 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)}\")" |
268 | 314 | ] |
269 | 315 | }, |
270 | 316 | { |
271 | 317 | "cell_type": "markdown", |
272 | 318 | "metadata": {}, |
273 | 319 | "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:" |
276 | 321 | ] |
277 | 322 | }, |
278 | 323 | { |
|
284 | 329 | "name": "stdout", |
285 | 330 | "output_type": "stream", |
286 | 331 | "text": [ |
287 | | - "3 1 4 0 5 2 6 " |
| 332 | + "0 1 2 3 4 5 6 " |
288 | 333 | ] |
289 | 334 | } |
290 | 335 | ], |
291 | 336 | "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)" |
299 | 347 | ] |
300 | 348 | }, |
301 | 349 | { |
302 | 350 | "cell_type": "markdown", |
303 | 351 | "metadata": {}, |
304 | 352 | "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:" |
306 | 354 | ] |
307 | 355 | }, |
308 | 356 | { |
309 | 357 | "cell_type": "code", |
310 | | - "execution_count": 6, |
| 358 | + "execution_count": 52, |
311 | 359 | "metadata": {}, |
312 | 360 | "outputs": [ |
313 | 361 | { |
314 | 362 | "name": "stdout", |
315 | 363 | "output_type": "stream", |
316 | 364 | "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 " |
320 | 366 | ] |
321 | 367 | } |
322 | 368 | ], |
323 | 369 | "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", |
339 | 372 | " 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)" |
347 | 377 | ] |
348 | 378 | }, |
349 | 379 | { |
|
376 | 406 | }, |
377 | 407 | { |
378 | 408 | "cell_type": "code", |
379 | | - "execution_count": 16, |
| 409 | + "execution_count": null, |
380 | 410 | "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": [], |
390 | 412 | "source": [ |
391 | 413 | "\"\"\"\n", |
392 | 414 | " 0\n", |
|
439 | 461 | }, |
440 | 462 | { |
441 | 463 | "cell_type": "code", |
442 | | - "execution_count": 17, |
| 464 | + "execution_count": null, |
443 | 465 | "metadata": {}, |
444 | 466 | "outputs": [], |
445 | 467 | "source": [ |
|
499 | 521 | }, |
500 | 522 | { |
501 | 523 | "cell_type": "code", |
502 | | - "execution_count": 24, |
| 524 | + "execution_count": null, |
503 | 525 | "metadata": {}, |
504 | | - "outputs": [ |
505 | | - { |
506 | | - "name": "stdout", |
507 | | - "output_type": "stream", |
508 | | - "text": [ |
509 | | - "1\n", |
510 | | - "8\n" |
511 | | - ] |
512 | | - } |
513 | | - ], |
| 526 | + "outputs": [], |
514 | 527 | "source": [ |
515 | 528 | "def bst_min(node):\n", |
516 | 529 | " if not node:\n", |
|
541 | 554 | "- 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." |
542 | 555 | ] |
543 | 556 | }, |
544 | | - { |
545 | | - "cell_type": "markdown", |
546 | | - "metadata": {}, |
547 | | - "source": [] |
548 | | - }, |
549 | 557 | { |
550 | 558 | "cell_type": "markdown", |
551 | 559 | "metadata": {}, |
|
0 commit comments