initial commit

parents
.eggs
######################
# Logs and databases #
######################
*\.log
.DS_Store
####################
# Eclipse metadata #
####################
\.project
\.pydevproject
\.settings/
#############
# vim files #
#############
*\.swp
*~
\#*\#
#################
# pycharm files #
#################
\.idea
##########################
# Python complied source #
##########################
*\.pyc
*\.pyo
build/
dist/
doc/_build/
###########################
# coverage files
##########################
htmlcov/
.coverage
coverage_html/
import itertools
from typing import List, Optional
class NDGraph:
"""
To handle Non Directed Graph
A graph is a collection of Nodes linked by edges
there are basically to way to implement a graph
- The graph handles Nodes, each nodes know it's neighbors
- The graph handles nodes and the edges between nodes
below I implemented the first version.
"""
def __init__(self):
self.nodes = set()
def add_node(self, node: 'Node') -> None:
self.nodes.add(node)
def del_node(self, node: 'Node') -> None:
self.nodes.remove(node)
def get_node(self, node_id: int) -> Optional['Node']:
for n in self.neighbors:
if n.id == node_id:
return n
class Node:
_id = itertools.count(0)
def __init__(self):
self.id: int = next(self._id)
self.neighbors = set()
def __hash__(self):
# to be usable in set an object must be hashable
# so we need to implement __hash__
# which must returm an int uniq per object
# here we ad the identifier of the Node
return self.id
def add_neighbor(self, node: 'Node') -> None:
"""
Add one neighbor to this node
:param node: the node to add
:return: None
"""
# the graph is not directed
# So don't forget to add the reciprocal relation between the 2 nodes
# if node is a neighbor of self => self is a neighbor of node
self.neighbors.add(node)
node.neighbors.add(self)
def del_neighbor(self, node: 'Node') -> None:
"""
remove one neighbor to this node
:param node: the node to add
:return: None
"""
# the graph is not directed
# So don't forget to remove the reciprocal relation between the 2 nodes
# if node is a neighbor of self => self is a neighbor of node
self.neighbors.remove(node)
self.node.neigbors.remove(self)
def get_neighbor(self, node_id: int) -> Optional['Node']:
"""
:param int node_id: the node id
:return: the node corresponding to id or None if no node corresponding is found
"""
for n in self.neighbors:
if n.id == node_id:
return n
def DFS(graph: Graph, node: Node) -> List[Node]:
"""
Depth First Search
:param graph:
:param node:
:return:
"""
to_visit = [node]
visited = set()
while to_visit:
n = to_visit.pop(-1)
visited.add(n)
new_to_visit = n.neighbors - visited - set(to_visit)
to_visit.extend(new_to_visit)
yield n
def BFS(graph: Graph, node: Node) -> List[Node]:
"""
Breadth First search
:param graph:
:param node:
:return:
"""
to_visit = [node]
visited = set()
while to_visit:
n = to_visit.pop(0)
visited.add(n)
new_to_visit =n.neighbors - visited - set(to_visit)
to_visit.extend(new_to_visit)
yield n
from graph.graph import NDGraph, Node, BFS, DFS
# We want to create a toy graph (not directed) to check our algos
# no
# / \
# n1 n3
# | |
# n2 n4
# \ /
# n5
g = NDGraph()
n0 = Node()
n1 = Node()
n2 = Node()
n3 = Node()
n4 = Node()
n5 = Node()
n1.add_neighbor(n2)
n0.add_neighbor(n1)
n3.add_neighbor(n4)
n0.add_neighbor(n3)
n2.add_neighbor(n5)
n4.add_neighbor(n5)
g.add_node(n0)
# The graph is created we will test
# a Depth First Search
# starting from n0
# the possible solutions are
# n0, n1,n2,n5,n4,n3
# n0, n3, n4, n5, n2, n1
print("DFS")
for n in DFS(g, n0):
print(n.id)
# a Breadth First Search
# starting n0
# the possible solutions are
# n0, n1, n3, n2, n4, n5
# n0, n3, n1, n2, n4, n5
# n0, n1, n3, n4, n2, n5
# ....
print("BFS")
for n in BFS(g, n0):
print(n.id)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment