Add new course
@@ -0,0 +1,114 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Task description: Open Hashing</title>
|
||||
<meta charset="utf-8">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h4>1. Implementing the Hash Table</h4>
|
||||
</div>
|
||||
<div>Create your own hash table that uses open hashing in Python. Each slot of the hash table contains a linked
|
||||
structure where the data (keys) are stored. The hash system must include search, insert, and delete operations. The hash table must be able to store both integer (<em>int</em>)
|
||||
and string (<em>str</em>) values. That means that also all the operations/methods (search, insert, and delete) need to work with both data types. You can decide or design the hash function by yourself.<br></div>
|
||||
<br>
|
||||
<div>Consider following things when you are creating the hash table:</div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li>The size of the hash table is <strong>fixed</strong>. That means that after initializing the size of the table must stay the same.</li><li>You must implement the linked structure where the data is stored by yourself.<br></li><li>Choose your hashing function wisely because it must work efficiently with very large hash tables.
|
||||
A Good start is the string folding. Be as creative you want but be prepared to explain how it works!</li>
|
||||
<li>Document your code!</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<div><div>Save the code of your new data structure as <strong>hash_1.py</strong></div><br></div><div>Answer to the following essay questions:</div>
|
||||
<ol>
|
||||
<li>Present the structure of your hash table.</li>
|
||||
<li>What hashing function did you choose and why?</li>
|
||||
<li>What (including required) methods your hash table has and explain briefly how do they work?</li>
|
||||
</ol><br>
|
||||
|
||||
|
||||
<div>
|
||||
<h4>2. Testing and Analyzing the Hash Table</h4>
|
||||
</div>
|
||||
<div>Create a Python program: <strong>hash_2.py</strong>:</div>
|
||||
<ol>
|
||||
<li>Create a new hash table of size \(3\). Add items <strong>12, 'hashtable', 1234, 4328989, 'BM40A1500', -12456, 'aaaabbbbcccc'</strong>
|
||||
to the hash table. Present the structure of the hash table each time when a new value is added.</li>
|
||||
<li>Now try to find values <strong>-12456, 'hashtable', 1235</strong>. Print out the results.</li>
|
||||
<li>Remove values <strong>'BM40A1500', 1234, 'aaaabbbbcccc'</strong>. Present the final structure of the hash table.</li>
|
||||
</ol>
|
||||
<div>Answer to the following essay questions:</div>
|
||||
<ol>
|
||||
<li>What is the running time of adding a new value in your hash table and why?</li>
|
||||
<li>What is the running time of finding a new value in your hash table and why?</li>
|
||||
<li>What is the running time of removing a new value in your hash table and why?</li>
|
||||
</ol>
|
||||
<div>Use \(\Theta\) notation. Consider what factors influence the running time of the methods.</div>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
|
||||
<div>
|
||||
<h4>3. The Pressure Test</h4>
|
||||
</div>
|
||||
<div>Let's put the hash table in a real use. The text file <a href="data/words_alpha.txt"><em>words_alpha.txt</em></a> (source: https://github.com/dwyl/english-words/)
|
||||
contains \(370105\) English (and not so English) words. The text file
|
||||
<a href="data/kaikkisanat.txt"><em>kaikkisanat.txt</em></a> (source: https://github.com/hugovk/everyfinnishword) contains \(93086\) Finnish words. Your task is to find all words from <em>kaikkisanat.txt</em> that are also in <em>words_alpha.txt</em> (exact matches).
|
||||
</div>
|
||||
<br>
|
||||
<div>Create a new Python file <strong>hash_3_1.py</strong>:</div>
|
||||
<ol>
|
||||
<li>Create a new hash table of size \(10000\).</li>
|
||||
<li>Read all words from <em>words_alpha.txt</em> and store them to your hash table.</li>
|
||||
<li>While reading words from <em>kaikkisanat.txt</em> check how many of them can you find from the hash table
|
||||
and print out the final result.</li>
|
||||
</ol>
|
||||
<div>Measure the runtime for each step. Tabulate the results
|
||||
as follows:
|
||||
</div>
|
||||
<br>
|
||||
|
||||
|
||||
|
||||
<table frame="grey" cellspacing="1" cellpadding="0" border="1">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Process</th>
|
||||
<th>Time (s)</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Initializing the hash table</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Adding the words</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Finding the common words</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
<div>How does your hash table stand against a linear array? Repeat the previous test,
|
||||
but this time store the words from <em>words_alpha.txt</em> to a <em>list</em> instead of the hash table. Save your code as <strong>hash_3_2.py</strong><br></div>
|
||||
|
||||
<div><br></div><div>Answer to the following essay questions:</div>
|
||||
<ol>
|
||||
<li>Which data structure was faster in adding the words from the file and why?</li>
|
||||
<li>In which data structure was the search faster and why?</li>
|
||||
<li>Are you able to make the test program in <strong>hash_3_1.py</strong> faster (even slight improvements)?
|
||||
<ul>
|
||||
<li>Try to change the size of the hash table.</li>
|
||||
<li>How well is the data distributed in the hash table?</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ol>
|
||||
<br>
|
||||
<p>Provide your answers to all the essay questions in a single PDF file. You can use the template below:</p><a href="data/PA_essay_template.odt?time=1665307225135">
|
||||
</a><p><a href="data/PA_essay_template.odt?time=1665398460962">PA_essay_template.odt</a><br></p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,128 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Week 1 Programming Assignments (9 points)</title>
|
||||
<meta charset="utf-8">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h4><strong> Assignment 1.1: Insertion Sort</strong> (3 points)</h4>
|
||||
</div>
|
||||
<p></p>
|
||||
<div> Following pseudo code sorts an array of integers. Command swap switches values of two variables. </div>
|
||||
<p></p>
|
||||
<pre>function isort(A)
|
||||
for i = 1 to size(A)-1
|
||||
j = i-1
|
||||
while (j >= 0) and (A[j] > A[j+1])
|
||||
swap(A[j], A[j+1])
|
||||
j = j-1
|
||||
return
|
||||
</pre>
|
||||
<p></p>
|
||||
<div> Create the following function in Python: </div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li> <strong>isort(A: list)</strong>: sorts a given list of integers. Implement the pseudo code to this function. </li>
|
||||
</ul>
|
||||
</ul>
|
||||
<p></p>
|
||||
<div> Limits: </div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li> the maximum length of the list is \(10^3\) </li>
|
||||
<li> each integer is between \(1...10^3\) </li>
|
||||
</ul>
|
||||
</ul>
|
||||
<div>A code template with an example program: </div>
|
||||
<p></p>
|
||||
<div style="border:2px solid black">
|
||||
<pre>def isort(A):
|
||||
# TODO
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
A = [4, 3, 6, 2, 9, 7, 1, 8, 5]
|
||||
isort(A)
|
||||
print(A) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
</pre>
|
||||
</div>
|
||||
<p></p>
|
||||
<div> Submit your solution in CodeGrade as <strong>isort.py</strong>. </div>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
|
||||
<div>
|
||||
<h4><strong> Assignment 1.2 Prime Numbers</strong> <span>(3 points)</span></h4>
|
||||
</div>
|
||||
<p></p>
|
||||
<div> For the background read the first paragraph of this article: <a href="https://en.wikipedia.org/wiki/Prime_number">https://en.wikipedia.org/wiki/Prime_number</a></div>
|
||||
<p></p>
|
||||
<div> Given a number \(N\) how many prime numbers are less or equal to \(N\)? For example if \(N = 7\) there are four prime numbers: \(2\), \(3\), \(5\) and \(7\) (note that 1 is not a prime number). </div>
|
||||
<p></p>
|
||||
<div> Create the following function in Python: </div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li> <strong>primes(N: int)</strong>: returns the numbers of primes that are less or equal to \(N\) </li>
|
||||
</ul>
|
||||
</ul>
|
||||
<div> Limits: \(1 \leq N \leq 10^5\) </div>
|
||||
<p></p>
|
||||
<div><div>A code template with an example program: </div></div>
|
||||
<p></p>
|
||||
<div style="border:2px solid black">
|
||||
<pre>def primes(N):
|
||||
# TODO
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(primes(7)) # 4
|
||||
print(primes(15)) # 6
|
||||
print(primes(50)) # 15
|
||||
</pre>
|
||||
</div>
|
||||
<p></p>
|
||||
<div> Submit your solution in CodeGrade as <strong>primes.py</strong>.</div>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
|
||||
<div>
|
||||
<h4><strong> Assignment 1.3: Is it a Triangle?</strong> (3 points)</h4>
|
||||
</div>
|
||||
<p></p>
|
||||
<div> Three integers \(a\), \(b\) and \(c\) presents the side lenghts of a triangle. Can you build any triangle from those three sides?</div>
|
||||
<p></p>
|
||||
<div> For example:</div>
|
||||
<ol>
|
||||
<li> sides \(3\), \(4\) and \(5\) makes a right angle triangle </li>
|
||||
<li> sides \(5\), \(5\) and \(3\) makes an isosceles triangle </li>
|
||||
<li> sides \(7\), \(3\) and \(3\) doesn't make a triangle </li>
|
||||
<li> sides \(4\), \(3\) and \(-1\) doesn't make a triangle </li>
|
||||
</ol>
|
||||
<div> Create the following function in Python:</div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li><strong>triangle(a: int, b: int, c: int)</strong>: returns a boolean <strong>True</strong> if triangle can be built, <strong>False</strong> if not </li>
|
||||
</ul>
|
||||
</ul>
|
||||
<div><div>A code template with an example program: </div></div>
|
||||
<p></p>
|
||||
<div style="border:2px solid black">
|
||||
<pre>def triangle(a, b, c):
|
||||
# TODO
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(triangle(3, 5, 4)) # True
|
||||
print(triangle(-1, 2, 3)) # False
|
||||
print(triangle(5, 9, 14)) # False
|
||||
print(triangle(30, 12, 29)) # True
|
||||
</pre>
|
||||
</div>
|
||||
<p></p>
|
||||
<div> Submit your solution in CodeGrade as <strong>triangle.py</strong>.</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,14 @@
|
||||
def isort(A):
|
||||
for i in range(1, len(A)):
|
||||
j = i-1
|
||||
while (j >= 0) and (A[j] > A[j+1]):
|
||||
temp = A[j]
|
||||
A[j] = A[j+1]
|
||||
A[j+1] = temp
|
||||
j = j-1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
A = [4, 3, 6, 2, 9, 7, 1, 8, 5]
|
||||
isort(A)
|
||||
print(A) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
@@ -0,0 +1,12 @@
|
||||
def primes(N):
|
||||
a = 0
|
||||
for num in range(2, N+1):
|
||||
if all(num % i != 0 for i in range(2, num)):
|
||||
a += 1
|
||||
return a
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(primes(7)) # 4
|
||||
print(primes(15)) # 6
|
||||
print(primes(50)) # 15
|
||||
@@ -0,0 +1,12 @@
|
||||
def triangle(a, b, c):
|
||||
if (a+b) > c and (a+c) > b and (b+c) > a:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(triangle(3, 5, 4)) # True
|
||||
print(triangle(-1, 2, 3)) # False
|
||||
print(triangle(5, 9, 14)) # False
|
||||
print(triangle(30, 12, 29)) # True
|
||||
@@ -0,0 +1,103 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Week 10 Programming Assignments (8 points)</title>
|
||||
<meta charset="utf-8">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<p><strong><span class="" style="color: rgb(239, 69, 64);">Note: both assignments for this week use the graph class implemented in Programming Assignment 9.1.</span></strong></p><h4><strong>Assignment 10.1: Floyd's Algorithm</strong> (4 points)</h4>
|
||||
</div>
|
||||
<div>To find the shortest distance between all pair of vertices the best solution is to use Floyd's algorithm.</div>
|
||||
<br>
|
||||
<div>Create a function <strong>floyd(graph: Graph)</strong> in Python. The function takes a Graph object as an input value and returns a \(V \times V\) matrix
|
||||
(\(V\) sized list of \(V\) sized lists) containing distances between all vertex pairs (\(v_i,v_j\)). The function must work for both directed and undirected graphs.</div>
|
||||
<br>
|
||||
<div>A code template with an example program for the directed graph below:</div>
|
||||
<p></p>
|
||||
<!-- Add other path in Moodle! -->
|
||||
<img src="data/examplegraph.png" alt="Example Graph" class="img-responsive atto_image_button_text-bottom" width="306" height="239">
|
||||
<p></p>
|
||||
<div style="border:2px solid black">
|
||||
<pre>from graph import Graph
|
||||
|
||||
|
||||
def floyd(graph):
|
||||
# TODO
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
matrix = [
|
||||
# 0 1 2 3 4 5
|
||||
[0, 0, 7, 0, 9, 0], # 0
|
||||
[0, 0, 0, 0, 0, 0], # 1
|
||||
[0, 5, 0, 1, 0, 2], # 2
|
||||
[6, 0, 0, 0, 0, 2], # 3
|
||||
[0, 0, 0, 0, 0, 1], # 4
|
||||
[0, 6, 0, 0, 0, 0] # 5
|
||||
]
|
||||
graph = Graph(matrix)
|
||||
D = floyd(graph)
|
||||
for i in range(6):
|
||||
for j in range(6):
|
||||
print(f"{D[i][j]:2d}", end=" ")
|
||||
print()
|
||||
# 0 12 7 8 9 9
|
||||
# 0 0 0 0 0 0
|
||||
# 7 5 0 1 16 2
|
||||
# 6 8 13 0 15 2
|
||||
# 0 7 0 0 0 1
|
||||
# 0 6 0 0 0 0
|
||||
</pre>
|
||||
</div>
|
||||
<p></p>
|
||||
<div>Submit your solution in CodeGrade as <strong>floyd.py</strong> including your graph class in <strong>graph.py</strong>.</div>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
|
||||
<div>
|
||||
<h4><strong>Assignment 10.2: Kruskal's Algorithm</strong> (4 points)</h4>
|
||||
</div>
|
||||
<div>Last week we constructed a graph with the shortest paths starting from a given vertex using Dijkstra's algorithm. Although the shortest -path graph might also be a minimal cost spanning tree (MCST), this is not guaranteed. Therefore, it is better to use an algorithm designed to produce MCST. Here we implement Kruskal's algorithm.</div>
|
||||
<br>
|
||||
<div>Create a function <strong>kruskal(graph: Graph)</strong> in Python. The function takes a Graph object as an input value and
|
||||
returns a new Graph object that has only the edges that constructs the minimum spanning tree computed by Kruskal's algorithm. The created graph is undirected and
|
||||
you can assume that the original graph is undirected too.</div>
|
||||
<br>
|
||||
<div>For example the on the left we have the original undirected graph and on the right we have a graph that the function produces.</div>
|
||||
<br>
|
||||
<p><img src="data/kruskal.png" alt="Example Graph" class="img-responsive atto_image_button_text-bottom" width="647" height="233"><br>
|
||||
</p><br>
|
||||
<div></div>A code template with an example program for the graph above:<br><br>
|
||||
<div style="border:2px solid black">
|
||||
<pre>from graph import Graph
|
||||
|
||||
def kruskal(graph):
|
||||
# TODO
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
matrix = [
|
||||
# 0 1 2 3 4 5
|
||||
[0, 0, 7, 6, 9, 0], # 0
|
||||
[0, 0, 5, 0, 0, 6], # 1
|
||||
[7, 5, 0, 1, 0, 2], # 2
|
||||
[6, 0, 1, 0, 0, 2], # 3
|
||||
[9, 0, 0, 0, 0, 1], # 4
|
||||
[0, 6, 2, 2, 1, 0] # 5
|
||||
]
|
||||
graph = Graph(matrix)
|
||||
graph.bf_print(0) # 0 2 3 4 1 5
|
||||
mst = kruskal(graph)
|
||||
mst.bf_print(0) # 0 3 2 1 5 4
|
||||
</pre>
|
||||
</div>
|
||||
<br>
|
||||
<div>Submit your solution in CodeGrade as <strong>kruskal.py</strong> including your graph class in <strong>graph.py</strong>.</div>
|
||||
<br>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 28 KiB |
@@ -0,0 +1,45 @@
|
||||
from sys import maxsize
|
||||
from graph import Graph
|
||||
|
||||
|
||||
def floyd(graph: Graph):
|
||||
distance = graph.matrix
|
||||
for x in range(graph.V):
|
||||
for y in range(graph.V):
|
||||
if x != y and distance[x][y] == 0:
|
||||
distance[x][y] = maxsize
|
||||
for k in range(graph.V):
|
||||
for i in range(graph.V):
|
||||
for j in range(graph.V):
|
||||
distance[i][j] = min(
|
||||
distance[i][j], distance[i][k] + distance[k][j])
|
||||
for x in range(graph.V):
|
||||
for y in range(graph.V):
|
||||
if x != y and distance[x][y] == maxsize:
|
||||
distance[x][y] = 0
|
||||
return distance
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
matrix = [
|
||||
# 0 1 2 3 4 5
|
||||
[0, 0, 7, 0, 9, 0], # 0
|
||||
[0, 0, 0, 0, 0, 0], # 1
|
||||
[0, 5, 0, 1, 0, 2], # 2
|
||||
[6, 0, 0, 0, 0, 2], # 3
|
||||
[0, 0, 0, 0, 0, 1], # 4
|
||||
[0, 6, 0, 0, 0, 0] # 5
|
||||
]
|
||||
graph = Graph(matrix)
|
||||
D = floyd(graph)
|
||||
for i in range(6):
|
||||
for j in range(6):
|
||||
print(f"{D[i][j]:2d}", end=" ")
|
||||
print()
|
||||
# 0 12 7 8 9 9
|
||||
# 0 0 0 0 0 0
|
||||
# 7 5 0 1 16 2
|
||||
# 6 8 13 0 15 2
|
||||
# 0 7 0 0 0 1
|
||||
# 0 6 0 0 0 0
|
||||
@@ -0,0 +1,50 @@
|
||||
from graph import Graph
|
||||
|
||||
|
||||
def kruskal(graph: Graph):
|
||||
matrix = graph.matrix
|
||||
V = graph.V
|
||||
edges = []
|
||||
for i in range(V):
|
||||
for j in range(V):
|
||||
if matrix[i][j] > 0:
|
||||
edges.append((i, j, matrix[i][j]))
|
||||
edges.sort(key=lambda item: item[2])
|
||||
subsets = []
|
||||
for i in range(V):
|
||||
subsets.append([i])
|
||||
result = []
|
||||
for edge in edges:
|
||||
subset1 = None
|
||||
subset2 = None
|
||||
for subset in subsets:
|
||||
if edge[0] in subset:
|
||||
subset1 = subset
|
||||
if edge[1] in subset:
|
||||
subset2 = subset
|
||||
if subset1 != subset2:
|
||||
result.append(edge)
|
||||
subsets.remove(subset1)
|
||||
subsets.remove(subset2)
|
||||
subsets.append(subset1 + subset2)
|
||||
new_matrix = [[0] * V for _ in range(V)]
|
||||
for edge in result:
|
||||
new_matrix[edge[0]][edge[1]] = edge[2]
|
||||
new_matrix[edge[1]][edge[0]] = edge[2]
|
||||
return Graph(new_matrix)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
matrix = [
|
||||
# 0 1 2 3 4 5
|
||||
[0, 0, 7, 6, 9, 0], # 0
|
||||
[0, 0, 5, 0, 0, 6], # 1
|
||||
[7, 5, 0, 1, 0, 2], # 2
|
||||
[6, 0, 1, 0, 0, 2], # 3
|
||||
[9, 0, 0, 0, 0, 1], # 4
|
||||
[0, 6, 2, 2, 1, 0] # 5
|
||||
]
|
||||
graph = Graph(matrix)
|
||||
graph.bf_print(0) # 0 2 3 4 1 5
|
||||
mst = kruskal(graph)
|
||||
mst.bf_print(0) # 0 3 2 1 5 4
|
||||
@@ -0,0 +1,112 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Week 11 Programming Assignments (8 points)</title>
|
||||
<meta charset="utf-8">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<p><strong style="color: rgb(0, 0, 0); font-size: 18px;">Assignment 11.1: Traveling salesman problem and branch-and-bound</strong><span style="color: rgb(0, 0, 0); font-size: 18px;"> (4 points)</span><br></p>
|
||||
</div>
|
||||
<div>In traveling salesman problem, the task is to find the shortest possible route that visits each city exactly once and returns to the origin city. The problem is known to be NP-hard. See <a href="https://moodle.lut.fi/mod/page/view.php?id=699882">Sec. 11.4.4 of the background material</a> for the introduction to the problem. </div>
|
||||
<div><br></div>
|
||||
<div>No efficient (polynomial time) algorithm is known for the problem. With a small amount of cities we can test all the possible permutations using backtracking and select the shortest route. However, the computation time quickly becomes unbearable when the amount of cities increases. Using <a href="https://moodle.lut.fi/mod/page/view.php?id=698497" target="_blank">branch-and-bound</a> we can reduce the computation time remarkably by reducing the number of solutions to be investigated. This approach still always produce the optimal solution, but can be used with a larger number of cities than the simple backtracking. </div>
|
||||
<div></div><br>
|
||||
<div>Create a Python function <strong>salesman(city_map: list)</strong> that solves the traveling salesman problem using branch-and-bound algorithm. The function takes a distance matrix (city_map[i][j] tells the distance between \(i\)th and \(j\)th city) of the cities as an input value and returns a order of the cities traversed in a list.
|
||||
Cities are labeled as integers starting from zero and the traverse always starts from the first city (\(0\)th city).</div>
|
||||
<br><strong>Target:</strong> <br>
|
||||
<ul>
|
||||
<li>The function finds the optimal route with 10 cities in 2 seconds on CodeGrade (2 points)</li>
|
||||
<li>The function finds the optimal route with 10 cities in 0.5 seconds on CodeGrade (4 points)</li>
|
||||
</ul>
|
||||
<div>Note, that testing all permutations with simple backtracking is too slow. In order the achieve either of the targets, the function needs to use branch-and-bound. To obtain 4 points, a more accurate estimate for the lower bound is needed.</div>
|
||||
<div><br></div>
|
||||
<div>A code template with an example program:</div><br>
|
||||
<div style="border:2px solid black">
|
||||
<pre>def salesman(city_map):
|
||||
# TODO
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
cost = 0
|
||||
|
||||
city_map = [
|
||||
# 0 1 2 3 4
|
||||
[ 0, 12, 19, 16, 29], # 0
|
||||
[12, 0, 27, 25, 5], # 1
|
||||
[19, 27, 0, 8, 4], # 2
|
||||
[16, 25, 8, 0, 14], # 3
|
||||
[29, 5, 4, 14, 0] # 4
|
||||
]
|
||||
|
||||
path = salesman(city_map)
|
||||
for i in range(len(city_map)):
|
||||
cost += city_map[path[i]][path[i+1]]
|
||||
|
||||
print(path) # [0, 1, 4, 2, 3, 0]
|
||||
print(cost) # 45
|
||||
</pre>
|
||||
</div>
|
||||
<p></p>
|
||||
<div>Submit your solution in CodeGrade as <strong>salesman.py</strong>.</div>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
|
||||
<div>
|
||||
<h4><strong>Assignment 11.2: The bin packing problem and approximation algorithms</strong> (4 points)</h4>
|
||||
</div>
|
||||
<div>When the size of the problem increases even the more sophisticated exact algorithms (e.g. branch-and-bound and dynamic programming) become insufficient. In such cases, we typically need to settle for approximation algorithms. Such algorithms do not (always) provide the optimal solutions, but usually provide a good solution fast.</div>
|
||||
<div><br></div>
|
||||
<div>
|
||||
<div><strong>Bin packing problem:</strong> given a set of \(n\) items with sizes \([s_1, s_2, s_3, … , s_n]\), find a way to pack the items to bins with size \(S\) so that the total amount of bins is minimized.</div>
|
||||
<div><br></div>
|
||||
<div>Design and implement an approximation algorithm for the bin packing problem. The algorithm must be able to find a solution for very large set of items. Therefore, brute-force approach or other algorithms that always find the optimal solution are not suitable. You will get points based on how close the solutions your algorithm produces are to the optimal solutions. </div>
|
||||
<div><br></div>
|
||||
<div>Create a function <strong>binpack(items: list, S: int)</strong> in Python. The function takes list of items and a maximum bin size \(S\) as an input value and returns a list of all bins. Each bin is a list of items.</div>
|
||||
<div><br></div>
|
||||
<div><strong>Target: </strong></div>
|
||||
<div>
|
||||
<ul>
|
||||
<li>the algorithm is able to find an (approximate) solution in less than \(1\) seconds when \(n \leq 1000\), and<br></li>
|
||||
<li>the solution (number of bins) is at most 50% larger than the optimal amount of bins (1 point)<br></li>
|
||||
<li>the solution (number of bins) is at most 5% larger than the optimal amount of bins (2 points)<br></li>
|
||||
<li>the solution (number of bins) is at most 1% larger than the optimal amount of bins (4 points)</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>Note that to get the points, you do not need to find a solution that has a theoretical worst case of 1% larger than the optimum. It is enough that you obtain good enough solution for the cases that are used in CodeGrade. Even quite simple solutions produce almost always much better solution than the theoretical worst case.</div>
|
||||
<div><br></div>
|
||||
<div></div>A code template with an example program:<br><br>
|
||||
<div style="border:2px solid black">
|
||||
<pre>def binpack(items, S):
|
||||
# TODO
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
items = [9, 3, 3, 6, 10, 4, 6, 8, 6, 3]
|
||||
B = 10
|
||||
|
||||
bins = binpack(items, B)
|
||||
|
||||
for i in range(len(bins)):
|
||||
print(f"bin {i+1}: {bins[i]}")
|
||||
|
||||
# A possible output:
|
||||
# bin 1: [9]
|
||||
# bin 2: [3, 3, 4]
|
||||
# bin 3: [6, 3]
|
||||
# bin 4: [10]
|
||||
# bin 5: [6]
|
||||
# bin 6: [8]
|
||||
# bin 7: [6]
|
||||
</pre>
|
||||
</div>
|
||||
<br>
|
||||
<div>Submit your solution in CodeGrade as <strong>binpack.py</strong>.</div>
|
||||
<br>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 28 KiB |
@@ -0,0 +1,143 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Week 2 Programming assignments (9 points)</title>
|
||||
<meta charset="utf-8">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h4><strong> Assignment 2.1: Changes</strong> (3 points)</h4>
|
||||
</div>
|
||||
<p></p>
|
||||
<div> An array of \(n\) number of integers must be modified so that no two consecutive integers are equal. The new value can be chosen arbitrarily. What is the minimum number of required changes? </div>
|
||||
<p></p>
|
||||
<div> For Example array \([1, 1, 2, 2, 2]\) requires 2 changes. Changed array can be e.g. \([1, <strong><span class="" style="color: rgb(51, 51, 51);">3</span></strong>, 2, <strong><span class="" style="color: rgb(51, 51, 51);">3</span></strong>, 2]\) (the changed integers are in bold).
|
||||
</div>
|
||||
<p></p>
|
||||
<div> Create the following function in Python: </div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li> <strong>changes(A: list)</strong>: returns the minimum number of required changes
|
||||
</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<div> Limits: </div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li> \(1 \leq n \leq 10^6\) </li>
|
||||
<li> each integer is between \(1...10^3\) </li>
|
||||
</ul>
|
||||
</ul>
|
||||
<div><strong> Target: Algorithm performs in \(\Theta(n)\) time. </strong></div>
|
||||
<p></p>
|
||||
<div>A code template with an example program: </div>
|
||||
<p></p>
|
||||
<div style="border:2px solid black">
|
||||
<pre>def changes(A):
|
||||
# TODO
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(changes([1, 1, 2, 2, 2])) # 2
|
||||
print(changes([1, 2, 3, 4, 5])) # 0
|
||||
print(changes([1, 1, 1, 1, 1])) # 2 </pre>
|
||||
</div>
|
||||
<p></p>
|
||||
<div><br> </div>
|
||||
<div>Submit your solution in CodeGrade as <strong>changes.py</strong>. <br></div>
|
||||
<div><br></div>
|
||||
<p></p>
|
||||
<p></p>
|
||||
|
||||
|
||||
<div>
|
||||
<h4><strong> Assignment 2.2: Bit Pairs</strong> (3 points)</h4>
|
||||
</div>
|
||||
<p></p>
|
||||
<div> We are given a bit string which each character is either 0 or 1. Count the sum of each distance of bit pairs where both bits are 1. </div>
|
||||
<p></p>
|
||||
<div> For example a bit string 100101 has following distances </div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li> <strong>1</strong>00<strong>1</strong>01 (3) </li>
|
||||
<li> <strong>1</strong>0010<strong>1</strong> (5) </li>
|
||||
<li> 100<strong>1</strong>0<strong>1</strong> (2) </li>
|
||||
</ul>
|
||||
</ul>
|
||||
<div> Therefore the sum of distances is \(3+5+2 = 10\). </div>
|
||||
<p></p>
|
||||
<div> Create the following function in Python:</div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li><strong>pairs(s: str)</strong>: returns the sum of distances </li>
|
||||
</ul>
|
||||
</ul>
|
||||
<div> Limits: the maximum length of the bit string is \(10^5\) </div>
|
||||
<p></p>
|
||||
<div><strong> Target: Algorithm performs in \(\Theta(n)\) time. </strong></div>
|
||||
<p></p>
|
||||
<div>A code template with an example program: </div>
|
||||
<p></p>
|
||||
<div style="border:2px solid black">
|
||||
<pre>def pairs(s):
|
||||
# TODO
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(pairs("100101")) # 10
|
||||
print(pairs("101")) # 2
|
||||
print(pairs("100100111001")) # 71
|
||||
</pre>
|
||||
</div>
|
||||
<p></p>
|
||||
<div> Submit your solution solution in CodeGrade as <strong>bitpairs.py</strong>.</div>
|
||||
<div><br></div>
|
||||
<p></p>
|
||||
<p></p>
|
||||
|
||||
|
||||
<div>
|
||||
<h4><strong> Assignment 2.3: Split Lists </strong>(3 points)</h4>
|
||||
</div>
|
||||
<p></p>
|
||||
<div>An array of \(n\) number of integers must be split in two sub arrays so that every integer of left sub array are smaller than every integer of right sub array. In how many points the array can be split in half? </div>
|
||||
<p></p>
|
||||
<div> For example array \([2, 1, 2, 5, 7, 6, 9]\) can be split in 3 ways: </div>
|
||||
<ol>
|
||||
<li>\([2, 1, 2]\) and \([5, 7, 6, 9]\)</li>
|
||||
<li>\([2, 1, 2, 5]\) and \([7, 6, 9]\)</li>
|
||||
<li>\([2, 1, 2, 5, 7, 6]\) and \([9]\)</li>
|
||||
</ol>
|
||||
<div> Create following function(s) in Python:</div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li><strong>split(A: list)</strong>: returns the number of possible splits </li>
|
||||
</ul>
|
||||
</ul>
|
||||
<div> Limits: </div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li>\(1 \leq n \leq 10^5\)<br></li>
|
||||
<li> each integer is between \(1...10^3\) </li>
|
||||
</ul>
|
||||
</ul>
|
||||
<div><strong> Target: Algorithm performs in \(\Theta(n)\) time. </strong></div>
|
||||
<p></p>
|
||||
<div>A code template with an example program: </div>
|
||||
<p></p>
|
||||
<div style="border:2px solid black">
|
||||
<pre>def split(T):
|
||||
# TODO
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(count([1,2,3,4,5])) # 4
|
||||
print(count([5,4,3,2,1])) # 0
|
||||
print(count([2,1,2,5,7,6,9])) # 3
|
||||
print(count([1,2,3,1])) # 0</pre>
|
||||
</div>
|
||||
<p></p>
|
||||
<div> Submit your solution solution in CodeGrade as <strong>split.py</strong>.</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,13 @@
|
||||
def pairs(s):
|
||||
result = 0
|
||||
loc = [x for x in range(len(s)) if s[x] == "1"]
|
||||
for i in range(len(loc)):
|
||||
result += loc[i]*(i) - loc[i]*(len(loc)-i-1)
|
||||
return result
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(pairs("100101")) # 10
|
||||
print(pairs("101")) # 2
|
||||
print(pairs("100100111001")) # 71
|
||||
print(pairs("0011110001110011010111"))
|
||||
@@ -0,0 +1,17 @@
|
||||
def changes(A):
|
||||
count = 0
|
||||
i = 0
|
||||
while i < len(A):
|
||||
if i == len(A)-1:
|
||||
break
|
||||
else:
|
||||
if A[i+1] == A[i]:
|
||||
count += 1
|
||||
i += 2
|
||||
else:
|
||||
i += 1
|
||||
return count
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(changes([1, 2, 5, 5, 4, 2]))
|
||||
@@ -0,0 +1,25 @@
|
||||
def split(T):
|
||||
count = 0
|
||||
max_from_left = T[0]
|
||||
min_to_right = T[-1]
|
||||
|
||||
for i in range(1, len(T)):
|
||||
max_from_left = max(max_from_left, T[i])
|
||||
|
||||
for i in range(len(T) - 2, -1, -1):
|
||||
min_to_right = min(min_to_right, T[i])
|
||||
|
||||
for i in range(len(T) - 1):
|
||||
if max_from_left < min_to_right:
|
||||
count += 1
|
||||
max_from_left = max(max_from_left, T[i])
|
||||
min_to_right = min(min_to_right, T[i+1])
|
||||
|
||||
return count
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(split([1, 2, 3, 4, 5])) # 4
|
||||
print(split([5, 4, 3, 2, 1])) # 0
|
||||
print(split([2, 1, 2, 5, 7, 6, 9])) # 3
|
||||
print(split([1, 2, 3, 1])) # 0
|
||||
@@ -0,0 +1,82 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Week 3: Programming Assignments (8 points)</title>
|
||||
<meta charset="utf-8">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h4><strong>Assignment 3.1: Linked List </strong>(5 points)<strong><br></strong></h4>
|
||||
</div>
|
||||
<div>Implement the linked list data structure in Python. Create a class <strong>Node</strong> which stores the data and link to another Node class. Create also the class <strong>LinkedList</strong> which maintains the linked list created by Node classes and has the following methods:
|
||||
</div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li><strong>append(data: object)</strong>: inserts a new Node containing the data to the end of the list.<br></li>
|
||||
<li><strong>insert(data: object, index: int)</strong>: inserts a new Node containing the data to the position indicated by the index (the index of the first node is 0).</li>
|
||||
<li><strong>delete(index: int)</strong>: deletes a node from the position indicated by the index.</li>
|
||||
<li><strong>index(data: object)</strong>: search the Node containing the data and returns its index. Returns \(-1\) if not found.</li>
|
||||
<li><strong>print()</strong>: prints the content of linked list (format: node1 -> node2 -> node3).</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<div>A code template with an example program: </div>
|
||||
<p></p>
|
||||
<div style="border:2px solid black">
|
||||
<pre>class Node:
|
||||
# TODO
|
||||
|
||||
|
||||
class LinkedList:
|
||||
# TODO
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
L = LinkedList()
|
||||
L.append(1)
|
||||
L.append(3)
|
||||
L.print() # 1 -> 3
|
||||
L.insert(10, 1)
|
||||
L.insert(15, 0)
|
||||
L.print() # 15 -> 1 -> 10 -> 3
|
||||
print(L.index(1)) # 1
|
||||
L.delete(0)
|
||||
L.print() # 1 -> 10 -> 3
|
||||
</pre>
|
||||
</div>
|
||||
<p></p>
|
||||
<div>Submit your solution in CodeGrade as <strong>linked.py</strong>.</div>
|
||||
<div><br><br></div>
|
||||
|
||||
|
||||
<div>
|
||||
<h4><strong>Assignment 3.2: Binary Search </strong>(3 points)</h4>
|
||||
</div>
|
||||
<div>Implement the binary search algorithm in Python. Create a function <strong>search(A: list, item: int)</strong> which returns the index of the item in the list. If the item is not found the function returns \(-1\). You can assume that the list contains only
|
||||
integers and it is always sorted.</div>
|
||||
<div><br>Limits:</div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li>Integers in the list are between \(1...10^6\)</li>
|
||||
<li>The maximum length of the list is \(10^6\)</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<div>Target: the algorithm performs in \(\Theta(\log(n))\) time.</div>
|
||||
<p></p>
|
||||
<div>A code template with an example program: </div>
|
||||
<p></p>
|
||||
<div style="border:2px solid black">
|
||||
<pre>def search(A: list, item: int):
|
||||
# TODO
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
A = [1, 2, 3, 6, 10, 15, 22, 27, 30, 31]
|
||||
print(search(A, 6)) # 3
|
||||
print(search(A, 7)) # -1
|
||||
print(search(A, 30)) # 8
|
||||
</pre>
|
||||
</div>
|
||||
<div><br></div><div>Submit your solution in CodeGrade as <strong>binarysearch.py</strong>.</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,20 @@
|
||||
def search(A: list, item: int):
|
||||
low = 0
|
||||
high = len(A) - 1
|
||||
mid = 0
|
||||
while low <= high:
|
||||
mid = (high + low) // 2
|
||||
if A[mid] < item:
|
||||
low = mid + 1
|
||||
elif A[mid] > item:
|
||||
high = mid - 1
|
||||
else:
|
||||
return mid
|
||||
return -1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
A = [1, 2, 3, 6, 10, 15, 22, 27, 30, 31]
|
||||
print(search(A, 6)) # 3
|
||||
print(search(A, 7)) # -1
|
||||
print(search(A, 30)) # 8
|
||||
@@ -0,0 +1,97 @@
|
||||
class Node:
|
||||
def __init__(self, data=None):
|
||||
self.data = data
|
||||
self.next = None
|
||||
|
||||
|
||||
class LinkedList:
|
||||
def __init__(self):
|
||||
self.head = None
|
||||
|
||||
def append(self, data):
|
||||
new = Node(data)
|
||||
if self.head is None:
|
||||
self.head = new
|
||||
return
|
||||
last = self.head
|
||||
while (last.next):
|
||||
last = last.next
|
||||
last.next = new
|
||||
|
||||
def print(self):
|
||||
val = self.head
|
||||
while val is not None:
|
||||
if val.next is None:
|
||||
print(val.data)
|
||||
else:
|
||||
print(val.data, end=" -> ")
|
||||
val = val.next
|
||||
|
||||
def length(self):
|
||||
temp = self.head
|
||||
count = 0
|
||||
while (temp != None):
|
||||
count += 1
|
||||
temp = temp.next
|
||||
return count
|
||||
|
||||
def insert(self, data, index):
|
||||
new = Node(data)
|
||||
if (index == 0):
|
||||
new.next = self.head
|
||||
self.head = new
|
||||
else:
|
||||
temp = self.head
|
||||
for i in range(1, index):
|
||||
if (temp != None):
|
||||
temp = temp.next
|
||||
if (temp != None):
|
||||
new.next = temp.next
|
||||
temp.next = new
|
||||
else:
|
||||
print("\nThe previous node is null.")
|
||||
|
||||
def index(self, data):
|
||||
temp = self.head
|
||||
index = 0
|
||||
while (temp != None):
|
||||
if (temp.data == data):
|
||||
return index
|
||||
temp = temp.next
|
||||
index += 1
|
||||
return -1
|
||||
|
||||
def delete(self, index):
|
||||
if (index == 0):
|
||||
self.head = self.head.next
|
||||
elif (index >= self.length()):
|
||||
return
|
||||
else:
|
||||
temp = self.head
|
||||
for i in range(1, index):
|
||||
if (temp != None):
|
||||
temp = temp.next
|
||||
if (temp != None):
|
||||
temp.next = temp.next.next
|
||||
else:
|
||||
print("\nThe previous node is null.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
L = LinkedList()
|
||||
L.append(2)
|
||||
L.append(3)
|
||||
L.append(1)
|
||||
L.append(4)
|
||||
L.print() # 1 -> 3
|
||||
L.insert(4, 3)
|
||||
L.insert(1, 0)
|
||||
L.insert(3, 2)
|
||||
L.insert(2, 1)
|
||||
L.print() # 15 -> 1 -> 10 -> 3
|
||||
print(L.index(1)) # 1
|
||||
L.delete(0)
|
||||
L.delete(1)
|
||||
L.delete(4)
|
||||
L.delete(5)
|
||||
L.print() # 1 -> 10 -> 3
|
||||
@@ -0,0 +1,106 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Week 4: Programming Assignments (8 points)</title>
|
||||
<meta charset="utf-8">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h4><strong>Programming Assignments: Hashing</strong></h4>
|
||||
</div>
|
||||
<div>Both assignments are related to fixed sized hash tables. The hash tables store string (str) values.
|
||||
The hash value (slot) is calculated with the following hash function for strings:</div>
|
||||
<p></p>
|
||||
<pre>procedure hash(data):
|
||||
sum = 0
|
||||
for i = 0 to N-1 do
|
||||
sum += ascii(data[i])
|
||||
return sum % X
|
||||
</pre>
|
||||
<p></p>
|
||||
<div>where N is the length of the string (data), <span style="color: rgb(33, 37, 41); font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 14px;">% </span>is the symbol for the mod operation and <span style="color: rgb(33, 37, 41); font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 14px;">X </span>is a parameter of the hash table. The ascii value of a character can be calculated with the function <strong><a href="https://www.w3schools.com/python/ref_func_ord.asp">ord</a></strong> in Python.</div>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
|
||||
<div>
|
||||
<h4><strong>Assignment 4.1: Linear Probing </strong>(4 points)</h4>
|
||||
</div>
|
||||
<div>Implement a fixed sized hash table in Python that uses <u>linear probing</u> for collision resolution.
|
||||
Create a class <strong>HashLinear</strong> which has the table size \(M\) as a input value when a object is created. The class has following methods:</div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li><strong>insert(data: str)</strong>: inserts new data into the hash table, no duplicates</li>
|
||||
<li><strong>delete(data: str)</strong>: removes data from the hash table</li>
|
||||
<li><strong>print()</strong>: prints the content of the hash table (the data string in each slot separated with a space; skip empty slots; see the example below)</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<div>For hashing use \(X = M\).</div>
|
||||
<p></p>
|
||||
<div>A code template with an example program (the hash table has the size of \(M=8\)): </div>
|
||||
<p></p>
|
||||
<div style="border:2px solid black">
|
||||
<pre>class HashLinear:
|
||||
# TODO
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
table = HashLinear(8)
|
||||
table.insert("BM40A1500")
|
||||
table.insert("fOo")
|
||||
table.insert("123")
|
||||
table.insert("Bar1")
|
||||
table.insert("10aaaa1")
|
||||
table.insert("BM40A1500")
|
||||
table.print() # 10aaaa1 BM40A1500 fOo 123 Bar1
|
||||
table.delete("fOo")
|
||||
table.delete("Some arbitary string which is not in the table")
|
||||
table.delete("123")
|
||||
table.print() # 10aaaa1 BM40A1500 Bar1
|
||||
</pre>
|
||||
</div>
|
||||
<div><br></div><div>Submit your solution in CodeGrade as <strong>hashlinear.py</strong>.</div>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
|
||||
<div>
|
||||
<h4><strong>Assignment 4.1: Bucket Hashing </strong>(4 points)</h4>
|
||||
</div>
|
||||
<div>Implement a fixed sized hash table in Python that uses <u>bucket hashing</u> for collision resolution.
|
||||
Create a class <strong>HashBucket</strong> which has the table size \(M\) and number of equal sized buckets \(B\) as the input values when a object is created.
|
||||
The hash table has a overflow array of size \(M\). The class has the following methods:</div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li><strong>insert(data)</strong>: inserts new data in the hash table, no duplicates</li>
|
||||
<li><strong>delete(data)</strong>: removes data from the hash table</li>
|
||||
<li><strong>print()</strong>: prints the content of the hash table and the overflow array (the data string in each slot followed by the data in the overflow array; slots separated with a space and empty slots skipped; see the example below)</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<div>For hashing use \(X = B\). Filling the buckets starts from the top and overflow values are appended to the end of the overflow array. </div>
|
||||
<p></p>
|
||||
<div>A code template with an example program (the hash table has the size of \(M=8\) and has \(B=4\) buckets):<br></div>
|
||||
<p></p>
|
||||
<div style="border:2px solid black"><pre>class HashBucket:
|
||||
# TODO
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
table = HashBucket(8, 4)
|
||||
table.insert("BM40A1500")
|
||||
table.insert("fOo")
|
||||
table.insert("123")
|
||||
table.insert("Bar1")
|
||||
table.insert("10aaaa1")
|
||||
table.insert("BM40A1500")
|
||||
table.print() # fOo BM40A1500 123 Bar1 10aaaa1
|
||||
table.delete("fOo")
|
||||
table.delete("Some arbitary string which is not in the table")
|
||||
table.delete("123")
|
||||
table.print() # BM40A1500 Bar1 10aaaa1
|
||||
</pre>
|
||||
</div>
|
||||
<div><br></div><div>Submit your solution in CodeGrade as <strong>hashbucket.py</strong>.</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,79 @@
|
||||
def hash(S, size):
|
||||
num = 0
|
||||
for i in range(0, len(S)):
|
||||
num += ord(S[i])
|
||||
return num % size
|
||||
|
||||
# Hash table with bucket hashing and overflow array
|
||||
# Class HashBucket which has the table size M and number of equal sized buckets B as the input values when a object is created. Size of one bucket is M/B. The hash table has a overflow array of size M.
|
||||
|
||||
|
||||
class HashBucket:
|
||||
def __init__(self, M, B):
|
||||
self.M = M
|
||||
self.B = B
|
||||
self.table = [[] for i in range(0, M)]
|
||||
self.overflow = []
|
||||
|
||||
# No duplicate strings are allowed
|
||||
def insert(self, S):
|
||||
h = hash(S, self.B)
|
||||
if S in self.table[h]:
|
||||
return
|
||||
elif S in self.overflow:
|
||||
return
|
||||
elif len(self.table[h]) < self.M / self.B:
|
||||
self.table[h].append(S)
|
||||
else:
|
||||
self.overflow.append(S)
|
||||
|
||||
def search(self, S):
|
||||
h = hash(S, self.B)
|
||||
if S in self.table[h]:
|
||||
return True
|
||||
elif S in self.overflow:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def delete(self, S):
|
||||
h = hash(S, self.B)
|
||||
if S in self.table[h]:
|
||||
self.table[h].remove(S)
|
||||
elif S in self.overflow:
|
||||
self.overflow.remove(S)
|
||||
else:
|
||||
print("String not found")
|
||||
|
||||
def print(self):
|
||||
for i in range(0, self.M):
|
||||
for j in range(0, len(self.table[i])):
|
||||
print(self.table[i][j], end=' ')
|
||||
for z in range(0, len(self.overflow)):
|
||||
print(self.overflow[z], end=' ')
|
||||
print()
|
||||
|
||||
|
||||
# Main program
|
||||
if __name__ == "__main__":
|
||||
table = HashBucket(20, 4)
|
||||
a = ["door", "billion", "how", "choice", "at", "husband", "truth", "song", "share", "develop", "Mr", "everybody", "common", "blood", "Democrat", "until", "stock", "southern", "song", "cover"
|
||||
]
|
||||
for i in a:
|
||||
table.insert(i)
|
||||
table.print()
|
||||
b = ["song", "develop", "choice", "common", "until", "how", "billion", "blood", "door", "truth"
|
||||
]
|
||||
for i in b:
|
||||
table.delete(i)
|
||||
table.print()
|
||||
table = HashBucket(8, 4)
|
||||
a = ["dinner", "while", "call", "relate",
|
||||
"be", "easy", "yourself", "decide"]
|
||||
for i in a:
|
||||
table.insert(i)
|
||||
table.print()
|
||||
b = ["relate", "call", "decide", "while"]
|
||||
for i in b:
|
||||
table.delete(i)
|
||||
table.print()
|
||||
@@ -0,0 +1,75 @@
|
||||
def hash(S, size):
|
||||
num = 0
|
||||
for i in range(0, len(S)):
|
||||
num += ord(S[i])
|
||||
return num % size
|
||||
|
||||
# Hash table with linear probing
|
||||
|
||||
|
||||
class HashLinear:
|
||||
def __init__(self, num):
|
||||
self.table = ["DELETED"] * num
|
||||
self.size = 0
|
||||
self.num = num
|
||||
|
||||
def insert(self, S):
|
||||
if self.search(S):
|
||||
return False
|
||||
h = hash(S, self.num)
|
||||
while self.table[h] != "DELETED" and self.table[h] != None:
|
||||
h = (h + 1) % self.num
|
||||
self.table[h] = S
|
||||
self.size += 1
|
||||
return True
|
||||
|
||||
def search(self, S):
|
||||
h = hash(S, self.num)
|
||||
while self.table[h] != "DELETED":
|
||||
if self.table[h] == S:
|
||||
return True
|
||||
h = (h + 1) % self.num
|
||||
return False
|
||||
|
||||
def find(self, S):
|
||||
h = hash(S, self.num)
|
||||
while self.table[h] != "DELETED":
|
||||
if self.table[h] == S:
|
||||
return h
|
||||
h = (h + 1) % self.num
|
||||
return -1
|
||||
|
||||
def delete(self, S):
|
||||
if not self.search(S):
|
||||
return False
|
||||
h = hash(S, self.num)
|
||||
if self.table[h] != S:
|
||||
while self.table[h] != S:
|
||||
h = (h + 1) % self.num
|
||||
self.table[h] = "DELETED"
|
||||
self.table[h] = None
|
||||
self.size -= 1
|
||||
return True
|
||||
|
||||
def print(self):
|
||||
for i in range(0, self.num):
|
||||
if self.table[i] != "DELETED" and self.table[i] != None:
|
||||
#print(i, self.table[i])
|
||||
print(self.table[i], end=' ')
|
||||
print()
|
||||
|
||||
def __str__(self):
|
||||
return str(self.table)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
table = HashLinear(20)
|
||||
a = ["town", "rather", "short", "toward", "employee", "player", "toward", "the", "of", "college",
|
||||
"in", "yes", "billion", "five", "wear", "last", "decade", "first", "training", "friend"]
|
||||
for i in a:
|
||||
table.insert(i)
|
||||
b = ["employee", "of", "toward", "in", "player",
|
||||
"town", "toward", "five", "rather", "yes"]
|
||||
for i in b:
|
||||
table.delete(i)
|
||||
table.print()
|
||||
@@ -0,0 +1,121 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Week 5: Programming Assignments (9 points)</title>
|
||||
<meta charset="utf-8">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h4><strong>Assignment 5.1: Binary Search Tree</strong> <span>(4 points)</span></h4>
|
||||
</div>
|
||||
|
||||
<div>Implement a binary seach tree in Python. The tree stores integers (keys) only.
|
||||
<p></p>
|
||||
<div>Create following classes:
|
||||
<ul>
|
||||
<ul>
|
||||
<li><strong>Node</strong> which stores the integer value (key) and links to its left and right child</li>
|
||||
<li><strong>BST</strong> maintains the binary search tree built with Node classes. </li>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div>Create following methods for class BTS:</div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li><strong>insert(key: int)</strong>: inserts a new key to the search tree, no duplicates.</li>
|
||||
<li><strong>search(key: int)</strong>: searches the key from the search tree and returns boolean True if the value is found, False otherwise.</li>
|
||||
<li><strong>preorder()</strong>: prints the content of the search tree in preorder. Implement the method using recursion.</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<p></p>
|
||||
<div>A code template with an example program: </div>
|
||||
<p></p>
|
||||
<div style="border:2px solid black">
|
||||
<pre>class Node:
|
||||
# TODO
|
||||
|
||||
|
||||
class BST:
|
||||
# TODO
|
||||
|
||||
if __name__ == "__main__":
|
||||
Tree = BST()
|
||||
keys = [5, 9, 1, 3, 7, 4, 6, 2]
|
||||
for key in keys:
|
||||
Tree.insert(key)
|
||||
|
||||
Tree.preorder() # 5 1 3 2 4 9 7 6
|
||||
print(Tree.search(6)) # True
|
||||
print(Tree.search(8)) # False
|
||||
</pre>
|
||||
</div>
|
||||
<p></p>
|
||||
<div>Submit your solution in CodeGrade as <strong>bintree.py</strong>.</div>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
|
||||
<div>
|
||||
<h4><strong>Assignment 5.2: Removing a Node</strong> (3 points)</h4>
|
||||
</div>
|
||||
|
||||
<div>Add new method <strong>remove(key: int)</strong> to the BST class. The function removes the node which has the given key value while maintaining the binary search tree property.</div>
|
||||
<p></p>
|
||||
<div>An example program: </div>
|
||||
<p></p>
|
||||
<div style="border:2px solid black">
|
||||
<pre>if __name__ == "__main__":
|
||||
Tree = BST()
|
||||
keys = [5, 9, 1, 3, 7, 4, 6, 2]
|
||||
for key in keys:
|
||||
Tree.insert(key)
|
||||
|
||||
Tree.preorder() # 5 1 3 2 4 9 7 6
|
||||
Tree.remove(1)
|
||||
Tree.preorder() # 5 3 2 4 9 7 6
|
||||
Tree.remove(9)
|
||||
Tree.preorder() # 5 3 2 4 7 6
|
||||
Tree.remove(3)
|
||||
Tree.preorder() # 5 2 4 7 6
|
||||
</pre>
|
||||
</div>
|
||||
<p></p>
|
||||
<div>Submit your expanded version of <strong>bintree.py</strong> in CodeGrade.</div>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
|
||||
<div>
|
||||
<h4><strong>Assignment 5.3: Breadth-First Enumeration </strong>(2 points)</h4>
|
||||
</div>
|
||||
|
||||
<div>Breadth-First enumeration presents the nodes of the search tree level by level (or depth) unlike preorder
|
||||
enumeration which presents the left subtree completely before the right subtree.</div>
|
||||
<div><br></div>
|
||||
<div><img src="data/Animated_BFS.gif" alt="Breadth-first enumeration for a binary tree." width="187" height="175" class="img-fluid atto_image_button_text-bottom"> </div>
|
||||
<div><strong>Figure 1</strong><strong>:</strong> Breadth-First enumeration for a binary tree. Black: explored, grey: queued to be explored later on (source: <em>wikipedia.org</em>). </div>
|
||||
<p></p>
|
||||
<div>Add a new method <strong>breadthfirst()</strong> to the BST class which prints out the content of the search tree in breadth-first order.</div>
|
||||
<p></p>
|
||||
<div>An example program: </div>
|
||||
<p></p>
|
||||
<div style="border:2px solid black">
|
||||
<pre>if __name__ == "__main__":
|
||||
Tree = BST()
|
||||
keys = [5, 9, 1, 3, 7, 4, 6, 2]
|
||||
for key in keys:
|
||||
Tree.insert(key)
|
||||
|
||||
Tree.preorder() # 5 1 3 2 4 9 7 6
|
||||
Tree.breadthfirst() # 5 1 9 3 7 2 4 6
|
||||
</pre>
|
||||
</div>
|
||||
<p></p>
|
||||
<div>Submit your expanded version of <strong>bintree.py</strong> in CodeGrade.</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 32 KiB |
@@ -0,0 +1,122 @@
|
||||
class Node:
|
||||
def __init__(self, key):
|
||||
self.key = key
|
||||
self.left = None
|
||||
self.right = None
|
||||
|
||||
|
||||
class BST:
|
||||
def __init__(self):
|
||||
self.root = None
|
||||
|
||||
def insert(self, key):
|
||||
if self.root is None:
|
||||
self.root = Node(key)
|
||||
else:
|
||||
self._insert(self.root, key)
|
||||
|
||||
def _insert(self, node, key):
|
||||
if key < node.key:
|
||||
if node.left is None:
|
||||
node.left = Node(key)
|
||||
else:
|
||||
self._insert(node.left, key)
|
||||
elif key > node.key:
|
||||
if node.right is None:
|
||||
node.right = Node(key)
|
||||
else:
|
||||
self._insert(node.right, key)
|
||||
|
||||
def search(self, key):
|
||||
if self.root is None:
|
||||
return False
|
||||
else:
|
||||
return self._search(self.root, key)
|
||||
|
||||
def _search(self, node, key):
|
||||
if node is None:
|
||||
return False
|
||||
elif node.key == key:
|
||||
return True
|
||||
elif key < node.key:
|
||||
return self._search(node.left, key)
|
||||
else:
|
||||
return self._search(node.right, key)
|
||||
|
||||
def preorder(self):
|
||||
if self.root is None:
|
||||
return
|
||||
else:
|
||||
self._preorder(self.root)
|
||||
print()
|
||||
|
||||
def _preorder(self, node):
|
||||
if node is None:
|
||||
return
|
||||
print(node.key, end=" ")
|
||||
self._preorder(node.left)
|
||||
self._preorder(node.right)
|
||||
|
||||
def breadthfirst(self):
|
||||
if self.root is None:
|
||||
return
|
||||
else:
|
||||
self._breadthfirst(self.root)
|
||||
print()
|
||||
|
||||
def _breadthfirst(self, node):
|
||||
if node is None:
|
||||
return
|
||||
queue = []
|
||||
queue.append(node)
|
||||
while len(queue) > 0:
|
||||
print(queue[0].key, end=" ")
|
||||
node = queue.pop(0)
|
||||
if node.left is not None:
|
||||
queue.append(node.left)
|
||||
if node.right is not None:
|
||||
queue.append(node.right)
|
||||
|
||||
def remove(self, key):
|
||||
if self.root is None:
|
||||
return
|
||||
else:
|
||||
self._remove(self.root, key)
|
||||
|
||||
def _remove(self, node, key):
|
||||
if node is None:
|
||||
return node
|
||||
if key < node.key:
|
||||
node.left = self._remove(node.left, key)
|
||||
elif key > node.key:
|
||||
node.right = self._remove(node.right, key)
|
||||
else:
|
||||
if node.left is None:
|
||||
temp = node.right
|
||||
node = None
|
||||
return temp
|
||||
elif node.right is None:
|
||||
temp = node.left
|
||||
node = None
|
||||
return temp
|
||||
temp = self._minValueNode(node.right)
|
||||
node.key = temp.key
|
||||
node.right = self._remove(node.right, temp.key)
|
||||
return node
|
||||
|
||||
def _minValueNode(self, node):
|
||||
if node is None:
|
||||
return node
|
||||
while node.left is not None:
|
||||
node = node.left
|
||||
return node
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
Tree = BST()
|
||||
keys = [5, 9, 1, 3, 7, 4, 6, 2]
|
||||
for key in keys:
|
||||
Tree.insert(key)
|
||||
|
||||
Tree.preorder() # 5 1 3 2 4 9 7 6
|
||||
Tree.breadthfirst() # 5 1 9 3 7 2 4 6
|
||||
@@ -0,0 +1,128 @@
|
||||
class AVLNode:
|
||||
# Constructor for new node
|
||||
def __init__(self, key: int):
|
||||
self.key = key
|
||||
self.left = None
|
||||
self.right = None
|
||||
self.balance = 0
|
||||
|
||||
|
||||
class AVL:
|
||||
|
||||
# Constructor for new AVL
|
||||
def __init__(self):
|
||||
self.root = None
|
||||
self.is_balanced = True
|
||||
|
||||
# Inserts a new key to the search tree
|
||||
def insert(self, key):
|
||||
self.root = self.insert_help(self.root, key)
|
||||
|
||||
# Help function for insert
|
||||
def insert_help(self, root, key):
|
||||
if not root:
|
||||
root = AVLNode(key)
|
||||
self.is_balanced = False
|
||||
elif key < root.key:
|
||||
root.left = self.insert_help(root.left, key)
|
||||
if not self.is_balanced: # Check for possible rotations
|
||||
if root.balance >= 0: # No Rotations needed, update balance variables
|
||||
self.is_balanced = root.balance == 1
|
||||
root.balance -= 1
|
||||
# Rotation(s) needed
|
||||
else:
|
||||
if root.left.balance == -1:
|
||||
root = self.right_rotation(root) # Single rotation
|
||||
else:
|
||||
root = self.left_right_rotation(
|
||||
root) # Double rotation
|
||||
self.is_balanced = True
|
||||
elif key > root.key:
|
||||
root.right = self.insert_help(root.right, key)
|
||||
if not self.is_balanced: # Check for possible rotations
|
||||
if root.balance <= 0: # No Rotations needed, update balance variables
|
||||
self.is_balanced = root.balance == -1
|
||||
root.balance += 1
|
||||
# Rotation(s) needed
|
||||
else:
|
||||
if root.right.balance == 1:
|
||||
root = self.left_rotation(root)
|
||||
else:
|
||||
root = self.right_left_rotation(root)
|
||||
self.is_balanced = True
|
||||
return root
|
||||
|
||||
# Single rotation: right rotation around root
|
||||
def right_rotation(self, root):
|
||||
child = root.left # Set variable for child node
|
||||
root.left = child.right # Rotate
|
||||
child.right = root
|
||||
child.balance = root.balance = 0 # Fix balance variables
|
||||
return child
|
||||
|
||||
# Single rotation: left rotation around root
|
||||
def left_rotation(self, root):
|
||||
child = root.right # Set variable for child node
|
||||
root.right = child.left # Rotate
|
||||
child.left = root
|
||||
child.balance = root.balance = 0 # Fix balance variables
|
||||
return child
|
||||
|
||||
# Double rotation: left rotation around child node followed by right rotation around root
|
||||
def left_right_rotation(self, root):
|
||||
child = root.left
|
||||
# Set variables for child node and grandchild node
|
||||
grandchild = child.right
|
||||
child.right = grandchild.left # Rotate
|
||||
grandchild.left = child
|
||||
root.left = grandchild.right
|
||||
grandchild.right = root
|
||||
root.balance = child.balance = 0 # Fix balance variables
|
||||
if grandchild.balance == -1:
|
||||
root.balance = 1
|
||||
elif grandchild.balance == 1:
|
||||
child.balance = -1
|
||||
grandchild.balance = 0
|
||||
return grandchild
|
||||
|
||||
# Double rotation: right rotation around child node followed by left rotation around root
|
||||
def right_left_rotation(self, root):
|
||||
child = root.right
|
||||
# Set variables for child node and grandchild node
|
||||
grandchild = child.left
|
||||
child.left = grandchild.right # Rotate
|
||||
grandchild.right = child
|
||||
root.right = grandchild.left
|
||||
grandchild.left = root
|
||||
root.balance = child.balance = 0 # Fix balance variables
|
||||
if grandchild.balance == 1:
|
||||
root.balance = -1
|
||||
elif grandchild.balance == -1:
|
||||
child.balance = 1
|
||||
grandchild.balance = 0
|
||||
return grandchild
|
||||
|
||||
def preorder(self):
|
||||
print(self.preorder_help(self.root))
|
||||
|
||||
def preorder_help(self, root):
|
||||
if not root:
|
||||
return ''
|
||||
return str(root.key) + ';' + str(root.balance) + ' ' + self.preorder_help(root.left) + self.preorder_help(root.right)
|
||||
|
||||
# Returns the height of the tree
|
||||
def height(self):
|
||||
return self.height_help(self.root)
|
||||
|
||||
def height_help(self, root):
|
||||
if not root:
|
||||
return 0
|
||||
return 1 + max(self.height_help(root.left), self.height_help(root.right))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Make a list from 5 19 3 9 4 16 13 8 14 11 7 17 2 15 1 10 6 12 20 18
|
||||
Tree = AVL()
|
||||
for key in [5, 19, 3, 9, 4, 16, 13, 8, 14, 11, 7, 17, 2, 15, 1, 10, 6, 12, 20, 18]:
|
||||
Tree.insert(key)
|
||||
Tree.preorder()
|
||||
@@ -0,0 +1,172 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Week 6 Programming Assignments (8 points)</title>
|
||||
<meta charset="utf-8">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h4><strong>Assignment 6.1: The AVL Tree</strong><span> (5 points)</span></h4>
|
||||
</div>
|
||||
|
||||
<div>The following Python code implements the AVL tree which can do single and double rotations to the right. Finalize the class <strong>AVL</strong> by creating following methods:</div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li><strong>left_rotation(root: AVLNode)</strong>: symmetrical to
|
||||
<strong>right_rotation</strong>
|
||||
</li>
|
||||
<li><strong>right_left_rotation(root: AVLNode)</strong>: symmetrical to <strong>left_right_rotation</strong></li>
|
||||
<li><strong>preorder()</strong>: enumerates the keys and their balance values in preorder</li>
|
||||
<ul>
|
||||
<li>the format: 'key1:balance1 key2:balance2 key3:balance3'</li>
|
||||
</ul>
|
||||
</ul>
|
||||
</ul>
|
||||
<div>Finally, finalize the method <strong>insert_help</strong> so that it functions properly.</div>
|
||||
<p></p>
|
||||
<div><span>
|
||||
<div>Submit your solution in CodeGrade as <strong>AVL.py</strong>.</div>
|
||||
</span><br></div>
|
||||
<div>An example program: </div>
|
||||
<p></p>
|
||||
<div style="border:2px solid black">
|
||||
<pre>if __name__ == "__main__":
|
||||
Tree = AVL()
|
||||
for key in [9, 10, 11, 3, 2, 6, 4, 7, 5, 1]:
|
||||
Tree.insert(key)
|
||||
Tree.preorder() # 9;-1 4;0 2;0 1;0 3;0 6;0 5;0 7;0 10;1 11;0
|
||||
</pre>
|
||||
</div>
|
||||
<div><br></div>
|
||||
<div>A code template for the AVL tree: </div>
|
||||
<p></p>
|
||||
<div style="border:2px solid black">
|
||||
<pre>class AVLNode:
|
||||
# Constructor for new node
|
||||
def __init__(self, key: int):
|
||||
self.key = key
|
||||
self.left = None
|
||||
self.right = None
|
||||
self.balance = 0
|
||||
|
||||
|
||||
class AVL:
|
||||
|
||||
# Constructor for new AVL
|
||||
def __init__(self):
|
||||
self.root = None
|
||||
self.is_balanced = True
|
||||
|
||||
|
||||
# Inserts a new key to the search tree
|
||||
def insert(self, key):
|
||||
self.root = self.insert_help(self.root, key)
|
||||
|
||||
# Help function for insert
|
||||
def insert_help(self, root, key):
|
||||
if not root:
|
||||
root = AVLNode(key)
|
||||
self.is_balanced = False
|
||||
elif key < root.key:
|
||||
root.left = self.insert_help(root.left, key)
|
||||
if not self.is_balanced: # Check for possible rotations
|
||||
if root.balance >= 0: # No Rotations needed, update balance variables
|
||||
self.is_balanced = root.balance == 1
|
||||
root.balance -= 1
|
||||
else: # Rotation(s) needed
|
||||
if root.left.balance == -1:
|
||||
root = self.right_rotation(root) # Single rotation
|
||||
else:
|
||||
root = self.left_right_rotation(root) # Double rotation
|
||||
self.is_balanced = True
|
||||
elif key > root.key:
|
||||
root.right = self.insert_help(root.right, key)
|
||||
|
||||
# TODO
|
||||
|
||||
return root
|
||||
|
||||
|
||||
# Single rotation: right rotation around root
|
||||
def right_rotation(self, root):
|
||||
child = root.left # Set variable for child node
|
||||
root.left = child.right # Rotate
|
||||
child.right = root
|
||||
child.balance = root.balance = 0 # Fix balance variables
|
||||
return child
|
||||
|
||||
|
||||
# Single rotation: left rotation around root
|
||||
def left_rotation(self, root):
|
||||
# TODO
|
||||
|
||||
|
||||
# Double rotation: left rotation around child node followed by right rotation around root
|
||||
def left_right_rotation(self, root):
|
||||
child = root.left
|
||||
grandchild = child.right # Set variables for child node and grandchild node
|
||||
child.right = grandchild.left # Rotate
|
||||
grandchild.left = child
|
||||
root.left = grandchild.right
|
||||
grandchild.right = root
|
||||
root.balance = child.balance = 0 # Fix balance variables
|
||||
if grandchild.balance == -1:
|
||||
root.balance = 1
|
||||
elif grandchild.balance == 1:
|
||||
child.balance = -1
|
||||
grandchild.balance = 0
|
||||
return grandchild
|
||||
|
||||
|
||||
# Double rotation: right rotation around child node followed by left rotation around root
|
||||
def right_left_rotation(self, root):
|
||||
# TODO
|
||||
</pre>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<div>
|
||||
<h4><strong>Assignment 6.2: The Min Heap</strong> (3 points)</h4>
|
||||
</div>
|
||||
<div>Implement the min heap structure that stores positive integers in Python. Create class <strong>MinHeap</strong> which has following functions:</div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li><strong>push(key: int)</strong>: inserts a new key to the heap while maintaining the min heap property.<br></li>
|
||||
<li><strong>pop(): </strong>removes the smallest key from the heap and returns its value. </li>
|
||||
<li><strong>print()</strong>: prints the heap in breadth-first order<ul>
|
||||
<li>the format: key values separated by spaces (e.g. 1 2 3 4).<br></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</ul>
|
||||
<div>Make sure that the heap always maintains the min heap property. The best practice is to store the heap structure in a list where a key in index \(i\)</div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li>has a left child at index \(2i + 1\)</li>
|
||||
<li>has a right child at index \(2i + 2\)</li>
|
||||
<li>has its parent at index \(\lfloor \frac{i-1}{2} \rfloor\) (\(\lfloor \ldots \rfloor\) rounds down to the nearest integer)<br></li>
|
||||
</ul>
|
||||
</ul>
|
||||
<div>A code template an example program: </div>
|
||||
<p></p>
|
||||
<div style="border:2px solid black">
|
||||
<pre>class MinHeap:
|
||||
# TODO
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
items = [4, 8, 6, 5, 1, 2, 3]
|
||||
heap = MinHeap()
|
||||
[heap.push(key) for key in items]
|
||||
heap.print() # 1 4 2 8 5 6 3
|
||||
print(heap.pop()) # 1
|
||||
heap.print() # 2 4 3 8 5 6
|
||||
</pre>
|
||||
</div>
|
||||
<p></p>
|
||||
<div>Submit your solution in CodeGrade as <strong>minheap.py</strong>.</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,49 @@
|
||||
class MinHeap:
|
||||
def __init__(self):
|
||||
self.heap = []
|
||||
|
||||
def push(self, key):
|
||||
self.heap.append(key)
|
||||
self.bubble_up(len(self.heap) - 1)
|
||||
|
||||
def bubble_up(self, index):
|
||||
if index == 0:
|
||||
return
|
||||
parent = (index - 1) // 2
|
||||
if self.heap[parent] > self.heap[index]:
|
||||
self.heap[parent], self.heap[index] = self.heap[index], self.heap[parent]
|
||||
self.bubble_up(parent)
|
||||
|
||||
def pop(self):
|
||||
if len(self.heap) == 0:
|
||||
return None
|
||||
if len(self.heap) == 1:
|
||||
return self.heap.pop()
|
||||
self.heap[0], self.heap[-1] = self.heap[-1], self.heap[0]
|
||||
min = self.heap.pop()
|
||||
self.bubble_down(0)
|
||||
return min
|
||||
|
||||
def bubble_down(self, index):
|
||||
left = 2 * index + 1
|
||||
right = 2 * index + 2
|
||||
smallest = index
|
||||
if left < len(self.heap) and self.heap[left] < self.heap[smallest]:
|
||||
smallest = left
|
||||
if right < len(self.heap) and self.heap[right] < self.heap[smallest]:
|
||||
smallest = right
|
||||
if smallest != index:
|
||||
self.heap[smallest], self.heap[index] = self.heap[index], self.heap[smallest]
|
||||
self.bubble_down(smallest)
|
||||
|
||||
def print(self):
|
||||
print(' '.join(map(str, self.heap)))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
items = [4, 8, 6, 5, 1, 2, 3]
|
||||
heap = MinHeap()
|
||||
[heap.push(key) for key in items]
|
||||
heap.print() # 1 4 2 8 5 6 3
|
||||
print(heap.pop()) # 1
|
||||
heap.print() # 2 4 3 8 5 6
|
||||
@@ -0,0 +1,121 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Week 7 Programming Assignments (9 points)</title>
|
||||
<meta charset="utf-8">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h4><span>Assignment 7.1: The Quicksort</span> <span style="font-weight: normal;">(4 point)</span><br></h4>
|
||||
</div>
|
||||
<div>Familiarize yourself with the principle of Quicksort from the background material and implement Quicksort in Python.
|
||||
Create a function <strong>qsort(A: list, i: int, j: int)</strong> which has the following input parameters:</div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li>\(A\): a (whole) list of integers</li>
|
||||
<li>\(i\): a start index of selected partition</li>
|
||||
<li>\(j\): a end index of selected partition</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<div>The function has no return value since the sorting process is done to the original list. You can select the pivot index/value as you wish.</div>
|
||||
<br>
|
||||
<div>Limits:</div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li>maximum list size is \(10^4\)</li>
|
||||
<li>all elements of the list are integers between \(1 \dots 10^4\)</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<div>A code template with an example program: </div>
|
||||
<p></p>
|
||||
<div style="border:2px solid black">
|
||||
<pre>def qsort(A, i, j):
|
||||
# TODO
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
A = [9, 7, 1, 8, 5, 3, 6, 2, 4]
|
||||
print(A) # [9, 7, 1, 8, 5, 3, 6, 2, 4]
|
||||
qsort(A, 0, len(A)-1)
|
||||
print(A) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
</pre>
|
||||
</div>
|
||||
<br>
|
||||
<div>Submit your solution in CodeGrade as <strong>quicksort.py</strong>.</div>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
|
||||
<div>
|
||||
<h4>Assignment 7.2: Car Sales<span style="font-weight: normal;"> (3 points)</span><br></h4>
|
||||
</div>
|
||||
<div>A car shop has cars \(A = [a_1, a_2, ..., a_n]\) (one of each) where \(a_i\) is the price of the car \(i\). Customers \(B = [b_1, b_2, ..., b_m]\) arrive to the shop.
|
||||
\(b_i\) is the price that the customer \(i\) can afford. What is the maximum amount of sales that can be made?<br></div>
|
||||
<br>
|
||||
<div>For example the shop has cars \(A = [20, 10, 15, 26]\) and there are customers \(B = [11, 25, 15, 9]\) it is possible to make \(3\) sales.</div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li>The first customer (\(11\)) gets car that cost \(10\), The second customer (\(25\)) gets the car that cost \(20\), and the third customer (\(15\)) gets the car that cost \(15\).</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<div>Create a function <strong>sales(A: list, B: list)</strong> in Python which returns the number of possible sales.</div>
|
||||
<br>
|
||||
<div>Limits:</div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li>\(1 \leq n,m \leq 10^4\)</li>
|
||||
<li>\(1 \leq a_i, b_i \leq 10^4\)</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<div>Target: the function performs in \(\Theta(n \log n)\) time.</div>
|
||||
<br>
|
||||
<div>A code template with an example program: </div>
|
||||
<p></p>
|
||||
<div style="border:2px solid black">
|
||||
<pre>def sales(cars, customers) -> int:
|
||||
# TODO
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(sales([20, 10, 15], [11, 25, 15])) # 3
|
||||
print(sales([13, 7, 2, 3, 12, 4, 19], [3, 25, 16, 14])) # 4
|
||||
print(sales([24, 6, 20, 21, 12, 5], [25, 1, 24, 15])) # 3
|
||||
print(sales([14, 9, 10, 15, 18, 20], [24, 17, 9, 22, 12, 4])) # 5
|
||||
</pre>
|
||||
</div>
|
||||
<br>
|
||||
<div>Submit your solution in CodeGrade as <strong>sales.py</strong>.</div>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
|
||||
<div>
|
||||
<h4>Assignment 7.3: Subsets<span style="font-weight: normal;"> (2 points)</span><br></h4>
|
||||
</div>
|
||||
<div>A given set that has numbers from \(1\) to \(N\) in increasing order (\(\{1, 2, 3, 4, \dots, N\}\)), create a function <strong>subsets(N: int)</strong> in Python which produces a list of all possible subsets.</div>
|
||||
<br>
|
||||
<div>For example when \(N = 3\) the subsets are \([1]\), \([2]\), \([1, 2]\), \([3]\), \([1, 3]\), \([2, 3]\) and \([1, 2, 3]\).</div>
|
||||
<br>
|
||||
<div>The function must return the list of subsets in specific order (see the example program below).<br></div><p></p><div>Limits: \(1 \leq N \leq 20\)<br></div><div><br></div><div>A code template with an example program:
|
||||
</div><p></p>
|
||||
<div style="border:2px solid black">
|
||||
<pre>def subsets(n: int) -> list:
|
||||
# TODO
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(subsets(3)) # [[1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
|
||||
|
||||
print(subsets(4)) # [[1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3],
|
||||
# [4], [1, 4], [2, 4], [1, 2, 4], [3, 4], [1, 3, 4],
|
||||
# [2, 3, 4], [1, 2, 3, 4]]
|
||||
|
||||
S = subsets(10)
|
||||
print(S[95]) # [6, 7]
|
||||
print(S[254]) # [1, 2, 3, 4, 5, 6, 7, 8]
|
||||
print(S[826]) # [1, 2, 4, 5, 6, 9, 10]
|
||||
</pre>
|
||||
</div>
|
||||
<p><br></p><p>Submit your solution in CodeGrade as <strong>subsets.py</strong></p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,24 @@
|
||||
def qsort(A, i, j):
|
||||
if i >= j:
|
||||
return
|
||||
p = partition(A, i, j)
|
||||
qsort(A, i, p-1)
|
||||
qsort(A, p+1, j)
|
||||
|
||||
|
||||
def partition(A, i, j):
|
||||
pivot = A[j]
|
||||
p = i
|
||||
for q in range(i, j):
|
||||
if A[q] < pivot:
|
||||
A[p], A[q] = A[q], A[p]
|
||||
p += 1
|
||||
A[p], A[j] = A[j], A[p]
|
||||
return p
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
A = [9, 7, 1, 8, 5, 3, 6, 2, 4]
|
||||
print(A) # [9, 7, 1, 8, 5, 3, 6, 2, 4]
|
||||
qsort(A, 0, len(A)-1)
|
||||
print(A) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
@@ -0,0 +1,18 @@
|
||||
def sales(cars, customers) -> int:
|
||||
cars.sort()
|
||||
customers.sort()
|
||||
sales = 0
|
||||
for customer in customers:
|
||||
for car in cars:
|
||||
if car <= customer:
|
||||
sales += 1
|
||||
cars.remove(car)
|
||||
break
|
||||
return sales
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(sales([20, 10, 15], [11, 25, 15])) # 3
|
||||
print(sales([13, 7, 2, 3, 12, 4, 19], [3, 25, 16, 14])) # 4
|
||||
print(sales([24, 6, 20, 21, 12, 5], [25, 1, 24, 15])) # 3
|
||||
print(sales([14, 9, 10, 15, 18, 20], [24, 17, 9, 22, 12, 4])) # 5
|
||||
@@ -0,0 +1,26 @@
|
||||
def subsets(a: int) -> list:
|
||||
s = [i for i in range(1, a+1)]
|
||||
return [x for x in get_sets(s) if x]
|
||||
|
||||
|
||||
def get_sets(s):
|
||||
size = 2**len(s)
|
||||
for cnt in range(0, size):
|
||||
final = []
|
||||
for i in range(0, len(s)):
|
||||
if ((cnt & (1 << i)) > 0):
|
||||
final.append(s[i])
|
||||
yield final
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(subsets(3)) # [[1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
|
||||
|
||||
print(subsets(4)) # [[1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3],
|
||||
# [4], [1, 4], [2, 4], [1, 2, 4], [3, 4], [1, 3, 4],
|
||||
# [2, 3, 4], [1, 2, 3, 4]]
|
||||
|
||||
S = subsets(10)
|
||||
print(S[95]) # [6, 7]
|
||||
print(S[254]) # [1, 2, 3, 4, 5, 6, 7, 8]
|
||||
print(S[826]) # [1, 2, 4, 5, 6, 9, 10]
|
||||
@@ -0,0 +1,103 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Week 8 Programming Assignments (8 points)</title>
|
||||
<meta charset="utf-8">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<h4><strong>Assignment 8.1: Jumps</strong> (4 points)</h4>
|
||||
<div>You are playing a game which has \(n\) levels. You start from the level \(0\) and your goal is to reach the level
|
||||
\(n\) by jumping from a level to another. From every level you're able to jump only to \(a\) or \(b\)
|
||||
levels higher. In how many different ways can you complete the game?
|
||||
</div>
|
||||
<br>
|
||||
<div>e.g.: let \(n=8\), \(a=2\) and \(b=3\), there are \(4\) different ways to pass the game.</div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li>\(0\rightarrow 2\rightarrow 4\rightarrow 6\rightarrow 8\)</li>
|
||||
<li>\(0\rightarrow 2\rightarrow 5\rightarrow 8\)</li>
|
||||
<li>\(0\rightarrow 3\rightarrow 5\rightarrow 8\)</li>
|
||||
<li>\(0\rightarrow 3\rightarrow 6\rightarrow 8\)</li>
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
<div>Create a function <strong>jumps(n: int, a: int, b: int)</strong> in Python which returns the number of all possible ways to complete the game.</div>
|
||||
<br>
|
||||
|
||||
<div>Limist (you can assume that):</div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li>\(n \leq 10000\)</li>
|
||||
<li>\(1 \leq a < b \leq n\)</li>
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
<div>Targets:</div>
|
||||
<ol>
|
||||
<li>correct solution: \(2\) points</li>
|
||||
<li>performs in \(\Theta (n)\) time: \(+2\) points (the solution must be correct)</li>
|
||||
</ol>
|
||||
|
||||
<div>A code template with an example program:</div>
|
||||
<br>
|
||||
<div style="border: 2px solid black">
|
||||
<pre>def jumps(n, a, b):
|
||||
# TODO
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(jumps(4, 1, 2)) # 5
|
||||
print(jumps(8, 2, 3)) # 4
|
||||
print(jumps(11, 6, 7)) # 0
|
||||
print(jumps(30, 3, 5)) # 58
|
||||
print(jumps(100, 4, 5)) # 1167937
|
||||
</pre>
|
||||
</div>
|
||||
<br>
|
||||
<div>Submit your solution in CodeGrade as <strong>jumps.py</strong>.</div>
|
||||
<br><br>
|
||||
<br>
|
||||
|
||||
<div>
|
||||
<h4><strong>Assignment 8.2: All Sums </strong>(4 points)</h4>
|
||||
</div>
|
||||
<div>\(A\) is a list consisting of \(n\) integers. How many different sums can be generated with the given integers?</div>
|
||||
<br>
|
||||
<div>For example:</div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li>list \([1, 2, 3]\) has 6 possible sums: \(1\), \(2\), \(3\), \(4\), \(5\) and \(6\)</li>
|
||||
<li>list \([2, 2, 3]\) has 5 possible sums: \(2\), \(3\), \(4\), \(5\) and \(7\)</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<div>Create a function <strong>sums(A: list)</strong> in Python which computes the number of all different sums.</div>
|
||||
<br>
|
||||
<div>Limits (you can assume that): \(1 \leq n, a_i \leq 100\)</div>
|
||||
<br>
|
||||
<div>Target: The algorithm computes the awnser in less than \(1\) second (in CodeGrade)</div>
|
||||
<ol>
|
||||
<li>correct solution: \(2\) points</li>
|
||||
<li>performs in \(\Theta (n^3)\) time: \(+2\) points (the solution be must correct)</li>
|
||||
<ul>
|
||||
<li>(extra: consider the running time of your algorithm)</li>
|
||||
</ul>
|
||||
</ol>
|
||||
<div>A code template with an example program:</div>
|
||||
<br>
|
||||
<div style="border: 2px solid black">
|
||||
<pre>def sums(items):
|
||||
# TODO
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(sums([1, 2, 3])) # 6
|
||||
print(sums([2, 2, 3])) # 5
|
||||
print(sums([1, 3, 5, 1, 3, 5])) # 18
|
||||
print(sums([1, 15, 5, 23, 100, 55, 2])) # 121
|
||||
</pre>
|
||||
</div>
|
||||
<br>
|
||||
<div>Submit your solution in CodeGrade as <strong>sums.py</strong>.</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,24 @@
|
||||
def jumps(n, a, b):
|
||||
if n < 0:
|
||||
return 0
|
||||
if n == 0:
|
||||
return 1
|
||||
|
||||
# Initialize an array to store the number of ways to reach each position
|
||||
num_ways = [0] * (n + 1)
|
||||
num_ways[0] = 1
|
||||
|
||||
# Calculate the number of ways to reach each position
|
||||
for i in range(n + 1):
|
||||
num_ways[i] += num_ways[i - a]
|
||||
num_ways[i] += num_ways[i - b]
|
||||
|
||||
return num_ways[n]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(jumps(4, 1, 2)) # 5
|
||||
print(jumps(8, 2, 3)) # 4
|
||||
print(jumps(11, 6, 7)) # 0
|
||||
print(jumps(30, 3, 5)) # 58
|
||||
print(jumps(100, 4, 5)) # 1167937
|
||||
@@ -0,0 +1,15 @@
|
||||
def sums(arr):
|
||||
sums = set()
|
||||
for i in range(len(arr)):
|
||||
for j in range(i, len(arr)):
|
||||
for k in range(j, len(arr)):
|
||||
sums.add(arr[i] + arr[j] + arr[k])
|
||||
return len(sums)
|
||||
|
||||
|
||||
# Test
|
||||
if __name__ == "__main__":
|
||||
print(sums([1, 2, 3])) # 6
|
||||
print(sums([2, 2, 3])) # 5
|
||||
print(sums([1, 3, 5, 1, 3, 5])) # 18
|
||||
print(sums([1, 15, 5, 23, 100, 55, 2])) # 121
|
||||
@@ -0,0 +1,32 @@
|
||||
def sums(arr):
|
||||
# Create a set to store all the unique sums
|
||||
sums = set()
|
||||
|
||||
# Initialize a list with length equal to the length of arr
|
||||
# to store the previous results
|
||||
prev_results = [0] * len(arr)
|
||||
|
||||
# Iterate through each element in arr
|
||||
for i in range(len(arr)):
|
||||
# Initialize a temporary set to store the new sums
|
||||
temp = set()
|
||||
# Iterate through all the previous results
|
||||
for j in range(i):
|
||||
# Add the current element to each of the previous sums
|
||||
# and add the new sum to the set
|
||||
temp.add(arr[i] + prev_results[j])
|
||||
# Add the current element to the set
|
||||
temp.add(arr[i])
|
||||
# Update the list of previous results with the new sums
|
||||
prev_results[i] = temp
|
||||
# Update the set of all sums with the new sums
|
||||
sums = sums.union(temp)
|
||||
return len(sums)
|
||||
|
||||
|
||||
# Test
|
||||
if __name__ == "__main__":
|
||||
print(sums([1, 2, 3])) # 6
|
||||
print(sums([2, 2, 3])) # 5
|
||||
print(sums([1, 3, 5, 1, 3, 5])) # 18
|
||||
print(sums([1, 15, 5, 23, 100, 55, 2])) # 121
|
||||
@@ -0,0 +1,118 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Week 9 Programming Assignments (8 points)</title>
|
||||
<meta charset="utf-8">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h4><span>Assignment 9.1: Creating a Graph</span> <span style="font-weight: normal;">(4 points)</span><br></h4>
|
||||
</div>
|
||||
<div><span class="" style="color: rgb(239, 69, 64);"></span>Your task is to create a class <strong>Graph</strong> in python which stores a weighted directed or undirected graph structure. The initializer method takes a \(V \times V\) weighted adjacency matrix as an input value (\(V\) sized list of \(V\) sized lists).
|
||||
The class must have following methods:</div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li><strong>df_print(start: int)</strong>: prints out the graph in depth-first order from the start vertex (vertex numbers separated by space).</li>
|
||||
<li><strong>bf_print(start: int)</strong>: prints out the graph in breadth-first order from the start vertex.</li>
|
||||
<li><strong>weight(vertex1: int, vertex2: int)</strong>: returns the weight from vertex1 to vertex2, returns -1 if there is no edge between the vertices.</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<div>where start vertex is labeled between \(0\ ...\ V-1\).</div>
|
||||
<p></p>
|
||||
<div>Feel free to store the graph structure to your class as you wish as long as the given functions above work as intended. You can use the adjacency matrix
|
||||
or create a adjacency list to keep track of neighbors of each vertex (or even both).</div>
|
||||
<div><br>
|
||||
</div>
|
||||
<div><strong><span class="" style="background-color: rgb(255, 255, 255); color: rgb(239, 69, 64);">Note: </span></strong><span class="" style="background-color: rgb(255, 255, 255); color: rgb(239, 69, 64);">This graph class will be used in following assignments related to graphs so it is recommended to complete this assignment before moving to others.</span></div>
|
||||
<p></p>
|
||||
<div><span>A code template with an example program </span>for the directed graph below:</div>
|
||||
<p></p>
|
||||
<!-- Add other path in Moodle! --> <img src="data/examplegraph.png?time=1657884314459" alt="Example Graph" class="img-responsive atto_image_button_text-bottom" width="306" height="239">
|
||||
<p></p>
|
||||
<div style="border:2px solid black">
|
||||
<pre>class Graph:
|
||||
# TODO
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
matrix = [
|
||||
# 0 1 2 3 4 5
|
||||
[0, 0, 7, 0, 9, 0], # 0
|
||||
[0, 0, 0, 0, 0, 0], # 1
|
||||
[0, 5, 0, 1, 0, 2], # 2
|
||||
[6, 0, 0, 0, 0, 2], # 3
|
||||
[0, 0, 0, 0, 0, 1], # 4
|
||||
[0, 6, 0, 0, 0, 0] # 5
|
||||
]
|
||||
|
||||
graph = Graph(matrix)
|
||||
|
||||
graph.df_print(0) # 0 2 1 3 5 4
|
||||
graph.bf_print(0) # 0 2 4 1 3 5
|
||||
print(graph.weight(0, 2)) # 7
|
||||
print(graph.weight(3, 4)) # -1
|
||||
</pre>
|
||||
</div>
|
||||
<p></p>
|
||||
<div>Submit your solution in CodeGrade as <strong>graph.py</strong>.</div>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
|
||||
<div>
|
||||
<h4><span><span>Assignment 9.2: Dijkstra's Algoritmh</span></span> <span style="font-weight: normal;">(4 points)</span><br></h4>
|
||||
</div>
|
||||
<div>With Dijkstra's algorithm we not only get the shortest paths from the start vertex to other vertices but we can build a new
|
||||
graph with only the arcs that constructs those paths.</div>
|
||||
<br>
|
||||
<div>Create a function <strong>dijkstragraph(graph: Graph, start: int)</strong> that takes a Graph object and the start vertex as an input value. The function
|
||||
returns a new Graph object that has only the arcs that constructs the shortest paths computed by Dijkstra's algorithm. The new graph will be directed despite
|
||||
whether the original graph was directed or undirected.</div>
|
||||
<br>
|
||||
<div>For example the on the left we have the original directed graph and on the right we have a graph that the function produces, starting from vertex \(0\).</div>
|
||||
<br>
|
||||
<p> <img src="data/dijkstra.png?time=1657884289742" alt="Example Graph" class="img-responsive atto_image_button_text-bottom" width="776" height="240">
|
||||
</p><br>
|
||||
<div><span>A code template with an example program </span>for the graph:</div>
|
||||
<br>
|
||||
<div style="border:2px solid black">
|
||||
<pre>from graph import Graph
|
||||
|
||||
|
||||
def dijkstragraph(graph, start):
|
||||
# TODO
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
matrix = [
|
||||
[0, 25, 6, 0, 0, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 10, 3, 0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 7, 0, 25, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 12, 15, 4, 15, 20, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 2, 0, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 2, 0],
|
||||
[0, 0, 0, 0, 0, 0, 0, 8, 13, 15],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 5],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
|
||||
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
]
|
||||
|
||||
graph = Graph(matrix)
|
||||
|
||||
new_graph = dijkstragraph(graph, 0)
|
||||
new_graph.df_print(0) # 0 1 2 3 4 5 6 7 9 8
|
||||
new_graph.bf_print(0) # 0 1 2 3 4 5 6 7 8 9
|
||||
print(new_graph.weight(3, 6)) # 4
|
||||
print(new_graph.weight(5, 8)) # -1
|
||||
|
||||
</pre>
|
||||
</div>
|
||||
<br>
|
||||
<div>Submit your solution in CodeGrade as <strong>dijkstra.py</strong> including your graph class in <strong>graph.py</strong> (Assignment 9.1).</div>
|
||||
<br>
|
||||
<div>Hint: try to do the Dijkstra's algorithm and new graph construction separately. What other information can we get while running Dijkstra's algorithm?</div>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 18 KiB |
@@ -0,0 +1,53 @@
|
||||
class Graph:
|
||||
def __init__(self, adj_matrix):
|
||||
self.adj_matrix = adj_matrix
|
||||
self.V = len(adj_matrix)
|
||||
|
||||
def df_print(self, start):
|
||||
visited = [False] * self.V
|
||||
self.dfs(start, visited)
|
||||
print()
|
||||
|
||||
def dfs(self, start, visited):
|
||||
visited[start] = True
|
||||
print(start, end=' ')
|
||||
for i in range(self.V):
|
||||
if self.adj_matrix[start][i] > 0 and not visited[i]:
|
||||
self.dfs(i, visited)
|
||||
|
||||
def bf_print(self, start):
|
||||
visited = [False] * self.V
|
||||
queue = []
|
||||
queue.append(start)
|
||||
visited[start] = True
|
||||
while queue:
|
||||
start = queue.pop(0)
|
||||
print(start, end=' ')
|
||||
for i in range(self.V):
|
||||
if self.adj_matrix[start][i] > 0 and not visited[i]:
|
||||
queue.append(i)
|
||||
visited[i] = True
|
||||
print()
|
||||
|
||||
def weight(self, vertex1, vertex2):
|
||||
return self.adj_matrix[vertex1][vertex2] if self.adj_matrix[vertex1][vertex2] > 0 else -1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
matrix = [
|
||||
# 0 1 2 3 4 5
|
||||
[0, 0, 7, 0, 9, 0], # 0
|
||||
[0, 0, 0, 0, 0, 0], # 1
|
||||
[0, 5, 0, 1, 0, 2], # 2
|
||||
[6, 0, 0, 0, 0, 2], # 3
|
||||
[0, 0, 0, 0, 0, 1], # 4
|
||||
[0, 6, 0, 0, 0, 0] # 5
|
||||
]
|
||||
|
||||
graph = Graph(matrix)
|
||||
|
||||
graph.df_print(0) # 0 2 1 3 5 4
|
||||
graph.bf_print(0) # 0 2 4 1 3 5
|
||||
print(graph.weight(0, 2)) # 7
|
||||
print(graph.weight(3, 4)) # -1
|
||||