BFS and DFS

This commit is contained in:
2025-04-15 13:36:57 +02:00
parent 8ed7e09075
commit 370adb1234
3 changed files with 140 additions and 0 deletions

65
graph.py Normal file
View File

@@ -0,0 +1,65 @@
from prettytable import PrettyTable
from utils import *
class Node:
def __init__(self, name):
self.parent = None
self.name = name
self.edges = []
self.value = 0
class Edge:
def __init__(self, edge):
self.start = edge[0]
self.end = edge[1]
self.value = edge[2]
class Graph:
def __init__(self, node_list, edges):
self.nodes = []
for name in node_list:
self.nodes.append(Node(name))
for e in edges:
e = (getNode(e[0],self.nodes), getNode(e[1], self.nodes), e[2])
self.nodes[next((i for i,v in enumerate(self.nodes) if v.name == e[0].name), -1)].edges.append(Edge(e))
self.nodes[next((i for i,v in enumerate(self.nodes) if v.name == e[1].name), -1)].edges.append(Edge((e[1], e[0], e[2])))
def print(self):
node_list = self.nodes
t = PrettyTable([' '] +[i.name for i in node_list])
for node in node_list:
edge_values = ['X'] * len(node_list)
for edge in node.edges:
edge_values[ next((i for i,e in enumerate(node_list) if e.name == edge.end.name) , -1)] = edge.value
t.add_row([node.name] + edge_values)
print(t)
class Queue:
def __init__(self, type):
self.type = type
self.items = []
def empty(self):
return len(self.items) == 0
def pop(self):
if not self.empty():
if self.type=='FIFO':
return self.items.pop(0)
else:
return self.items.pop()
return None
def push(self, node):
self.items.append(node)
if self.type=='PRIO':
# Sorting reverse, because nodes with lowest cost/ value should be prioritized
self.items.sort(key = lambda item: item.value, reverse=True)

73
main.py Normal file
View File

@@ -0,0 +1,73 @@
from graph import Graph, Node, Queue
from utils import getNode
# directed and weighted digraph
romania = Graph( ['Or', 'Ne', 'Ze', 'Ia', 'Ar', 'Si', 'Fa',
'Va', 'Ri', 'Ti', 'Lu', 'Pi', 'Ur', 'Hi',
'Me', 'Bu', 'Dr', 'Ef', 'Cr', 'Gi'],
[
('Or', 'Ze', 71), ('Or', 'Si', 151),
('Ne', 'Ia', 87), ('Ze', 'Ar', 75),
('Ia', 'Va', 92), ('Ar', 'Si', 140),
('Ar', 'Ti', 118), ('Si', 'Fa', 99),
('Si', 'Ri', 80), ('Fa', 'Bu', 211),
('Va', 'Ur', 142), ('Ri', 'Pi', 97),
('Ri', 'Cr', 146), ('Ti', 'Lu', 111),
('Lu', 'Me', 70), ('Me', 'Dr', 75),
('Dr', 'Cr', 120), ('Cr', 'Pi', 138),
('Pi', 'Bu', 101), ('Bu', 'Gi', 90),
('Bu', 'Ur', 85), ('Ur', 'Hi', 98),
('Hi', 'Ef', 86)
] )
def search(graph, queue, start_node_name, target_node_name):
cost = 0
visited_nodes = [] # Nodes which have been visited
path = []
start_node = getNode(start_node_name, graph.nodes)
target_node = getNode(target_node_name, graph.nodes)
queue.push(start_node)
while not queue.empty():
current_node = queue.pop()
visited_nodes.append(current_node.name)
if current_node == target_node:
path.append(current_node.name)
tmp = current_node
while not tmp == start_node:
for edge in tmp.parent.edges:
if edge.end.name == tmp.name:
cost += edge.value
tmp = tmp.parent
path.insert(0, tmp.name) # reversed insertion
else:
for edge in current_node.edges:
neighbor = edge.end
# works with digraph, because current_node is marked at this point, a cycle is not possible
if not visited_nodes.__contains__(neighbor.name):
queue.push(neighbor)
neighbor.parent = current_node
if path.__len__() == 0:
print('zwischen ' + start_node_name + ' und ' + target_node_name + ' konnte kein Pfad gefunden werden')
else:
print('From ' + start_node_name + ' to ' + target_node_name + ': ')
print('Path: ' + path.__str__().format())
print('Cost: ' + cost.__str__())
def bfs(graph, start_node_name, target_node_name):
search(graph,Queue('FIFO'),start_node_name, target_node_name)
def dfs(graph, start_node_name, target_node_name):
search(graph,Queue('LIFO'),start_node_name, target_node_name)
def main():
bfs(romania, 'Ti', 'Bu')
dfs(romania, 'Ti', 'Bu')
if __name__ == "__main__":
main()

2
utils.py Normal file
View File

@@ -0,0 +1,2 @@
def getNode(name, l):
return next(( i for i in l if i.name == name), -1 )