Skip to content

Commit 267b5ef

Browse files
brunohadlichcclauss
authored andcommitted
Added doctest and more explanation about Dijkstra execution. (TheAlgorithms#1014)
* Added doctest and more explanation about Dijkstra execution. * tests were not passing with python2 due to missing __init__.py file at number_theory folder * Removed the dot at the beginning of the imported modules names because 'python3 -m doctest -v data_structures/hashing/*.py' and 'python3 -m doctest -v data_structures/stacks/*.py' were failing not finding hash_table.py and stack.py modules. * Moved global code to main scope and added doctest for project euler problems 1 to 14. * Added test case for negative input. * Changed N variable to do not use end of line scape because in case there is a space after it the script will break making it much more error prone. * Added problems description and doctests to the ones that were missing. Limited line length to 79 and executed python black over all scripts. * Changed the way files are loaded to support pytest call. * Added __init__.py to problems to make them modules and allow pytest execution. * Added project_euler folder to test units execution * Changed 'os.path.split(os.path.realpath(__file__))' to 'os.path.dirname()'
1 parent 2fb3bee commit 267b5ef

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+2651
-1468
lines changed

.travis.yml

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ script:
2626
matrix
2727
networking_flow
2828
other
29+
project_euler
2930
searches
3031
sorts
3132
strings

data_structures/hashing/double_hash.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env python3
22

3-
from .hash_table import HashTable
3+
from hash_table import HashTable
44
from number_theory.prime_numbers import next_prime, check_prime
55

66

data_structures/hashing/hash_table_with_linked_list.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from .hash_table import HashTable
1+
from hash_table import HashTable
22
from collections import deque
33

44

data_structures/hashing/number_theory/__init__.py

Whitespace-only changes.

data_structures/hashing/quadratic_probing.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env python3
22

3-
from .hash_table import HashTable
3+
from hash_table import HashTable
44

55

66
class QuadraticProbing(HashTable):

data_structures/stacks/infix_to_postfix_conversion.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from __future__ import absolute_import
33
import string
44

5-
from .Stack import Stack
5+
from stack import Stack
66

77
__author__ = 'Omkar Pathak'
88

graphs/dijkstra.py

+94-23
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,50 @@
11
"""pseudo-code"""
22

33
"""
4-
DIJKSTRA(graph G, start vertex s,destination vertex d):
5-
// all nodes initially unexplored
6-
let H = min heap data structure, initialized with 0 and s [here 0 indicates the distance from start vertex]
7-
while H is non-empty:
8-
remove the first node and cost of H, call it U and cost
9-
if U is not explored
10-
mark U as explored
11-
if U is d:
12-
return cost // total cost from start to destination vertex
13-
for each edge(U, V): c=cost of edge(u,V) // for V in graph[U]
14-
if V unexplored:
15-
next=cost+c
16-
add next,V to H (at the end)
4+
DIJKSTRA(graph G, start vertex s, destination vertex d):
5+
6+
//all nodes initially unexplored
7+
8+
1 - let H = min heap data structure, initialized with 0 and s [here 0 indicates
9+
the distance from start vertex s]
10+
2 - while H is non-empty:
11+
3 - remove the first node and cost of H, call it U and cost
12+
4 - if U has been previously explored:
13+
5 - go to the while loop, line 2 //Once a node is explored there is no need
14+
to make it again
15+
6 - mark U as explored
16+
7 - if U is d:
17+
8 - return cost // total cost from start to destination vertex
18+
9 - for each edge(U, V): c=cost of edge(U,V) // for V in graph[U]
19+
10 - if V explored:
20+
11 - go to next V in line 9
21+
12 - total_cost = cost + c
22+
13 - add (total_cost,V) to H
23+
24+
You can think at cost as a distance where Dijkstra finds the shortest distance
25+
between vertexes s and v in a graph G. The use of a min heap as H guarantees
26+
that if a vertex has already been explored there will be no other path with
27+
shortest distance, that happens because heapq.heappop will always return the
28+
next vertex with the shortest distance, considering that the heap stores not
29+
only the distance between previous vertex and current vertex but the entire
30+
distance between each vertex that makes up the path from start vertex to target
31+
vertex.
1732
"""
33+
1834
import heapq
1935

2036

2137
def dijkstra(graph, start, end):
38+
"""Return the cost of the shortest path between vertexes start and end.
39+
40+
>>> dijkstra(G, "E", "C")
41+
6
42+
>>> dijkstra(G2, "E", "F")
43+
3
44+
>>> dijkstra(G3, "E", "F")
45+
3
46+
"""
47+
2248
heap = [(0, start)] # cost from start node,end node
2349
visited = set()
2450
while heap:
@@ -28,20 +54,65 @@ def dijkstra(graph, start, end):
2854
visited.add(u)
2955
if u == end:
3056
return cost
31-
for v, c in G[u]:
57+
for v, c in graph[u]:
3258
if v in visited:
3359
continue
3460
next = cost + c
3561
heapq.heappush(heap, (next, v))
36-
return (-1, -1)
62+
return -1
63+
64+
65+
G = {
66+
"A": [["B", 2], ["C", 5]],
67+
"B": [["A", 2], ["D", 3], ["E", 1], ["F", 1]],
68+
"C": [["A", 5], ["F", 3]],
69+
"D": [["B", 3]],
70+
"E": [["B", 4], ["F", 3]],
71+
"F": [["C", 3], ["E", 3]],
72+
}
73+
74+
"""
75+
Layout of G2:
76+
77+
E -- 1 --> B -- 1 --> C -- 1 --> D -- 1 --> F
78+
\ /\
79+
\ ||
80+
----------------- 3 --------------------
81+
"""
82+
G2 = {
83+
"B": [["C", 1]],
84+
"C": [["D", 1]],
85+
"D": [["F", 1]],
86+
"E": [["B", 1], ["F", 3]],
87+
"F": [],
88+
}
89+
90+
"""
91+
Layout of G3:
92+
93+
E -- 1 --> B -- 1 --> C -- 1 --> D -- 1 --> F
94+
\ /\
95+
\ ||
96+
-------- 2 ---------> G ------- 1 ------
97+
"""
98+
G3 = {
99+
"B": [["C", 1]],
100+
"C": [["D", 1]],
101+
"D": [["F", 1]],
102+
"E": [["B", 1], ["G", 2]],
103+
"F": [],
104+
"G": [["F", 1]],
105+
}
106+
107+
shortDistance = dijkstra(G, "E", "C")
108+
print(shortDistance) # E -- 3 --> F -- 3 --> C == 6
37109

110+
shortDistance = dijkstra(G2, "E", "F")
111+
print(shortDistance) # E -- 3 --> F == 3
38112

39-
G = {'A': [['B', 2], ['C', 5]],
40-
'B': [['A', 2], ['D', 3], ['E', 1]],
41-
'C': [['A', 5], ['F', 3]],
42-
'D': [['B', 3]],
43-
'E': [['B', 1], ['F', 3]],
44-
'F': [['C', 3], ['E', 3]]}
113+
shortDistance = dijkstra(G3, "E", "F")
114+
print(shortDistance) # E -- 2 --> G -- 1 --> F == 3
45115

46-
shortDistance = dijkstra(G, 'E', 'C')
47-
print(shortDistance)
116+
if __name__ == "__main__":
117+
import doctest
118+
doctest.testmod()

project_euler/problem_01/__init__.py

Whitespace-only changes.

project_euler/problem_01/sol1.py

+26-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,34 @@
1-
'''
1+
"""
22
Problem Statement:
33
If we list all the natural numbers below 10 that are multiples of 3 or 5,
44
we get 3,5,6 and 9. The sum of these multiples is 23.
55
Find the sum of all the multiples of 3 or 5 below N.
6-
'''
6+
"""
77
from __future__ import print_function
8+
89
try:
9-
raw_input # Python 2
10+
raw_input # Python 2
1011
except NameError:
1112
raw_input = input # Python 3
12-
n = int(raw_input().strip())
13-
print(sum([e for e in range(3, n) if e % 3 == 0 or e % 5 == 0]))
13+
14+
15+
def solution(n):
16+
"""Returns the sum of all the multiples of 3 or 5 below n.
17+
18+
>>> solution(3)
19+
0
20+
>>> solution(4)
21+
3
22+
>>> solution(10)
23+
23
24+
>>> solution(600)
25+
83700
26+
>>> solution(-7)
27+
0
28+
"""
29+
30+
return sum([e for e in range(3, n) if e % 3 == 0 or e % 5 == 0])
31+
32+
33+
if __name__ == "__main__":
34+
print(solution(int(raw_input().strip())))

project_euler/problem_01/sol2.py

+31-12
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,39 @@
1-
'''
1+
"""
22
Problem Statement:
33
If we list all the natural numbers below 10 that are multiples of 3 or 5,
44
we get 3,5,6 and 9. The sum of these multiples is 23.
55
Find the sum of all the multiples of 3 or 5 below N.
6-
'''
6+
"""
77
from __future__ import print_function
8+
89
try:
9-
raw_input # Python 2
10+
raw_input # Python 2
1011
except NameError:
1112
raw_input = input # Python 3
12-
n = int(raw_input().strip())
13-
sum = 0
14-
terms = (n-1)//3
15-
sum+= ((terms)*(6+(terms-1)*3))//2 #sum of an A.P.
16-
terms = (n-1)//5
17-
sum+= ((terms)*(10+(terms-1)*5))//2
18-
terms = (n-1)//15
19-
sum-= ((terms)*(30+(terms-1)*15))//2
20-
print(sum)
13+
14+
15+
def solution(n):
16+
"""Returns the sum of all the multiples of 3 or 5 below n.
17+
18+
>>> solution(3)
19+
0
20+
>>> solution(4)
21+
3
22+
>>> solution(10)
23+
23
24+
>>> solution(600)
25+
83700
26+
"""
27+
28+
sum = 0
29+
terms = (n - 1) // 3
30+
sum += ((terms) * (6 + (terms - 1) * 3)) // 2 # sum of an A.P.
31+
terms = (n - 1) // 5
32+
sum += ((terms) * (10 + (terms - 1) * 5)) // 2
33+
terms = (n - 1) // 15
34+
sum -= ((terms) * (30 + (terms - 1) * 15)) // 2
35+
return sum
36+
37+
38+
if __name__ == "__main__":
39+
print(solution(int(raw_input().strip())))

project_euler/problem_01/sol3.py

+57-41
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,66 @@
1-
from __future__ import print_function
2-
3-
'''
1+
"""
42
Problem Statement:
53
If we list all the natural numbers below 10 that are multiples of 3 or 5,
64
we get 3,5,6 and 9. The sum of these multiples is 23.
75
Find the sum of all the multiples of 3 or 5 below N.
8-
'''
9-
'''
10-
This solution is based on the pattern that the successive numbers in the series follow: 0+3,+2,+1,+3,+1,+2,+3.
11-
'''
6+
"""
7+
from __future__ import print_function
128

139
try:
14-
raw_input # Python 2
10+
raw_input # Python 2
1511
except NameError:
1612
raw_input = input # Python 3
17-
n = int(raw_input().strip())
18-
sum=0
19-
num=0
20-
while(1):
21-
num+=3
22-
if(num>=n):
23-
break
24-
sum+=num
25-
num+=2
26-
if(num>=n):
27-
break
28-
sum+=num
29-
num+=1
30-
if(num>=n):
31-
break
32-
sum+=num
33-
num+=3
34-
if(num>=n):
35-
break
36-
sum+=num
37-
num+=1
38-
if(num>=n):
39-
break
40-
sum+=num
41-
num+=2
42-
if(num>=n):
43-
break
44-
sum+=num
45-
num+=3
46-
if(num>=n):
47-
break
48-
sum+=num
4913

50-
print(sum);
14+
15+
def solution(n):
16+
"""
17+
This solution is based on the pattern that the successive numbers in the
18+
series follow: 0+3,+2,+1,+3,+1,+2,+3.
19+
Returns the sum of all the multiples of 3 or 5 below n.
20+
21+
>>> solution(3)
22+
0
23+
>>> solution(4)
24+
3
25+
>>> solution(10)
26+
23
27+
>>> solution(600)
28+
83700
29+
"""
30+
31+
sum = 0
32+
num = 0
33+
while 1:
34+
num += 3
35+
if num >= n:
36+
break
37+
sum += num
38+
num += 2
39+
if num >= n:
40+
break
41+
sum += num
42+
num += 1
43+
if num >= n:
44+
break
45+
sum += num
46+
num += 3
47+
if num >= n:
48+
break
49+
sum += num
50+
num += 1
51+
if num >= n:
52+
break
53+
sum += num
54+
num += 2
55+
if num >= n:
56+
break
57+
sum += num
58+
num += 3
59+
if num >= n:
60+
break
61+
sum += num
62+
return sum
63+
64+
65+
if __name__ == "__main__":
66+
print(solution(int(raw_input().strip())))

0 commit comments

Comments
 (0)