"We will use the following binary tree data structure (unless specified otherwise):"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2b179632-5d9e-4abd-95c1-abfea9d455df",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"class Node:\n",
" def __init__(self, value):\n",
" self.value = value\n",
" self.left = None\n",
" self.right = None"
]
},
{
"cell_type": "markdown",
"id": "1d18a7cb-9003-4d84-a68d-dfbd8202713b",
"metadata": {},
"source": [
"## Exercise 1: Check if a binary tree is balanced"
]
},
{
"cell_type": "markdown",
"id": "ac3a3e11-4a8d-416c-8b55-3c6a4137a457",
"metadata": {},
"source": [
"Write an **iterative** function that checks if a binary tree is balanced, i.e. the difference between the heights of the left and right subtrees is at most 1.\n",
"\n",
"Tips:\n",
"- Use af dfs traversal approach (using a stack) using a post-order approach (left, right, and root node)\n",
"- For each node, calculate and memorize the current height in a dictionnary\n",
"- Check if the current node is balanced, if not return `False`\n",
"- Mark the node as visited and store its height\n",
"- Return `True` if all the nodes are visited (without an un-balanced situation)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "51a49306-6cb7-4e84-9257-081793657848",
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "87a9e0ddfcedc6d476e6774ce0c52278",
"grade": false,
"grade_id": "cell-9be6329f66aa0822",
"locked": false,
"schema_version": 3,
"solution": true,
"task": false
},
"tags": []
},
"outputs": [],
"source": [
"def is_balanced_ite(root):\n",
" # YOUR CODE HERE\n",
" raise NotImplementedError()\n",
"\n"
]
},
{
"cell_type": "markdown",
"id": "556f6692-1e4f-4f55-adbc-cf373402673d",
"metadata": {},
"source": [
"Compare to the following recursive version:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b7fb2e89-b045-4a46-851e-153c64e0de60",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"def get_height(node):\n",
" if node is None:\n",
" return -1\n",
" left_height = get_height(node.left)\n",
" right_height = get_height(node.right)\n",
" return max(left_height, right_height) + 1\n",
"\n",
"def is_balanced(root):\n",
" # un abre vide (None) est équilibré\n",
" if root is None: \n",
" return True\n",
" return is_balanced(root.right) and is_balanced(root.left) and abs(get_height(root.left) - get_height(root.right)) <= 1\n",
"\n",
"#get_height(racine)\n",
"#is_balanced(racine)"
]
},
{
"cell_type": "markdown",
"id": "00e2ddec-e259-4f8b-a414-a11051672173",
"metadata": {},
"source": [
"Write tests with both balanced and unbalanced trees."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f90da531-0173-429a-a415-923e7b2bf275",
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "9d5e1580d1c78f16d9a187e4f353c99d",
"grade": false,
"grade_id": "cell-62f1e3032591a590",
"locked": false,
"schema_version": 3,
"solution": true,
"task": false
},
"tags": []
},
"outputs": [],
"source": [
"# YOUR CODE HERE\n",
"raise NotImplementedError()"
]
},
{
"cell_type": "markdown",
"id": "09013922-8606-4298-91e5-02da49a8ced2",
"metadata": {},
"source": [
"## Exercise 2: DFS traversal orders\n",
"\n",
"Given the following tree, which type of dfs traversal order you may use to return the number in ascending order?\n",
"\n",
"```\n",
" 1\n",
" / \\\n",
" 2 5\n",
" / \\\n",
"3 4\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "afa39767-9b92-4eb7-8a2c-7b59715153da",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"def inorder_traversal(root):\n",
" if root is not None:\n",
" inorder_traversal(root.left)\n",
" print(root.value, end=' ')\n",
" inorder_traversal(root.right)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e88833c1-3cf0-4751-bf79-d7ba410a3dd2",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"def preorder_traversal(root):\n",
" if root is not None:\n",
" print(root.value, end=' ')\n",
" preorder_traversal(root.left)\n",
" preorder_traversal(root.right)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "fdff0e4c-e6f1-4185-b7dc-92aa3f8f7ccb",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"def postorder_traversal(root):\n",
" if root is not None:\n",
" postorder_traversal(root.left)\n",
" postorder_traversal(root.right)\n",
" print(root.value, end=' ')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "78fbbaa9-a66f-4edc-ad6d-35364efcf83a",
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "8b065502c3c0d81f22e153ccb0bdcf85",
"grade": false,
"grade_id": "cell-525d556fb7dad98a",
"locked": false,
"schema_version": 3,
"solution": true,
"task": false
},
"tags": []
},
"outputs": [],
"source": [
"# YOUR CODE HERE\n",
"raise NotImplementedError()"
]
},
{
"cell_type": "markdown",
"id": "0ab0e8cb-0f07-4df4-a1e1-8934b9fa9de2",
"metadata": {},
"source": [
"Now write the corresponding tree for the 2 other traversal functions to return values in ascending order (i.e. provide a new tree but do not change the functions)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "498cd602-5e9e-456b-b66a-4b289442170f",
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "43158bce133c763a801278ce66e04227",
"grade": false,
"grade_id": "cell-56de47103a5dc76a",
"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": "13dd6b6f-e843-4a92-af0e-2c860d95cf40",
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "8f4024dc6f357c7ea8450e3d5c290030",
"grade": false,
"grade_id": "cell-f407001e56e50590",
"locked": false,
"schema_version": 3,
"solution": true,
"task": false
},
"tags": []
},
"outputs": [],
"source": [
"# YOUR CODE HERE\n",
"raise NotImplementedError()"
]
},
{
"cell_type": "markdown",
"id": "098f76aa-1597-4394-a7d7-564e5e1949cf",
"metadata": {},
"source": [
"## Exercise 3: Check if two binary trees are identical\n",
"\n",
"```\n",
" 1 1\n",
" / \\ / \\\n",
" 2 3 2 3\n",
"```\n",
"\n",
"For the example above, it may return `True`"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "49aa6fce-c267-4ac1-af06-085ab33cfb4f",
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "e3f63d2b59a5d5ccdfcea2a42970fbe7",
"grade": false,
"grade_id": "cell-20f87de8b31f2a3c",
"locked": false,
"schema_version": 3,
"solution": true,
"task": false
},
"tags": []
},
"outputs": [],
"source": [
"def check_equal(p, q):\n",
"# YOUR CODE HERE\n",
"raise NotImplementedError()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d34397b0-e505-410f-9edb-75d6f9f35b32",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"p = Node(1)\n",
"q = Node(1)\n",
"assert check_equal(p, q)"
]
},
{
"cell_type": "markdown",
"id": "8d65c14b",
"metadata": {},
"source": [
"## Exercise 4: Check if a binary tree has a cycle\n",
"\n",
"Write a function to determine if a binary tree contains a cycle (i.e. when a node is revisited during traversal)."
"## Exercise 5: Check if a binary tree is connected\n",
"\n",
"Write a function to determine if a binary is connected to all the nodes of the tree. Warning: will now use a dictionnary data structure to store the tree."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8ba8a250-70f7-4ec8-9deb-eea0b3f34ca3",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"T_dict = {\n",
" '0': ['1', '2'],\n",
" '1': ['4', '5'],\n",
" '2': ['3'],\n",
" '4': [],\n",
" '5': [],\n",
" '3': []\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0460d5e5-d9b1-4418-a58b-0e00a481ed67",
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "8512f8ddd6ccce216feb0f213417c264",
"grade": false,
"grade_id": "cell-bc5d0252ee379402",
"locked": false,
"schema_version": 3,
"solution": true,
"task": false
},
"tags": []
},
"outputs": [],
"source": [
"def is_connected(T_dict):\n",
"# YOUR CODE HERE\n",
"raise NotImplementedError()"
]
},
{
"cell_type": "markdown",
"id": "d8298892-488a-482c-98bd-2a16d02f29a6",
"metadata": {},
"source": [
"Write tests for bot a connected and a non-connected tree."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "55ab4951-be83-48ee-a6c5-85d6e73bdf05",
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "f4dddcceb5343e7311bee83bd4b4396f",
"grade": false,
"grade_id": "cell-135d5364fe4568d7",
"locked": false,
"schema_version": 3,
"solution": true,
"task": false
},
"tags": []
},
"outputs": [],
"source": [
"# YOUR CODE HERE\n",
"raise NotImplementedError()"
]
},
{
"cell_type": "markdown",
"id": "c06c33fb-661b-4a73-84f7-c19c5c157fae",
"metadata": {},
"source": [
"## Exercise 6: Calculate the diameter of a binary tree\n",
"\n",
"To find the diameter of a binary tree, you need to compute the longest path between any two nodes in the tree. This path may or may not pass through the root. Here is a way to calculate the diameter:\n",
"\n",
"1. Calculate the height of the left and right subtrees for each node\n",
"2. Calculate the diameter at each node as the height of left subtree + right subtree\n",
"3. Traverse the tree and keep track of the max diameter encountered\n",
Write an **iterative** function that checks if a binary tree is balanced, i.e. the difference between the heights of the left and right subtrees is at most 1.
Tips:
- Use af dfs traversal approach (using a stack) using a post-order approach (left, right, and root node)
- For each node, calculate and memorize the current height in a dictionnary
- Check if the current node is balanced, if not return `False`
- Mark the node as visited and store its height
- Return `True` if all the nodes are visited (without an un-balanced situation)
Now write the corresponding tree for the 2 other traversal functions to return values in ascending order (i.e. provide a new tree but do not change the functions)
## Exercise 5: Check if a binary tree is connected
Write a function to determine if a binary is connected to all the nodes of the tree. Warning: will now use a dictionnary data structure to store the tree.
## Exercise 6: Calculate the diameter of a binary tree
To find the diameter of a binary tree, you need to compute the longest path between any two nodes in the tree. This path may or may not pass through the root. Here is a way to calculate the diameter:
1. Calculate the height of the left and right subtrees for each node
2. Calculate the diameter at each node as the height of left subtree + right subtree
3. Traverse the tree and keep track of the max diameter encountered