Implementation
class HamiltonianPath:
def __init__(self, edges):
self.g = HamiltonianPath.__create_graph(edges)
@ staticmethod
def __create_graph(edges):
g = {}
for u, v in edges:
g[u] = set()
g[v] = set()
for u, v in edges:
g[u].add(v)
return g
def getHamiltonianPath(self):
def dfs(start):
s = [(start, None)]
h_path = []
visited = set()
while s:
top, parent = s.pop()
h_path.append(top)
visited.add(top)
if len(h_path) == len(self.g):
return h_path
none = True
for edge in self.g[top]:
if edge not in visited:
none = False
s.append((edge, top))
if none:
if not s:
return []
# back track until we reach the next element in the stack
# backtracking in this context means iterating backwards
# through the current path we collected
#
# our stopping condition is when:
# 1. The current element in the path is connected to the top of the stack
# 2. The parent of the top of the stack is current path element
while h_path and s[-1][0] not in self.g[h_path[-1]] or s[-1][1] != h_path[-1]:
tmp = h_path.pop()
visited.remove(tmp)
return []
for vertex, _ in self.g.items():
s = dfs(vertex)
if s:
return s
return []Testing
Discussion
The biggest challenge for me when implementing this iteratively, was knowing when stop backtracking. Consider the graph that does not have a Hamiltonian Path:

Our DFS tree for vertex 1 looks like follows:
At this point in time, the stack has elements
[8,3]. Once the algorithm discovers that path 1...9 is not a Hamiltonian path, it must backtrack to find the top element in the stack [3]. However we can see that vertex 13 is connected to vertex 3. We need another piece of information, which is that [3] has come from parent [1]. So we backtrack until our path contains this parent element as well.
Last updated
Was this helpful?