Skip to content
Snippets Groups Projects
Commit e4e9d146 authored by Romain Vuillemot's avatar Romain Vuillemot
Browse files

Update 04-priority-queues-exercises.ipynb

parent d9daf73e
Branches
No related tags found
No related merge requests found
%% Cell type:markdown id:994d4d0c tags: %% Cell type:markdown id:b805152f tags:
NAME: NAME:
%% Cell type:markdown id:651a2e17-2fe1-41c7-be26-a7d3b40f9277 tags: %% Cell type:markdown id:651a2e17-2fe1-41c7-be26-a7d3b40f9277 tags:
# UE5 Fundamentals of Algorithms # UE5 Fundamentals of Algorithms
# Lab 4: Priority queues # Lab 4: Priority queues
%% Cell type:markdown id:dd4f535a-2401-45c6-9d4a-ca8f146aa9c9 tags: %% Cell type:markdown id:dd4f535a-2401-45c6-9d4a-ca8f146aa9c9 tags:
--- ---
%% Cell type:markdown id:615a1282-53cf-4610-bddd-2a3ba105e5bf tags: %% Cell type:markdown id:615a1282-53cf-4610-bddd-2a3ba105e5bf tags:
<details style="border: 1px"> <details style="border: 1px">
<summary> How to use those notebooks</summary> <summary> How to use those notebooks</summary>
For each of the following questions: For each of the following questions:
- In the `# YOUR CODE HERE` cell, remove `raise NotImplementedError()` to write your code - In the `# YOUR CODE HERE` cell, remove `raise NotImplementedError()` to write your code
- Write an example of use of your code or make sure the given examples and tests pass - Write an example of use of your code or make sure the given examples and tests pass
- Add extra tests in the `#Tests` cell - Add extra tests in the `#Tests` cell
</details> </details>
%% Cell type:markdown id:b93b7332-5a40-4a85-b505-83835d68fe67 tags: %% Cell type:markdown id:b93b7332-5a40-4a85-b505-83835d68fe67 tags:
## Exercise 1: How to use a priority queue ## Exercise 1: How to use a priority queue
Your are given a list of elements (`items`) and a matching list of priorities (`priorities`) as follows: Your are given a list of elements (`items`) and a matching list of priorities (`priorities`) as follows:
%% Cell type:code id:b91e0762-b158-44b1-850e-2987d7206b2b tags: %% Cell type:code id:b91e0762-b158-44b1-850e-2987d7206b2b tags:
``` python ``` python
items = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] items = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
priorities = [2, 1, 3, 3, 0, 1, 1, 2] priorities = [2, 1, 3, 3, 0, 1, 1, 2]
for item, priority in zip(items, priorities): for item, priority in zip(items, priorities):
print((item, priority)) print((item, priority))
``` ```
%% Cell type:markdown id:2a348646-7633-4e79-a4ad-9597893c327d tags: %% Cell type:markdown id:2a348646-7633-4e79-a4ad-9597893c327d tags:
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. 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 id:18d02388-dca0-4493-a1c6-9d2c1314683d tags: %% Cell type:code id:18d02388-dca0-4493-a1c6-9d2c1314683d tags:
``` python ``` python
q = PriorityQueue() q = PriorityQueue()
# YOUR CODE HERE # YOUR CODE HERE
raise NotImplementedError() raise NotImplementedError()
``` ```
%% Cell type:markdown id:f44ea802-5fbf-404c-8430-0b931da0bf53 tags: %% Cell type:markdown id:f44ea802-5fbf-404c-8430-0b931da0bf53 tags:
Write a similar version that returns the `items` by _descending_ order (we assume `priorities` are always integers). Write a similar version that returns the `items` by _descending_ order (we assume `priorities` are always integers).
%% Cell type:code id:9bc92f94-97a1-46fa-813c-63fb6abc9f65 tags: %% Cell type:code id:9bc92f94-97a1-46fa-813c-63fb6abc9f65 tags:
``` python ``` python
q = PriorityQueue() q = PriorityQueue()
# YOUR CODE HERE # YOUR CODE HERE
raise NotImplementedError() raise NotImplementedError()
``` ```
%% Cell type:markdown id:c2ab7bd0-a237-4755-9421-a2dee82e77a4 tags: %% Cell type:markdown id:c2ab7bd0-a237-4755-9421-a2dee82e77a4 tags:
## Exercise 2: Implement your own priority queue ## Exercise 2: Implement your own priority queue
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. Implement your own priority queue class and compare it to the Python module `PriorityQueue` used previously. To write the class, you may re-use the stack (or the queue) classes we have seen previously.
%% Cell type:code id:ca96c6ee-54c9-47ba-959e-60c7168256d6 tags: %% Cell type:code id:ca96c6ee-54c9-47ba-959e-60c7168256d6 tags:
``` python ``` python
class MyPriorityQueue(): class MyPriorityQueue():
# YOUR CODE HERE # YOUR CODE HERE
raise NotImplementedError() raise NotImplementedError()
``` ```
%% Cell type:markdown id:9e2f1c19-1f64-4de1-b9e8-1ed2e167cf40 tags: %% Cell type:markdown id:9e2f1c19-1f64-4de1-b9e8-1ed2e167cf40 tags:
Write comparisons with the `PriorityQueue` module: Write code that compare the results with the `PriorityQueue` module:
%% Cell type:code id:e86176bf-fb09-44a1-8732-5becb06921af tags: %% Cell type:code id:e86176bf-fb09-44a1-8732-5becb06921af tags:
``` python ``` python
p1 = PriorityQueue() p1 = PriorityQueue()
p2 = MyPriorityQueue() p2 = MyPriorityQueue()
# YOUR CODE HERE # YOUR CODE HERE
raise NotImplementedError() raise NotImplementedError()
``` ```
%% Cell type:markdown id:9f0d41e9-254a-4121-a209-e751e6122e7c tags: %% Cell type:markdown id:9f0d41e9-254a-4121-a209-e751e6122e7c tags:
## Exercise 3: Tasks scheduler ## Exercise 3: Tasks scheduler
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. In this exercise we want to write an algorithm that will schedule some tasks. Think of a task 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 from the ones that are added, 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): Start by writing the `Task` class with its properties, and include a way to compare tasks by `start` value by overriding the [comparison operator](https://docs.python.org/3/library/operator.html):
```python ```python
def __lt__(self, other): def __lt__(self, other):
return self.start < other.start return self.start < other.start
``` ```
%% Cell type:code id:44aacc95-2aa6-485b-8759-ac292244f290 tags: %% Cell type:code id:44aacc95-2aa6-485b-8759-ac292244f290 tags:
``` python ``` python
class Task: class Task:
# YOUR CODE HERE # YOUR CODE HERE
raise NotImplementedError() raise NotImplementedError()
``` ```
%% Cell type:code id:6430a61e-879d-4c2d-bc92-a6f288786242 tags: %% Cell type:code id:6430a61e-879d-4c2d-bc92-a6f288786242 tags:
``` python ``` python
task1 = Task("Task 1", 1, 4) task1 = Task("Task 1", 1, 4)
task2 = Task("Task 2", 2, 5) task2 = Task("Task 2", 2, 5)
assert task1 < task2 assert task1 < task2
``` ```
%% Cell type:markdown id:7563c27b-c412-4899-acb3-57c10f2abb8d tags: %% Cell type:markdown id:7563c27b-c412-4899-acb3-57c10f2abb8d tags:
Now write the `TaskScheduler` class. You can use the `PriorityQueue` or your own implementation of a priority queue. Tip: write 3 methods: Now write the `TaskScheduler` class. You can use the `PriorityQueue` or your own implementation of a priority queue. Tip: write 3 methods that:
1. add a task 1. add a task and use the **start time as priority**
2. check if overlapping 2. check if overlapping
3. return the non-overlapping tasks 3. return the list of non-overlapping tasks
%% Cell type:code id:6e9d6120-ffb9-4a2f-9fb6-e3c0761ecf75 tags: %% Cell type:code id:6e9d6120-ffb9-4a2f-9fb6-e3c0761ecf75 tags:
``` python ``` python
from queue import PriorityQueue from queue import PriorityQueue
class TaskScheduler: class TaskScheduler:
# YOUR CODE HERE # YOUR CODE HERE
raise NotImplementedError() raise NotImplementedError()
``` ```
%% Cell type:code id:558776cd-9f8f-404e-bc7f-803c4fbbae55 tags: %% Cell type:code id:558776cd-9f8f-404e-bc7f-803c4fbbae55 tags:
``` python ``` python
# Usage example # Usage example
s = TaskScheduler() s = TaskScheduler()
t1 = Task("Task 1", 1, 4) t1 = Task("Task 1", 1, 4)
t2 = Task("Task 2", 2, 5) # overlap t2 = Task("Task 2", 2, 5) # overlap
t3 = Task("Task 3", 5, 6) t3 = Task("Task 3", 5, 6)
s.put(t1) s.put(t1)
s.put(t2) # cannot add (overlap) s.put(t2) # cannot add (overlap)
s.put(t3) s.put(t3)
for task in s.get(): for task in s.get():
print(f"{task.name}: [{task.start}, {task.end}]") print(f"{task.name}: [{task.start}, {task.end}]")
``` ```
%% Cell type:code id:14c5196d-d45e-4314-9678-60548fe2f811 tags: %% Cell type:code id:14c5196d-d45e-4314-9678-60548fe2f811 tags:
``` python ``` python
# Tests # Tests
s = TaskScheduler() s = TaskScheduler()
assert s.get() == [] assert s.get() == []
``` ```
%% Cell type:markdown id:2911284c-7c5b-4c65-a426-dac028d6bd4f tags: %% Cell type:markdown id:2911284c-7c5b-4c65-a426-dac028d6bd4f tags:
## Exercise 4: Merge sorted lists (using heaps) ## Exercise 4: Merge sorted lists (using heaps)
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: 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 can be used instead of the `PriorityQueue` class. The operations complexity are are:
- `heapify` $O(n)$ as it find the smallest value (only) to return next - `heapify` (equivalent to put) $O(n)$ as it finds 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 - `heappop` (equivalent to get) $O(log(n))$ as it finds again the smallest value (only) to return next, but in an efficient way
%% Cell type:code id:da1fbbad-7bb6-4f89-a446-bdb308a545ac tags: %% Cell type:code id:da1fbbad-7bb6-4f89-a446-bdb308a545ac tags:
``` python ``` python
import heapq import heapq
nums = [10, 20, 5, 7, 9, 15, 3] nums = [10, 20, 5, 7, 9, 15, 3]
heapq.heapify(nums) heapq.heapify(nums)
sorted_list = [heapq.heappop(nums) for _ in range(len(nums))] sorted_list = [heapq.heappop(nums) for _ in range(len(nums))]
sorted_list sorted_list
``` ```
%% Cell type:markdown id:327aa702-5699-42ba-96e1-b75079d31050 tags: %% Cell type:markdown id:327aa702-5699-42ba-96e1-b75079d31050 tags:
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. 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. You may follow those steps:
1. Use `heapq` to store the first element of each list. 1. Use `heapq` to store the first element of each list.
2. Store each element in the heap as a tuple `(value, list_index, element_index)`: 2. Store each element in the heap as a tuple `(value, list_index, element_index)`:
- `value` is the element value, - `value` is the element value,
- `list_index` is the index of the list it comes from, - `list_index` is the index of the list it comes from,
- `element_index` is the position of the element in its original list. - `element_index` is the position of the element in its original list
3. At each step, extract the smallest element from the heap and add it to the result list. 3. At each step, extract the smallest element from the heap and add it to the result list
4. Insert the next element from the same list into the heap until all lists are empty. 4. Insert the next element from the same list into the heap until all lists are empty
%% Cell type:code id:4b20f11a-47b8-419a-b94a-902943048c76 tags: %% Cell type:code id:4b20f11a-47b8-419a-b94a-902943048c76 tags:
``` python ``` python
import heapq import heapq
def merge(lists): def merge(lists):
min_heap = [] # YOUR CODE HERE
merged_list = [] raise NotImplementedError()
for i, lst in enumerate(lists): # each first element in heap
if lst:
heapq.heappush(min_heap, (lst[0], i, 0)) # (value, list_index, element_index)
while min_heap:
val, list_index, element_index = heapq.heappop(min_heap)
merged_list.append(val)
if element_index + 1 < len(lists[list_index]):
next_val = lists[list_index][element_index + 1]
heapq.heappush(min_heap, (next_val, list_index, element_index + 1))
return merged_list
``` ```
%% Cell type:code id:1b7e1364-1335-4daf-9100-ef933f97b86d tags: %% Cell type:code id:1b7e1364-1335-4daf-9100-ef933f97b86d tags:
``` python ``` python
# Usage example # Usage example
lists = [ lists = [
[1, 4, 5], [1, 4, 5],
[1, 3, 4], [1, 3, 4],
[2, 6] [2, 6]
] ]
merge(lists) # [1, 1, 2, 3, 4, 4, 5, 6] merge(lists) # [1, 1, 2, 3, 4, 4, 5, 6]
``` ```
%% Cell type:code id:44600161-32a0-4b84-b152-65a15ba103ae tags: %% Cell type:code id:44600161-32a0-4b84-b152-65a15ba103ae tags:
``` python ``` python
# Tests # Tests
assert merge([[]]) == [] assert merge([[]]) == []
assert merge([[1, 2, 3]]) == [1, 2, 3] assert merge([[1, 2, 3]]) == [1, 2, 3]
``` ```
%% Cell type:markdown id:b318e23f-4ab5-455c-9607-90e75245df21 tags:
## Exercise 5 (BONUS)
- Re-implement previous exercises that involve a priority queue using heaps
- Compare performance in execution time
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment