From f0265f9b3a8a167df26e802c26958d589fc01515 Mon Sep 17 00:00:00 2001 From: Romain Vuillemot <romain.vuillemot@gmail.com> Date: Mon, 2 Dec 2024 11:07:29 +0100 Subject: [PATCH] lab 10 --- labs-solutions/09-trees-exercises.ipynb | 782 ++++++++++++++++++++++++ labs/10-graphs-exercises.ipynb | 500 +++++++++++++++ 2 files changed, 1282 insertions(+) create mode 100644 labs-solutions/09-trees-exercises.ipynb create mode 100644 labs/10-graphs-exercises.ipynb diff --git a/labs-solutions/09-trees-exercises.ipynb b/labs-solutions/09-trees-exercises.ipynb new file mode 100644 index 0000000..3b5708b --- /dev/null +++ b/labs-solutions/09-trees-exercises.ipynb @@ -0,0 +1,782 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "4ef6c0ef-cf70-45dd-af93-5a910c414ea1", + "metadata": {}, + "source": [ + "# UE5 Fundamentals of Algorithms\n", + "# Lab 9: Trees" + ] + }, + { + "cell_type": "markdown", + "id": "34c7a5e4-9f95-48fc-9729-5b0b7c76ea64", + "metadata": {}, + "source": [ + "---" + ] + }, + { + "cell_type": "markdown", + "id": "c62d36f3-db61-40b0-add2-d2da652708fd", + "metadata": {}, + "source": [ + "## Exercise 1: Compare two trees data structures\n", + "\n", + "You are given a tree data structure as a dictionnary, e.g:" + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "id": "58d3c26d-d101-45d3-9283-44427258854b", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "tree_dict = {\n", + " 'a': ['b', 'c'],\n", + " 'b': ['d', 'e'],\n", + " 'c': ['f'],\n", + " 'd': [],\n", + " 'e': [],\n", + " 'f': []\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "134fc918-8d81-43f8-b847-be70b3047d25", + "metadata": {}, + "source": [ + "And another one as an Object:" + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "id": "deea1d47-404d-43df-adee-5c49427598c8", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "class Node:\n", + " def __init__(self, value = None, children = []):\n", + " self.value = value\n", + " self.children = children" + ] + }, + { + "cell_type": "markdown", + "id": "c77a0f57-7f47-4eb7-b673-1972398106c7", + "metadata": {}, + "source": [ + "Implement the following:\n", + "\n", + "1. Use the above data structure to store the first 6 letters of the alphabet in alphabetical order (if the tree is traversed using bfs)\n", + "2. A bfs function to compare the trees (i.e. the bfs function returns the same nodes in the same order)" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "id": "59f3995a-3e79-401b-8813-7543037841b2", + "metadata": { + "nbgrader": { + "grade": false, + "grade_id": "cell-e3c919e88440ce72", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "### BEGIN SOLUTION\n", + "node_d = Node('d')\n", + "node_e = Node('e')\n", + "node_f = Node('f')\n", + "node_b = Node('b', [node_d, node_e])\n", + "node_c = Node('c', [node_f])\n", + "root = Node('a', [node_b, node_c])\n", + "\n", + "def bfs_tree_dict(tree_dict, root):\n", + " queue = [root]\n", + " traversal_order = []\n", + "\n", + " while queue:\n", + " node = queue.pop(0)\n", + " traversal_order.append(node)\n", + " for child in tree_dict.get(node, []):\n", + " queue.append(child)\n", + "\n", + " return traversal_order\n", + "\n", + "def bfs_tree_node(root):\n", + " if root is None:\n", + " return []\n", + "\n", + " queue = [root]\n", + " traversal_order = []\n", + "\n", + " while queue:\n", + " node = queue.pop(0)\n", + " traversal_order.append(node.value)\n", + " for child in node.children:\n", + " queue.append(child)\n", + "\n", + " return traversal_order\n", + "\n", + "assert bfs_tree_dict(tree_dict, 'a') == list(tree_dict.keys())\n", + "assert bfs_tree_node(root) == bfs_tree_dict(tree_dict, 'a')\n", + "### END SOLUTION" + ] + }, + { + "cell_type": "markdown", + "id": "0ee4bcec-c701-4558-b35d-4ce49a953f47", + "metadata": {}, + "source": [ + "## Exercise 2: Return the list of links from a tree\n", + "\n", + "Given the two data structure from the previous exercise (i.e. dict and object), return the list of links of those two trees in the same order and compare them. Return `-1` if the trees have a cycle." + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "id": "f521a89e-c319-4180-94e1-adb1cd7832ad", + "metadata": { + "nbgrader": { + "grade": false, + "grade_id": "cell-53bb2a8f08b5b459", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def get_edges_node(root):\n", + " if root is None:\n", + " return []\n", + "\n", + " edges = []\n", + " visited = set()\n", + " stack = [root]\n", + "\n", + " while stack:\n", + " node = stack.pop(0)\n", + " if node in visited:\n", + " return -1\n", + " visited.add(node)\n", + "\n", + " for child in node.children:\n", + " edges.append([node.value, child.value])\n", + " stack.append(child)\n", + "\n", + " return edges" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "id": "78392fbd-7887-4e91-b006-8785e1d135d4", + "metadata": { + "nbgrader": { + "grade": false, + "grade_id": "cell-d46da0388a47efdc", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def get_edges_dict(tree_dict, start_node):\n", + "### BEGIN SOLUTION\n", + " edges = []\n", + " queue = [start_node]\n", + " visited = set()\n", + "\n", + " while queue:\n", + " parent = queue.pop(0)\n", + "\n", + " if parent in visited:\n", + " continue\n", + " visited.add(parent)\n", + "\n", + " for child in tree_dict.get(parent, []):\n", + " edges.append([parent, child])\n", + " if child not in visited:\n", + " queue.append(child)\n", + "\n", + " return edges\n", + "### END SOLUTION" + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "id": "f711a8a8-420c-4eff-9227-90c9b933bdba", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "assert get_edges_dict(tree_dict, 'a') == get_edges_node(root)" + ] + }, + { + "cell_type": "markdown", + "id": "8b7b3ed0-771b-49b4-b1ca-4d7ffde0cae5", + "metadata": {}, + "source": [ + "## Exercise 3: Calculate the total weight of a weighted tree\n", + "\n", + "Update the two previous data structure to store a weight value. The weight is stored in links and is any numerical value. For the dictionnary, adapt the data structured using named values as below. Provide examples of weighted trees similar as the previous questions (you assign random weights, if no weight then assign `0`)." + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "id": "0780439e-6d76-4576-9669-0c94c8a7b476", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "tree_dict_weight = {\n", + " \"a\": {\"neighbors\": [\"b\", \"c\"]},\n", + " \"b\": {\"neighbors\": [\"d\", \"e\"]},\n", + " \"c\": {\"neighbors\": [\"f\"]},\n", + " \"d\": {\"neighbors\": []},\n", + " \"e\": {\"neighbors\": []},\n", + " \"f\": {\"neighbors\": []}\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "id": "8209cb32-7d73-44a4-af00-85d73a80f5ca", + "metadata": { + "nbgrader": { + "grade": false, + "grade_id": "cell-0ebc501702fdb5a4", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "12" + ] + }, + "execution_count": 58, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "### BEGIN SOLUTION\n", + "class Node_weight:\n", + " def __init__(self, data, weight=0):\n", + " self.data = data\n", + " self.children = []\n", + " self.weight = weight\n", + "\n", + "tree = Node_weight(1)\n", + "child1 = Node_weight(2, weight=5)\n", + "child2 = Node_weight(3, weight=7)\n", + "tree.children = [child1, child2]\n", + "\n", + "def get_tree_edges(root):\n", + " edges = []\n", + " stack = [(root, None)]\n", + "\n", + " while stack:\n", + " node, parent_data = stack.pop()\n", + " \n", + " for child in node.children:\n", + " stack.append((child, node.data))\n", + " edges.append((node.data, child.data, child.weight))\n", + "\n", + " return edges\n", + "\n", + "sum(tpl[2] for tpl in get_tree_edges(tree))\n", + "### END SOLUTION" + ] + }, + { + "cell_type": "markdown", + "id": "6436c778-b2b4-44a1-8998-892cdab9a9e9", + "metadata": {}, + "source": [ + "Write some tests" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "adf4724c-ce18-4f66-8fa2-ac5199a4fd69", + "metadata": { + "nbgrader": { + "grade": false, + "grade_id": "cell-c9a6287bd6ca9388", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "### BEGIN SOLUTION\n", + "### END SOLUTION" + ] + }, + { + "cell_type": "markdown", + "id": "7bc1c52d-1701-47d8-88ee-bc02e0188261", + "metadata": {}, + "source": [ + "## Exercise 4: Check if the tree is an n-ary tree\n", + "\n", + "A $n$-ary tree with $n=2$ is a binary tree. Write solution that are recursive, and for the dict and Node data structures." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "776f8fdd-dd91-4cfc-a239-0a00bceb9e40", + "metadata": { + "nbgrader": { + "grade": false, + "grade_id": "cell-12661c11043349ab", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def is_nary_tree_dict(tree, node, n = 2, visited=None):\n", + "### BEGIN SOLUTION\n", + " if visited is None:\n", + " visited = set()\n", + "\n", + " if node in visited:\n", + " return True\n", + "\n", + " visited.add(node)\n", + " children = tree.get(node, [])\n", + "\n", + " if len(children) > n:\n", + " return False\n", + "\n", + " for child in children:\n", + " if not is_binary_tree(tree, child, n, visited):\n", + " return False\n", + "\n", + " return True\n", + "\n", + "is_binary_tree(tree, \"A\", 2)\n", + "### END SOLUTION" + ] + }, + { + "cell_type": "markdown", + "id": "01df4470-fab0-4cc2-a58b-0c22d4ed5754", + "metadata": {}, + "source": [ + "Write some tests" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "id": "f2ef2bfb-35af-45ed-b526-6a69f8890282", + "metadata": { + "nbgrader": { + "grade": false, + "grade_id": "cell-1eaf29113206c31d", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def is_nary_tree_node(root, n = 2, visited=None):\n", + "### BEGIN SOLUTION\n", + " pass\n", + "### END SOLUTION" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "id": "cd6d9842-f110-46e3-9869-24cfc5f301e7", + "metadata": { + "nbgrader": { + "grade": false, + "grade_id": "cell-b78a8de1ea2ab199", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "### BEGIN SOLUTION\n", + "### END SOLUTION" + ] + }, + { + "cell_type": "markdown", + "id": "9d03a5bf-205f-4a5e-9446-d57b9800e0aa", + "metadata": {}, + "source": [ + "## Exercise BONUS: Update the Node class with the following methods\n", + "\n", + "You may progressively update the class property methods with `Node.your_method`\n" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "id": "3085f09f-5bc2-4bfe-b082-46b1fc579a84", + "metadata": { + "nbgrader": { + "grade": false, + "grade_id": "cell-618403002a124a8b", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def get_children(self): # return all the children of the current node\n", + "### BEGIN SOLUTION\n", + " return [child.value for child in self.children]\n", + "\n", + "Node.get_children = get_children\n", + "assert root.get_children() == [\"b\", \"c\"]\n", + "### END SOLUTION" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "id": "8750c154-28e6-4165-a682-5d3995ead561", + "metadata": { + "nbgrader": { + "grade": false, + "grade_id": "cell-7658fd50d1a6640f", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def is_root(self): # check of the current node is a root node\n", + "### BEGIN SOLUTION\n", + " pass\n", + "### END SOLUTION" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "id": "bd3e2185-8c19-48ed-89e3-ae6499e2acf2", + "metadata": { + "nbgrader": { + "grade": false, + "grade_id": "cell-713bb31725abd453", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def get_nodes(self): # get all the nodes of the tree (or sub-tree)\n", + "### BEGIN SOLUTION\n", + " pass\n", + "### END SOLUTION" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "id": "5a713b70-bcf9-4850-a874-750ca25c2895", + "metadata": { + "nbgrader": { + "grade": false, + "grade_id": "cell-a335b930ac93a5e5", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def get_edges(self): # get all the edges of the tree (or sub-tree)\n", + "### BEGIN SOLUTION\n", + " pass\n", + "### END SOLUTION" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "id": "aa0619f4-758e-4b67-a8f9-edfdc13b109d", + "metadata": { + "nbgrader": { + "grade": false, + "grade_id": "cell-601da6374219c6de", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def get_parent(self): # return the parent of a given node\n", + "### BEGIN SOLUTION\n", + " pass\n", + "### END SOLUTION" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "id": "a4f871d3-4fae-4819-8fe3-675f2f8ea310", + "metadata": { + "nbgrader": { + "grade": false, + "grade_id": "cell-744461e5cdd2c364", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def is_parent(self, node): # check if the parent of a given node\n", + "### BEGIN SOLUTION\n", + " pass\n", + "### END SOLUTION" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "id": "55af73bd-7793-402c-b1aa-cf976420c904", + "metadata": { + "nbgrader": { + "grade": false, + "grade_id": "cell-3d9c70e0373783db", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def get_height(self, parent): # return the height of a node\n", + "### BEGIN SOLUTION\n", + " pass\n", + "### END SOLUTION" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "id": "be881a18-5e7d-44ee-a59d-a3211bc4d9c4", + "metadata": { + "nbgrader": { + "grade": false, + "grade_id": "cell-8df451890eb0851b", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def get_siblings(self): # return all the nodes with the same height\n", + "### BEGIN SOLUTION\n", + " pass\n", + "### END SOLUTION" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "id": "6bc87519-f219-4f42-81d9-bef7c92483ec", + "metadata": { + "nbgrader": { + "grade": false, + "grade_id": "cell-e0f74e8bb091ab18", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def get_leaves(self): # get all the leaves of the sub-tree\n", + "### BEGIN SOLUTION\n", + " pass\n", + "### END SOLUTION" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "id": "1ff5ce8d-4539-4c67-a249-8ce1638fbc37", + "metadata": { + "nbgrader": { + "grade": false, + "grade_id": "cell-05662988e3373818", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def is_leaf(self): # check if a node is a leaf\n", + "### BEGIN SOLUTION\n", + " pass\n", + "### END SOLUTION" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "id": "f4505be1-0f79-40f8-adfd-9bbb184d3671", + "metadata": { + "nbgrader": { + "grade": false, + "grade_id": "cell-8fb25a1f664ec637", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def get_edges(self): # get edges of a sub-tree\n", + "### BEGIN SOLUTION\n", + " pass\n", + "### END SOLUTION" + ] + }, + { + "cell_type": "markdown", + "id": "3fba7abb-00ea-49ff-945e-91bda370d1e6", + "metadata": {}, + "source": [ + "Write tests." + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "id": "acb7b4b0-af3b-42c0-bacb-f97d4fd2b530", + "metadata": { + "nbgrader": { + "grade": false, + "grade_id": "cell-308d6a53c2dc721a", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "### BEGIN SOLUTION\n", + "### END SOLUTION" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "81d762d6-42ca-444d-a633-503880364f11", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/labs/10-graphs-exercises.ipynb b/labs/10-graphs-exercises.ipynb new file mode 100644 index 0000000..61a1428 --- /dev/null +++ b/labs/10-graphs-exercises.ipynb @@ -0,0 +1,500 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "53c1dc9b", + "metadata": {}, + "source": [ + "NAME:" + ] + }, + { + "cell_type": "markdown", + "id": "497036b2-a410-477c-bcfa-e1dd1b02cd8a", + "metadata": {}, + "source": [ + "# UE5 Fundamentals of Algorithms\n", + "# Lab 10: Graphs" + ] + }, + { + "cell_type": "markdown", + "id": "5876dd49-e808-4107-9b93-08ad6600bd34", + "metadata": {}, + "source": [ + "---" + ] + }, + { + "cell_type": "markdown", + "id": "3e08eb9a-9d3d-466a-afbe-aa1219475dc7", + "metadata": {}, + "source": [ + "For the following exercices, your are given a graph data structure as a dictionnary:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f22d7834-bff7-4e23-b15d-4250ce39a1df", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "g = { \"a\" : [\"d\"],\n", + " \"b\" : [\"c\"],\n", + " \"c\" : [\"b\", \"c\", \"d\", \"e\"],\n", + " \"d\" : [\"a\", \"c\"],\n", + " \"e\" : [\"c\"], \n", + " \"f\" : [] \n", + " }" + ] + }, + { + "cell_type": "markdown", + "id": "7c9b9b7f-0292-4761-aa41-0ebe6cfab49c", + "metadata": {}, + "source": [ + "## Exercise 1: Understand the graph properties\n", + "\n", + "Give the graph `g` given previously, answer the following questions:\n", + "\n", + "1. Draw the graph using a node-link diagram\n", + "2. Does it have a cycle?\n", + "3. Is it connected? If not, how many components?\n", + "4. Does it have a self loop?" + ] + }, + { + "cell_type": "markdown", + "id": "613dbe01-f1a1-4811-96f0-fc893cc6ae24", + "metadata": { + "tags": [] + }, + "source": [ + "We will now check the properties programmatically in the next questions." + ] + }, + { + "cell_type": "markdown", + "id": "2d324f2e-25d4-488b-9178-c29f52caee1a", + "metadata": {}, + "source": [ + "## Exercise 2: Check if the graph has a cycle\n", + "\n", + "Here is a `dfs` algorithm for a graph, write a function `has_cycle` to detect if the graph `g` has a cycle." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b9611934-1a07-4cc5-b3be-1b18e6f50e57", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def dfs(graph, start_node):\n", + " visited = set()\n", + " stack = [start_node]\n", + "\n", + " while stack:\n", + " node = stack.pop()\n", + " if node not in visited:\n", + " print(node, end=' ')\n", + " visited.add(node)\n", + " for neighbor in reversed(graph[node]):\n", + " if neighbor not in visited:\n", + " stack.append(neighbor)\n", + " \n", + "dfs(g, 'a') # start from node 'a'." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "17ffa86d-f149-4746-9658-5c6aeb71f6d7", + "metadata": { + "deletable": false, + "nbgrader": { + "cell_type": "code", + "checksum": "3c53848ec68074e3abef68a93bc0699c", + "grade": false, + "grade_id": "cell-fa50a2164fb6d1e6", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "# YOUR CODE HERE\n", + "raise NotImplementedError()" + ] + }, + { + "cell_type": "markdown", + "id": "849df1e9-aef3-4883-a3c0-d7f0e937315e", + "metadata": {}, + "source": [ + "Write tests." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d815ba3f-8dc5-4a2c-a908-4545e66ebbb5", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "assert has_cycle(g)\n", + "assert not has_cycle({'a': []})\n", + "assert has_cycle({'a': ['a']}) " + ] + }, + { + "cell_type": "markdown", + "id": "bad893ca-312e-4500-bc2e-d9420dca47a3", + "metadata": { + "tags": [] + }, + "source": [ + "## Exercise 3: Check if the graph is connected\n", + "\n", + "Check if all nodes can be reached." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "714e9dff-adb1-44d9-a2de-a5eb5fc6f618", + "metadata": { + "deletable": false, + "nbgrader": { + "cell_type": "code", + "checksum": "901a2895481f2c75ff3c71a653a8fc3f", + "grade": false, + "grade_id": "cell-a4d3225ec6fd0d1d", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def is_connected(graph):\n", + " # YOUR CODE HERE\n", + " raise NotImplementedError()" + ] + }, + { + "cell_type": "markdown", + "id": "d63ff45a-76d7-42d1-ae43-045cdc714b92", + "metadata": {}, + "source": [ + "Write tests." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b59faa9a-5ed6-4795-a650-ba0bc4c6b39e", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "assert not is_connected(g)" + ] + }, + { + "cell_type": "markdown", + "id": "05c4b848-67a1-4aa7-9ae6-182ccca5ad82", + "metadata": { + "tags": [] + }, + "source": [ + "## Exercise 4: Check if the graph has self-loop\n", + "\n", + "Check if there is at least a node that links to itself." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ff86ab1e-574f-45d8-b9d7-cd14d7d9e81b", + "metadata": { + "deletable": false, + "nbgrader": { + "cell_type": "code", + "checksum": "3ca6c7ec76afae543761ff6254b0b97c", + "grade": false, + "grade_id": "cell-716f2eec18989a2d", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def has_self_loop(graph):\n", + " # YOUR CODE HERE\n", + " raise NotImplementedError()" + ] + }, + { + "cell_type": "markdown", + "id": "385d5be2-036f-448b-9b34-2a5f478eb9db", + "metadata": { + "tags": [] + }, + "source": [ + "Write tests." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "07f67cfb-3edd-4160-a42e-679f97fedbc8", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "assert has_self_loop(g)" + ] + }, + { + "cell_type": "markdown", + "id": "be1da5d3-b677-41dc-b52a-428e84e834ed", + "metadata": {}, + "source": [ + "## Exercise 5: Use embedded marking for visited nodes\n", + "\n", + "Instead of using an external list to store visited node, use the data structure below that stores the information internally." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fb11aa28-e1a8-4700-99a6-c7f0e8477be8", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "g2 = {\n", + " 'a': {'neighbors': ['d'], 'visited': False},\n", + " 'b': {'neighbors': ['c'], 'visited': False},\n", + " 'c': {'neighbors': ['b', 'c', 'd', 'e'], 'visited': False},\n", + " 'd': {'neighbors': ['a', 'c'], 'visited': False},\n", + " 'e': {'neighbors': ['c'], 'visited': False},\n", + " 'f': {'neighbors': [''], 'visited': False}\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5bcb46e4-d175-4356-b33b-ff44ce7df2a1", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def dfs2(graph, start_node):\n", + " stack = [start_node]\n", + "\n", + " while stack:\n", + " node = stack.pop()\n", + " if not graph[node]['visited']:\n", + " print(node, end=' ')\n", + " graph[node]['visited'] = True\n", + " for neighbor in reversed(graph[node]['neighbors']):\n", + " if neighbor and not graph[neighbor]['visited']:\n", + " stack.append(neighbor)\n", + " \n", + "dfs2(g2, 'a')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e4fcaef5-cfb0-4d10-a8ca-930696b29c89", + "metadata": { + "deletable": false, + "nbgrader": { + "cell_type": "code", + "checksum": "a51b3775bbd811fdc5c3405386189c3f", + "grade": false, + "grade_id": "cell-646e92ff31a3a804", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "# YOUR CODE HERE\n", + "raise NotImplementedError()" + ] + }, + { + "cell_type": "markdown", + "id": "50882bb9-8de8-4e0a-93db-38aedfa77ca0", + "metadata": {}, + "source": [ + "Write tests." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7fb9a85c-976f-4054-948a-a58d6e4504ea", + "metadata": { + "deletable": false, + "nbgrader": { + "cell_type": "code", + "checksum": "d4cf1af31642fc40582135f3e0fc1976", + "grade": false, + "grade_id": "cell-585b0274f5419089", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "# YOUR CODE HERE\n", + "raise NotImplementedError()" + ] + }, + { + "cell_type": "markdown", + "id": "ce9470d2-7b5c-48a9-9ebf-7060a023a379", + "metadata": {}, + "source": [ + "## Exercise 6: Use a Graph POO data structure\n", + "\n", + "Instead of using a Dict, use a POO class (that may use a dict internally) and associated methods to solve the above problems (as new methods of the class)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bcb18a5c-d96b-464e-aa14-bc096f1ecfd4", + "metadata": { + "deletable": false, + "nbgrader": { + "cell_type": "code", + "checksum": "63f06c59eaa1fb2b7995fe5993b99440", + "grade": false, + "grade_id": "cell-1a9fb3e8e3fca660", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "class Graph:\n", + " def __init__(self):\n", + " pass\n", + " def has_cycle(self):\n", + " pass\n", + " def is_connected(self):\n", + " pass\n", + " def has_self_loop(self):\n", + " pass\n", + "# YOUR CODE HERE\n", + "raise NotImplementedError()" + ] + }, + { + "cell_type": "markdown", + "id": "5ad7b301-ef0f-431c-8587-9318d635c05b", + "metadata": { + "nbgrader": { + "grade": false, + "grade_id": "cell-20547345ca6ee2a9", + "locked": false, + "schema_version": 3, + "solution": false, + "task": false + }, + "tags": [] + }, + "source": [ + "Write tests." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5d5fa858-9403-420d-a4e3-d00b90fd0d31", + "metadata": { + "deletable": false, + "nbgrader": { + "cell_type": "code", + "checksum": "6903788b0eae1a94ae12a554805b4a09", + "grade": false, + "grade_id": "cell-573b352161e48cfd", + "locked": false, + "schema_version": 3, + "solution": true, + "task": false + }, + "tags": [] + }, + "outputs": [], + "source": [ + "# YOUR CODE HERE\n", + "raise NotImplementedError()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c097160a-6c52-4caf-9e50-70688ae51106", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} -- GitLab