Verified Commit 9932d7e8 authored by Bertrand  NÉRON's avatar Bertrand NÉRON
Browse files

use FIFO/LIFO to implement DFS/BFS

parent 94d53f2b
......@@ -15,10 +15,17 @@ I propose two graph implementation
* *graph* store *nodes*
* each *node* have an unique id and knows its neighbors
* the BFS and DFS have been implemented with FIFO and LIFO
The interesting thing to see is that **BFS** and **DFS** differ only by using respectively
a **LIFO** or **FIFO**
## The second implementation graph_2.py and main_2.py
* *graph* store nodes, and edges between nodes
* *nodes* knows only its properties here, an unique id
in this secon implementation we recode LIFO and FIFO using a list and benefit that list are iterable
so they can be convert in set easily.
we see that the 2 search path algorithms *BFS* and *DFS* do not change whatever the graph implementation.
\ No newline at end of file
......@@ -2,6 +2,8 @@ import itertools
from typing import Iterator, Set, Optional
from .helpers import FIFO, LIFO
class NDGraph:
"""
......@@ -87,13 +89,15 @@ def DFS(graph: NDGraph, node: Node) -> Iterator[Node]:
:param node:
:return:
"""
to_visit = [node]
to_visit = FIFO()
to_visit.add(node)
visited = set()
while to_visit:
n = to_visit.pop(-1)
n = to_visit.pop()
visited.add(n)
new_to_visit = n.neighbors - visited - set(to_visit)
to_visit.extend(new_to_visit)
for neighbor in n.neighbors:
if neighbor not in visited and neighbor not in to_visit:
to_visit.add(neighbor)
yield n
......@@ -111,11 +115,13 @@ def BFS(graph: NDGraph, node: Node) -> Iterator[Node]:
:param node:
:return:
"""
to_visit = [node]
to_visit = LIFO()
to_visit.add(node)
visited = set()
while to_visit:
n = to_visit.pop(0)
n = to_visit.pop()
visited.add(n)
new_to_visit =n.neighbors - visited - set(to_visit)
to_visit.extend(new_to_visit)
for neighbor in n.neighbors:
if neighbor not in visited and neighbor not in to_visit:
to_visit.add(neighbor)
yield n
from abc import ABCMeta, abstractmethod
from typing import Any
from collections import deque
class AbstractQueue(metaclass=ABCMeta):
def __init__(self) -> None:
self._queue = deque()
def __bool__(self) -> bool:
"""
:return: True if there is any item in the queue, False otherwise.
"""
return bool(self._queue)
def __len__(self) -> int:
"""
:return: The length of the queue
"""
return len(self._queue)
def __contains__(self, item: Any) -> bool:
return item in self._queue
@abstractmethod
def add(self, item: Any) -> None:
return None
@abstractmethod
def pop(self) -> Any:
return None
class FIFO(AbstractQueue):
"""
This structure allow to store any object,
The First element add to the structure will be the First element removed from it.
*F*irst *I*n *F*irst *O*ut
"""
def add(self, item: Any) -> Any:
"""
Add item on the right side
:param item: The item to add
"""
self._queue.append(item)
def pop(self) -> Any:
"""
Remove and return an element from the right side.
If no elements are present, raises an IndexError.
:param item:
:return: the first element added in the FIFO
:rtype: Any
:raise: IndexError if there is no element in the FiFO
"""
return self._queue.pop()
class LIFO(AbstractQueue):
"""
This structure allow to store any object,
The Last element add to the structure will be the First element removed from it.
*L*ast *I*n *F*irst *O*ut
"""
def add(self, item: Any) -> None:
self._queue.append(item)
def pop(self) -> Any:
"""
Remove and return an element from the right side.
If no elements are present, raises an IndexError.
:param item:
:return: the first element added in the FIFO
:rtype: Any
:raise: IndexError if there is no element in the FiFO
"""
return self._queue.popleft()
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