|
291 | 291 | " return flatten(left(tree)) + (value(tree), ) + flatten(right(tree))"
|
292 | 292 | ]
|
293 | 293 | },
|
| 294 | + { |
| 295 | + "cell_type": "markdown", |
| 296 | + "id": "d93d4c6e-d88f-49b1-b189-17017c7de51c", |
| 297 | + "metadata": {}, |
| 298 | + "source": [ |
| 299 | + "The implementation of `flatten` would be much simpler if we would use Python `list` rather than `tuple`, but given the fact that we want to program in a functional style, we make sure the data structures are immutable." |
| 300 | + ] |
| 301 | + }, |
| 302 | + { |
| 303 | + "cell_type": "code", |
| 304 | + "execution_count": 21, |
| 305 | + "id": "113acbc3-b18b-4ef5-b993-1ab5d8b3a043", |
| 306 | + "metadata": {}, |
| 307 | + "outputs": [], |
| 308 | + "source": [ |
| 309 | + "def visualize_tree(tree, indent=''):\n", |
| 310 | + " '''Print a visualization of a tree to standard output\n", |
| 311 | + " \n", |
| 312 | + " Parameters\n", |
| 313 | + " ----------\n", |
| 314 | + " tree: tuple[Any, tuple | None, tuple | None] | None\n", |
| 315 | + " binary search tree to visualize\n", |
| 316 | + " '''\n", |
| 317 | + " if is_empty(tree):\n", |
| 318 | + " print(f'{indent}empty tree')\n", |
| 319 | + " else:\n", |
| 320 | + " print(f'{indent}{value(tree)}')\n", |
| 321 | + " if not is_empty(left(tree)):\n", |
| 322 | + " print(f'{indent} left:')\n", |
| 323 | + " visualize_tree(left(tree), indent + ' ')\n", |
| 324 | + " if not is_empty(right(tree)):\n", |
| 325 | + " print(f'{indent} right:')\n", |
| 326 | + " visualize_tree(right(tree), indent + ' ')" |
| 327 | + ] |
| 328 | + }, |
| 329 | + { |
| 330 | + "cell_type": "markdown", |
| 331 | + "id": "fa4074a4-e15b-4388-958e-7497a11eba64", |
| 332 | + "metadata": {}, |
| 333 | + "source": [ |
| 334 | + "# Testing" |
| 335 | + ] |
| 336 | + }, |
294 | 337 | {
|
295 | 338 | "cell_type": "markdown",
|
296 | 339 | "id": "b86c0c7a-d2c2-4e3a-8b70-108868d83f85",
|
|
301 | 344 | },
|
302 | 345 | {
|
303 | 346 | "cell_type": "code",
|
304 |
| - "execution_count": 9, |
| 347 | + "execution_count": 28, |
305 | 348 | "id": "2c595c38-71e1-4df1-8016-99b632373817",
|
306 | 349 | "metadata": {},
|
307 |
| - "outputs": [ |
308 |
| - { |
309 |
| - "data": { |
310 |
| - "text/plain": [ |
311 |
| - "True" |
312 |
| - ] |
313 |
| - }, |
314 |
| - "execution_count": 9, |
315 |
| - "metadata": {}, |
316 |
| - "output_type": "execute_result" |
317 |
| - } |
318 |
| - ], |
| 350 | + "outputs": [], |
319 | 351 | "source": [
|
320 |
| - "is_empty(empty())" |
| 352 | + "assert is_empty(empty()), 'empty tree is not empty'" |
321 | 353 | ]
|
322 | 354 | },
|
323 | 355 | {
|
324 | 356 | "cell_type": "markdown",
|
325 | 357 | "id": "ccd1eec7-7eea-4193-9323-053d1638d3d9",
|
326 | 358 | "metadata": {},
|
327 | 359 | "source": [
|
328 |
| - "Store the successive trees in a list that are obtained by inserting values into it, flatten them and print the result." |
| 360 | + "Store the successive trees in a list that are obtained by inserting values into it, that illustrates that this implementation of binary search trees is indeed persistent, and hence purely functional." |
329 | 361 | ]
|
330 | 362 | },
|
331 | 363 | {
|
332 | 364 | "cell_type": "code",
|
333 |
| - "execution_count": 14, |
| 365 | + "execution_count": 23, |
334 | 366 | "id": "9bf2469e-c918-450e-bae0-86afa77dd371",
|
335 | 367 | "metadata": {},
|
336 | 368 | "outputs": [
|
337 | 369 | {
|
338 | 370 | "name": "stdout",
|
339 | 371 | "output_type": "stream",
|
340 | 372 | "text": [
|
341 |
| - "4 into None\n", |
342 |
| - "1 into (4, None, None)\n", |
343 |
| - "7 into (4, (1, None, None), None)\n", |
344 |
| - "-3 into (4, (1, None, None), (7, None, None))\n", |
345 |
| - "1 into (4, (1, (-3, None, None), None), (7, None, None))\n", |
346 |
| - "8 into (4, (1, (-3, None, None), None), (7, None, None))\n", |
347 |
| - "4 into (4, (1, (-3, None, None), None), (7, None, (8, None, None)))\n", |
348 |
| - "9 into (4, (1, (-3, None, None), None), (7, None, (8, None, None)))\n", |
349 |
| - "-3 into (4, (1, (-3, None, None), None), (7, None, (8, None, (9, None, None))))\n", |
350 | 373 | "None\n",
|
351 |
| - "(4,)\n", |
352 |
| - "(1, 4)\n", |
353 |
| - "(1, 4, 7)\n", |
354 |
| - "(-3, 1, 4, 7)\n", |
355 |
| - "(-3, 1, 4, 7)\n", |
356 |
| - "(-3, 1, 4, 7, 8)\n", |
357 |
| - "(-3, 1, 4, 7, 8)\n", |
358 |
| - "(-3, 1, 4, 7, 8, 9)\n", |
359 |
| - "(-3, 1, 4, 7, 8, 9)\n" |
| 374 | + "(4, None, None)\n", |
| 375 | + "(4, (1, None, None), None)\n", |
| 376 | + "(4, (1, None, None), (7, None, None))\n", |
| 377 | + "(4, (1, (-3, None, None), None), (7, None, None))\n", |
| 378 | + "(4, (1, (-3, None, None), None), (7, None, None))\n", |
| 379 | + "(4, (1, (-3, None, None), None), (7, None, (8, None, None)))\n", |
| 380 | + "(4, (1, (-3, None, None), None), (7, None, (8, None, None)))\n", |
| 381 | + "(4, (1, (-3, None, None), None), (7, None, (8, None, (9, None, None))))\n", |
| 382 | + "(4, (1, (-3, None, None), None), (7, None, (8, None, (9, None, None))))\n" |
360 | 383 | ]
|
361 | 384 | }
|
362 | 385 | ],
|
363 | 386 | "source": [
|
364 | 387 | "new_values = (4, 1, 7, -3, 1, 8, 4, 9, -3)\n",
|
365 | 388 | "trees = [empty()]\n",
|
366 | 389 | "for new_value in new_values:\n",
|
367 |
| - " print(f'{new_value} into {trees[-1]}')\n", |
368 | 390 | " trees.append(insert(trees[-1], new_value))\n",
|
369 | 391 | "for tree in trees:\n",
|
370 |
| - " print(flatten(tree))" |
| 392 | + " print(tree)" |
| 393 | + ] |
| 394 | + }, |
| 395 | + { |
| 396 | + "cell_type": "markdown", |
| 397 | + "id": "c88e781a-303e-4ac4-933c-f9b3d9c39255", |
| 398 | + "metadata": {}, |
| 399 | + "source": [ |
| 400 | + "In order to test the implementation, you should note that when a correct binary search tree is flattened, the resulting tuple ir ordered, i.e, its elements are in ascending order. To test this, we implement the function `is_ordered`." |
371 | 401 | ]
|
372 | 402 | },
|
373 | 403 | {
|
374 | 404 | "cell_type": "code",
|
375 |
| - "execution_count": 14, |
376 |
| - "id": "41b1e508-407c-4fb5-aa40-45943825a7dd", |
| 405 | + "execution_count": 26, |
| 406 | + "id": "d3da91e3-4658-43bc-a980-f611cf65bd35", |
377 | 407 | "metadata": {},
|
378 | 408 | "outputs": [],
|
379 | 409 | "source": [
|
380 |
| - "t = insert(insert(insert(insert(empty(), 3), 5), 1), 2)" |
| 410 | + "def is_ordered(elements):\n", |
| 411 | + " '''Check whether the elements of a tuple are orded\n", |
| 412 | + " \n", |
| 413 | + " Parameters\n", |
| 414 | + " ----------\n", |
| 415 | + " elements: tuple[Any] | None\n", |
| 416 | + " tuple to check\n", |
| 417 | + " \n", |
| 418 | + " Returns\n", |
| 419 | + " -------\n", |
| 420 | + " bool\n", |
| 421 | + " True if the tuple's elements are in order, False otherwise; None, that represents\n", |
| 422 | + " the elements of an empty tree is also consired ordered\n", |
| 423 | + " '''\n", |
| 424 | + " return (elements is None or len(elements) <= 1 or\n", |
| 425 | + " (elements[0] <= elements[1]) and is_ordered(elements[1:])) " |
381 | 426 | ]
|
382 | 427 | },
|
383 | 428 | {
|
384 |
| - "cell_type": "code", |
385 |
| - "execution_count": 15, |
386 |
| - "id": "8b71169d-3660-4024-b23b-1a77037ea922", |
| 429 | + "cell_type": "markdown", |
| 430 | + "id": "e81e0471-68d8-440c-bf74-9d408fbd517d", |
387 | 431 | "metadata": {},
|
388 |
| - "outputs": [ |
389 |
| - { |
390 |
| - "data": { |
391 |
| - "text/plain": [ |
392 |
| - "(1, 2, 3, 5)" |
393 |
| - ] |
394 |
| - }, |
395 |
| - "execution_count": 15, |
396 |
| - "metadata": {}, |
397 |
| - "output_type": "execute_result" |
398 |
| - } |
399 |
| - ], |
400 | 432 | "source": [
|
401 |
| - "flatten(t)" |
| 433 | + "We can now test the implementation." |
402 | 434 | ]
|
403 | 435 | },
|
404 | 436 | {
|
405 | 437 | "cell_type": "code",
|
406 |
| - "execution_count": 20, |
407 |
| - "id": "d3da91e3-4658-43bc-a980-f611cf65bd35", |
| 438 | + "execution_count": 27, |
| 439 | + "id": "7ea1284c-8ca6-49b3-b051-263e3109d0f7", |
408 | 440 | "metadata": {},
|
409 | 441 | "outputs": [],
|
410 | 442 | "source": [
|
411 |
| - "def is_ordered(xs):\n", |
412 |
| - " return len(xs) <= 1 or (xs[0] <= xs[1]) and is_ordered(xs[1:]) " |
| 443 | + "new_values = (4, 1, 7, -3, 1, 8, 4, 9, -3)\n", |
| 444 | + "trees = [empty()]\n", |
| 445 | + "for new_value in new_values:\n", |
| 446 | + " trees.append(insert(trees[-1], new_value))\n", |
| 447 | + "for tree in trees:\n", |
| 448 | + " assert is_ordered(flatten(tree)), f'{tree} is not ordered'" |
| 449 | + ] |
| 450 | + }, |
| 451 | + { |
| 452 | + "cell_type": "markdown", |
| 453 | + "id": "36904405-5769-41db-9e8e-5314d50aa42b", |
| 454 | + "metadata": {}, |
| 455 | + "source": [ |
| 456 | + "Check whether the visualization works as expected." |
413 | 457 | ]
|
414 | 458 | },
|
415 | 459 | {
|
416 | 460 | "cell_type": "code",
|
417 |
| - "execution_count": 10, |
418 |
| - "id": "113acbc3-b18b-4ef5-b993-1ab5d8b3a043", |
| 461 | + "execution_count": 16, |
| 462 | + "id": "41b1e508-407c-4fb5-aa40-45943825a7dd", |
419 | 463 | "metadata": {},
|
420 | 464 | "outputs": [],
|
421 | 465 | "source": [
|
422 |
| - "def visualize_tree(xs, indent=''):\n", |
423 |
| - " if is_empty(xs):\n", |
424 |
| - " print(f'{indent}empty tree')\n", |
425 |
| - " else:\n", |
426 |
| - " print(f'{indent}{value(xs)}')\n", |
427 |
| - " if not is_empty(left(xs)):\n", |
428 |
| - " print(f'{indent} left:')\n", |
429 |
| - " visualize_tree(left(xs), indent + ' ')\n", |
430 |
| - " if not is_empty(right(xs)):\n", |
431 |
| - " print(f'{indent} right:')\n", |
432 |
| - " visualize_tree(right(xs), indent + ' ')" |
| 466 | + "tree = insert(insert(insert(insert(empty(), 3), 5), 1), 2)" |
433 | 467 | ]
|
434 | 468 | },
|
435 | 469 | {
|
436 | 470 | "cell_type": "code",
|
437 |
| - "execution_count": 11, |
| 471 | + "execution_count": 22, |
438 | 472 | "id": "df17e319-80d1-45c1-8fe9-bf81626ea48d",
|
439 | 473 | "metadata": {},
|
440 | 474 | "outputs": [
|
|
453 | 487 | }
|
454 | 488 | ],
|
455 | 489 | "source": [
|
456 |
| - "visualize_tree(t)" |
| 490 | + "visualize_tree(tree)" |
457 | 491 | ]
|
458 | 492 | }
|
459 | 493 | ],
|
|
0 commit comments