Skip to content

Commit c6968b1

Browse files
committed
Added Hierholzer's algorithm to find Eulerian Tour in a graph.
1 parent 31a4068 commit c6968b1

File tree

1 file changed

+105
-0
lines changed

1 file changed

+105
-0
lines changed

graphs/eulerian_tour.py

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
#!/usr/bin/env python3
2+
# Find Eulerian Tour
3+
#
4+
# Write a program that takes in a graph
5+
# represented as a list of tuples
6+
# and return a list of nodes that
7+
# you would follow on an Eulerian Tour
8+
#
9+
# For example, if the input graph was
10+
# [(1, 2), (2, 3), (3, 1)]
11+
# A possible Eulerian tour would be [1, 2, 3, 1]
12+
13+
def get_a_tour():
14+
'''This function returns a possible tour in the current graph and removes the edges included in that tour, from the graph.'''
15+
global graph
16+
17+
nodes_degree = {} # Creating a {node: degree} dictionary for current graph.
18+
for edge in graph:
19+
a, b = edge[0], edge[1]
20+
nodes_degree[a] = nodes_degree.get(a, 0) + 1
21+
nodes_degree[b] = nodes_degree.get(b, 0) + 1
22+
23+
tour =[] # Finding a tour in the current graph.
24+
loop = enumerate(nodes_degree)
25+
while True:
26+
try:
27+
l = loop.__next__()
28+
index = l[0]
29+
node = l[1]
30+
degree = nodes_degree[node]
31+
try:
32+
if (tour[-1], node) in graph or (node, tour[-1]) in graph:
33+
tour.append(node)
34+
try:
35+
graph.remove((tour[-2], tour[-1]))
36+
nodes_degree[tour[-1]] -= 1 # Updating degree of nodes in the graph, not required but for the sake of completeness.
37+
nodes_degree[tour[-2]] -= 1 # Can also be used to check the correctness of program. In the end all degrees must zero.
38+
except ValueError:
39+
graph.remove((tour[-1], tour[-2]))
40+
nodes_degree[tour[-1]] -= 1
41+
nodes_degree[tour[-2]] -= 1
42+
except IndexError:
43+
tour.append(node)
44+
except StopIteration:
45+
loop = enumerate(nodes_degree)
46+
47+
if len(tour) > 2:
48+
if tour[0] == tour[-1]:
49+
return tour
50+
51+
def get_eulerian_tour():
52+
'''This function returns a Eulerian Tour for the input graph.'''
53+
global graph
54+
tour = get_a_tour()
55+
56+
if graph: # If stuck at the beginning, finding additional tour in the graph.
57+
loop = enumerate(tour[: -1])
58+
l = loop.__next__()
59+
i = l[0]
60+
node = l[1]
61+
try:
62+
while True:
63+
if node in list(zip(*graph))[0] or node in list(zip(*graph))[1]:
64+
t = get_a_tour() # Retreivng the additional tour
65+
j = t.index(node)
66+
tour = tour[ : i] + t[j:-1] + t[ :j+1] + tour[i+1: ] # Joining the two tours.
67+
if not graph: # Found Eulerian Tour
68+
return tour # Returning the Eulerian Tour
69+
loop = enumerate(tour[: -1]) # Still stuck? Looping back to search for another tour.
70+
l = loop.__next__()
71+
i = l[0]
72+
node = l[1]
73+
except StopIteration: # Oops! seems like the vertices in the current tour cannot connect to rest of the edges in the graph.
74+
print("Your graph doesn't seem to be connected")
75+
exit()
76+
else: # Found the Eulerian Tour in the very first call. Lucky Enough!
77+
return tour
78+
79+
# Sample inputs
80+
# graph = [(1, 2), (1, 3), (2, 3), (2, 4), (2, 6), (3, 4), (3, 5), (4, 5), (4, 6)]
81+
# graph = [(1, 2), (1, 3), (2, 3)]
82+
# graph = [(1, 2), (1, 3), (2, 3), (2, 4), (2, 6), (3, 4), (3, 5), (4, 5), (4, 6), (9, 10), (10, 11), (11, 9)]
83+
# graph = [(1, 2), (1, 3), (2, 3), (2, 4), (2, 6), (3, 4), (3, 5), (4, 5), (4, 6), (2, 7), (7, 8), (8, 2)]
84+
# graph = [(1, 2), (1, 3), (2, 3), (2, 4), (2, 6), (3, 4), (3, 5), (4, 5), (4, 6), (1, 5), (5, 6), (1, 6)]
85+
# graph = [(1, 2), (2, 3), (3, 1), (3, 4), (4, 3)]
86+
# graph = [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
87+
# graph = [(2, 6), (4, 2), (5, 4), (6, 5), (6, 8), (7, 9), (8, 7), (9, 6)]
88+
89+
# creating a {node: degree} dictionary
90+
nodes_degree = {}
91+
for edge in graph:
92+
a, b = edge[0], edge[1]
93+
nodes_degree[a] = nodes_degree.get(a, 0) + 1
94+
nodes_degree[b] = nodes_degree.get(b, 0) + 1
95+
96+
#checking degree
97+
degrees = nodes_degree.values() # remember it return a view
98+
for degree in degrees:
99+
if degree % 2:
100+
print("Your graph have one or more nodes with odd degrees. Hence an Eulerian Tour is impossible.")
101+
exit()
102+
103+
#finding Eulerian Tour
104+
tour = get_eulerian_tour()
105+
print(tour)

0 commit comments

Comments
 (0)