"for item, priority in zip(items, priorities):\n",
" print((item, priority))"
]
},
{
"cell_type": "markdown",
"id": "2a348646-7633-4e79-a4ad-9597893c327d",
"metadata": {},
"source": [
"Use the Python [PriorityQueue](https://docs.python.org/3/library/queue.html#queue.PriorityQueue) module to store such values, and then return by _ascending_ order."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "18d02388-dca0-4493-a1c6-9d2c1314683d",
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "b4b91474b8a893af393ecf41a4177229",
"grade": false,
"grade_id": "cell-7a9ba41922a9d48b",
"locked": false,
"schema_version": 3,
"solution": true,
"task": false
},
"tags": []
},
"outputs": [],
"source": [
"q = PriorityQueue()\n",
"\n",
"# YOUR CODE HERE\n",
"raise NotImplementedError()"
]
},
{
"cell_type": "markdown",
"id": "f44ea802-5fbf-404c-8430-0b931da0bf53",
"metadata": {},
"source": [
"Write a similar version that returns the `items` by _descending_ order (we assume `priorities` are always integers)."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9bc92f94-97a1-46fa-813c-63fb6abc9f65",
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "4296a9b681b44c000d6aec878f352558",
"grade": false,
"grade_id": "cell-55279200308121d0",
"locked": false,
"schema_version": 3,
"solution": true,
"task": false
},
"tags": []
},
"outputs": [],
"source": [
"q = PriorityQueue()\n",
"\n",
"# YOUR CODE HERE\n",
"raise NotImplementedError()"
]
},
{
"cell_type": "markdown",
"id": "c2ab7bd0-a237-4755-9421-a2dee82e77a4",
"metadata": {},
"source": [
"## Exercise 2: Implement your own priority queue\n",
"\n",
"Implement your own priority queue class and compare it to the Python module `PriorityQueue` use previously. Use the stack (or the queue) we have seen in the previous lab."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ca96c6ee-54c9-47ba-959e-60c7168256d6",
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "97ee0cb3d80986b98414224fb7f81255",
"grade": false,
"grade_id": "cell-256c1b911658a81f",
"locked": false,
"schema_version": 3,
"solution": true,
"task": false
},
"tags": []
},
"outputs": [],
"source": [
"class MyPriorityQueue():\n",
" # YOUR CODE HERE\n",
" raise NotImplementedError()"
]
},
{
"cell_type": "markdown",
"id": "9e2f1c19-1f64-4de1-b9e8-1ed2e167cf40",
"metadata": {},
"source": [
"Write comparisons with the `PriorityQueue` module:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e86176bf-fb09-44a1-8732-5becb06921af",
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "a7d5a588a04dc75038101a4010a5ad1c",
"grade": false,
"grade_id": "cell-fd82f6f4e92e8816",
"locked": false,
"schema_version": 3,
"solution": true,
"task": false
},
"tags": []
},
"outputs": [],
"source": [
"p1 = PriorityQueue()\n",
"p2 = MyPriorityQueue()\n",
"\n",
"# YOUR CODE HERE\n",
"raise NotImplementedError()"
]
},
{
"cell_type": "markdown",
"id": "9f0d41e9-254a-4121-a209-e751e6122e7c",
"metadata": {
"tags": []
},
"source": [
"## Exercise 3: Tasks scheduler\n",
"\n",
"In this exercise we want to write an algorithm that will schedule some tasks. Think of a tasks as an event with a name (eg `\"Task 1\"`, a `start` time and an `end` time). To keep it simple, we will consider times as `int`. The goal will be to write a scheduler that will decide which task to do, with an important condition: tasks cannot overlap (ie at any given moment, only 1 task can be picked). You'll start by defining a `Task` class and then the `TaskScheduler` class that manages the list of tasks you picked and that do not overlap.\n",
"\n",
"Start by writing the `Task` class and in particular include a way to compare tasks by overriding the [comparison operator](https://docs.python.org/3/library/operator.html):\n",
"\n",
"```python\n",
" def __lt__(self, other):\n",
" return self.start < other.start\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "44aacc95-2aa6-485b-8759-ac292244f290",
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "31d7c78de176602c4028bc2873ba2eaa",
"grade": false,
"grade_id": "cell-8eeb5fa664a2abf2",
"locked": false,
"schema_version": 3,
"solution": true,
"task": false
},
"tags": []
},
"outputs": [],
"source": [
"class Task:\n",
" # YOUR CODE HERE\n",
" raise NotImplementedError()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6430a61e-879d-4c2d-bc92-a6f288786242",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"task1 = Task(\"Task 1\", 1, 4)\n",
"task2 = Task(\"Task 2\", 2, 5)\n",
"assert task1 < task2"
]
},
{
"cell_type": "markdown",
"id": "7563c27b-c412-4899-acb3-57c10f2abb8d",
"metadata": {},
"source": [
"Now write the `TaskScheduler` class. You can use the `PriorityQueue` or your own implementation of a priority queue. Tip: write 3 methods:\n",
"The `heapq` [(doc)](https://docs.python.org/3/library/heapq.html) module provides an efficient implementation of priority queue using the heap sorting algorithm, that use can use instead of the `PriorityQueue` class. Here is an example on how to use the heap. The operations complexity are are:\n",
"- `heapify` $O(n)$ as it find the smallest value (only) to return next\n",
"- `heappop` $O(log(n))$ as it finds again the smallest value (only) to return next, but in an efficient way"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "da1fbbad-7bb6-4f89-a446-bdb308a545ac",
"metadata": {},
"outputs": [],
"source": [
"import heapq\n",
"nums = [10, 20, 5, 7, 9, 15, 3]\n",
"heapq.heapify(nums)\n",
"sorted_list = [heapq.heappop(nums) for _ in range(len(nums))]\n",
"sorted_list"
]
},
{
"cell_type": "markdown",
"id": "327aa702-5699-42ba-96e1-b75079d31050",
"metadata": {},
"source": [
"Write a function `merge_sorted_lists(lists)` that takes a list of sorted lists, and uses `heapq` to merge them into a single sorted list as a result.\n",
"\n",
"1. Use `heapq` to store the first element of each list.\n",
"2. Store each element in the heap as a tuple `(value, list_index, element_index)`:\n",
" - `value` is the element value,\n",
" - `list_index` is the index of the list it comes from,\n",
" - `element_index` is the position of the element in its original list.\n",
"3. At each step, extract the smallest element from the heap and add it to the result list.\n",
"4. Insert the next element from the same list into the heap until all lists are empty."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4b20f11a-47b8-419a-b94a-902943048c76",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"import heapq\n",
"\n",
"def merge(lists):\n",
" min_heap = []\n",
" merged_list = []\n",
"\n",
" for i, lst in enumerate(lists): # each first element in heap\n",
" if lst:\n",
" heapq.heappush(min_heap, (lst[0], i, 0)) # (value, list_index, element_index)\n",
Use the Python [PriorityQueue](https://docs.python.org/3/library/queue.html#queue.PriorityQueue) module to store such values, and then return by _ascending_ order.
Implement your own priority queue class and compare it to the Python module `PriorityQueue` use previously. Use the stack (or the queue) we have seen in the previous lab.
In this exercise we want to write an algorithm that will schedule some tasks. Think of a tasks as an event with a name (eg `"Task 1"`, a `start` time and an `end` time). To keep it simple, we will consider times as `int`. The goal will be to write a scheduler that will decide which task to do, with an important condition: tasks cannot overlap (ie at any given moment, only 1 task can be picked). You'll start by defining a `Task` class and then the `TaskScheduler` class that manages the list of tasks you picked and that do not overlap.
Start by writing the `Task` class and in particular include a way to compare tasks by overriding the [comparison operator](https://docs.python.org/3/library/operator.html):
The `heapq`[(doc)](https://docs.python.org/3/library/heapq.html) module provides an efficient implementation of priority queue using the heap sorting algorithm, that use can use instead of the `PriorityQueue` class. Here is an example on how to use the heap. The operations complexity are are:
-`heapify` $O(n)$ as it find the smallest value (only) to return next
-`heappop` $O(log(n))$ as it finds again the smallest value (only) to return next, but in an efficient way