TheAlgorithms/Python · #11757

Add doctests to DFS and BFS. Contributes to #9943

prak74 · merged Sep 19, 20262 files · 208 + / 67
DIRECTORY.md11 + / 0
@@ -1164,6 +1164,7 @@     * [Sol2](project_euler/problem_012/sol2.py)   * Problem 013     * [Sol1](project_euler/problem_013/sol1.py)+    * [Sol2](project_euler/problem_013/sol2.py)   * Problem 014     * [Sol1](project_euler/problem_014/sol1.py)     * [Sol2](project_euler/problem_014/sol2.py)@@ -1344,6 +1345,8 @@     * [Sol1](project_euler/problem_107/sol1.py)   * Problem 109     * [Sol1](project_euler/problem_109/sol1.py)+  * Problem 111+    * [Sol1](project_euler/problem_111/sol1.py)   * Problem 112     * [Sol1](project_euler/problem_112/sol1.py)   * Problem 113@@ -1366,6 +1369,8 @@     * [Sol1](project_euler/problem_122/sol1.py)   * Problem 123     * [Sol1](project_euler/problem_123/sol1.py)+  * Problem 124+    * [Sol1](project_euler/problem_124/sol1.py)   * Problem 125     * [Sol1](project_euler/problem_125/sol1.py)   * Problem 129@@ -1376,6 +1381,12 @@     * [Sol1](project_euler/problem_135/sol1.py)   * Problem 136     * [Sol1](project_euler/problem_136/sol1.py)+  * Problem 137+    * [Sol1](project_euler/problem_137/sol1.py)+  * Problem 138+    * [Sol1](project_euler/problem_138/sol1.py)+  * Problem 142+    * [Sol1](project_euler/problem_142/sol1.py)   * Problem 144     * [Sol1](project_euler/problem_144/sol1.py)   * Problem 145
graphs/directed_and_undirected_weighted_graph.py197 + / 67
@@ -10,10 +10,23 @@ class DirectedGraph:     def __init__(self) -> None:         self.graph = {} -    # adding vertices and edges-    # adding the weight is optional-    # handles repetition     def add_pair(self, u, v, w=1) -> None:+        """+        Adds a directed edge u->v with weight w.+        Add vertices and edges+        Add the weight is optional+        Handle repetition++        >>> dg = DirectedGraph()+        >>> dg.add_pair(-1,2)+        >>> dg.add_pair(1,3,5)+        >>> dg.add_pair(1,3,5)+        >>> dg.add_pair(1,3,6)+        >>> dg.all_nodes()+        [-1, 2, 1, 3]+        >>> dg.graph[1]+        [[5, 3], [6, 3]]+        """         if self.graph.get(u):             if self.graph[u].count([w, v]) == 0:                 self.graph[u].append([w, v])@@ -23,53 +36,94 @@ def add_pair(self, u, v, w=1) -> None:             self.graph[v] = []      def all_nodes(self):+        """+        Returns list of all nodes in the graph.+        >>> dg = DirectedGraph()+        >>> dg.all_nodes()+        []+        >>> dg.add_pair(1,1)+        >>> dg.all_nodes()+        [1]+        >>> dg.add_pair(2,3,3)+        >>> dg.all_nodes()+        [1, 2, 3]+        """         return list(self.graph)      # handles if the input does not exist     def remove_pair(self, u, v) -> None:+        """+        Removes all edges u->v if it exists.+        >>> dg = DirectedGraph()+        >>> dg.remove_pair(1,2) # silently exits+        >>> dg.add_pair(0,5,2)+        >>> dg.graph[0]+        [[2, 5]]+        >>> dg.remove_pair(5,0)+        >>> dg.graph[0]+        [[2, 5]]+        >>> dg.remove_pair(0,5)+        >>> dg.graph[0]+        []+        """         if self.graph.get(u):             for _ in self.graph[u]:                 if _[1] == v:                     self.graph[u].remove(_)      # if no destination is meant the default value is -1     def dfs(self, s=-2, d=-1):-        if s == d:-            return []+        """+        Performs depth first search from s to find d.+        Returns the path s->d as a list.+        Returns dfs from s if d is not found+        >>> dg = DirectedGraph()+        >>> dg.dfs()+        []+        >>> dg.add_pair(1,1)+        >>> dg.dfs(1,1)+        [1]+        >>> dg = DirectedGraph()+        >>> dg.add_pair(0,1)+        >>> dg.add_pair(0,2)+        >>> dg.add_pair(1,3)+        >>> dg.add_pair(1,4)+        >>> dg.add_pair(1,5)+        >>> dg.add_pair(2,5)+        >>> dg.add_pair(5,6)+        >>> dg.dfs(0,6)+        [0, 2, 5, 6]+        >>> dg.dfs(1,6)+        [1, 5, 6]+        >>> dg.dfs()+        [0, 2, 5, 6, 1, 4, 3]+        >>> dg.dfs(1,0)+        [1, 5, 6, 4, 3]+        """         stack = []         visited = []         if s == -2:-            s = next(iter(self.graph))-        stack.append(s)-        visited.append(s)-        ss = s--        while True:-            # check if there is any non isolated nodes-            if len(self.graph[s]) != 0:-                ss = s-                for node in self.graph[s]:-                    if visited.count(node[1]) < 1:-                        if node[1] == d:-                            visited.append(d)-                            return visited-                        else:-                            stack.append(node[1])-                            visited.append(node[1])-                            ss = node[1]-                            break--            # check if all the children are visited-            if s == ss:-                stack.pop()-                if len(stack) != 0:-                    s = stack[len(stack) - 1]+            if self.graph.get(s, None):+                pass  # -2 is a node+            elif len(self.graph) > 0:+                s = next(iter(self.graph))             else:-                s = ss+                return []  # Graph empty+        stack.append(s) -            # check if se have reached the starting point-            if len(stack) == 0:-                return visited+        # Run dfs+        while len(stack) > 0:+            s = stack.pop()+            visited.append(s)+            # If reached d, return+            if s == d:+                break++            # add not visited child nodes to stack+            for _, ss in self.graph[s]:+                if visited.count(ss) < 1:+                    stack.append(ss)+        return visited      # c is the count of nodes you want and if you leave it or pass -1 to the function     # the count will be random from 10 to 10000@@ -84,12 +138,42 @@ def fill_graph_randomly(self, c=-1) -> None:                     self.add_pair(i, n, 1)      def bfs(self, s=-2):+        """+        Performs breadth first search from s+        Returns list.+        >>> dg = DirectedGraph()+        >>> dg.bfs()+        []+        >>> dg.add_pair(1,1)+        >>> dg.bfs(1)+        [1]+        >>> dg = DirectedGraph()+        >>> dg.add_pair(0,1)+        >>> dg.add_pair(0,2)+        >>> dg.add_pair(1,3)+        >>> dg.add_pair(1,4)+        >>> dg.add_pair(1,5)+        >>> dg.add_pair(2,5)+        >>> dg.add_pair(5,6)+        >>> dg.bfs(0)+        [0, 1, 2, 3, 4, 5, 6]+        >>> dg.bfs(1)+        [1, 3, 4, 5, 6]+        >>> dg.bfs()+        [0, 1, 2, 3, 4, 5, 6]+        """         d = deque()         visited = []         if s == -2:-            s = next(iter(self.graph))+            if self.graph.get(s, None):+                pass  # -2 is a node+            elif len(self.graph) > 0:+                s = next(iter(self.graph))+            else:+                return []  # Graph empty         d.append(s)         visited.append(s)+        # Run bfs         while d:             s = d.popleft()             if len(self.graph[s]) != 0:@@ -298,42 +382,59 @@ def remove_pair(self, u, v) -> None:      # if no destination is meant the default value is -1     def dfs(self, s=-2, d=-1):-        if s == d:-            return []+        """+        Performs depth first search from s to find d.+        Returns the path s->d as a list.+        Returns dfs from s if d is not found+        >>> ug = Graph()+        >>> ug.dfs()+        []+        >>> ug.add_pair(1,1)+        >>> ug.dfs(1,1)+        [1]+        >>> ug = Graph()+        >>> ug.add_pair(0,1)+        >>> ug.add_pair(0,2)+        >>> ug.add_pair(1,3)+        >>> ug.add_pair(1,4)+        >>> ug.add_pair(1,5)+        >>> ug.add_pair(2,5)+        >>> ug.add_pair(5,6)+        >>> ug.dfs(0,6)+        [0, 2, 5, 6]+        >>> ug.dfs(1,6)+        [1, 5, 6]+        >>> ug.dfs()+        [0, 2, 5, 6, 1, 4, 3]+        >>> ug.dfs(1,0)+        [1, 5, 6, 2, 0]+        """         stack = []         visited = []         if s == -2:-            s = next(iter(self.graph))-        stack.append(s)-        visited.append(s)-        ss = s--        while True:-            # check if there is any non isolated nodes-            if len(self.graph[s]) != 0:-                ss = s-                for node in self.graph[s]:-                    if visited.count(node[1]) < 1:-                        if node[1] == d:-                            visited.append(d)-                            return visited-                        else:-                            stack.append(node[1])-                            visited.append(node[1])-                            ss = node[1]-                            break--            # check if all the children are visited-            if s == ss:-                stack.pop()-                if len(stack) != 0:-                    s = stack[len(stack) - 1]+            if self.graph.get(s, None):+                pass  # -2 is a node+            elif len(self.graph) > 0:+                s = next(iter(self.graph))             else:-                s = ss+                return []  # Graph empty+        stack.append(s) -            # check if se have reached the starting point-            if len(stack) == 0:-                return visited+        # Run dfs+        while len(stack) > 0:+            s = stack.pop()+            if visited.count(s) == 1:+                continue+            visited.append(s)+            # If reached d, return+            if s == d:+                break++            # add not visited child nodes to stack+            for _, ss in self.graph[s]:+                if visited.count(ss) < 1:+                    stack.append(ss)+        return visited      # c is the count of nodes you want and if you leave it or pass -1 to the function     # the count will be random from 10 to 10000@@ -348,10 +449,39 @@ def fill_graph_randomly(self, c=-1) -> None:                     self.add_pair(i, n, 1)      def bfs(self, s=-2):+        """+        Performs breadth first search from s+        Returns list.+        >>> ug = Graph()+        >>> ug.bfs()+        []+        >>> ug.add_pair(1,1)+        >>> ug.bfs(1)+        [1]+        >>> ug = Graph()+        >>> ug.add_pair(0,1)+        >>> ug.add_pair(0,2)+        >>> ug.add_pair(1,3)+        >>> ug.add_pair(1,4)+        >>> ug.add_pair(1,5)+        >>> ug.add_pair(2,5)+        >>> ug.add_pair(5,6)+        >>> ug.bfs(0)+        [0, 1, 2, 3, 4, 5, 6]+        >>> ug.bfs(1)+        [1, 0, 3, 4, 5, 2, 6]+        >>> ug.bfs()+        [0, 1, 2, 3, 4, 5, 6]+        """         d = deque()         visited = []         if s == -2:-            s = next(iter(self.graph))+            if self.graph.get(s, None):+                pass  # -2 is a node+            elif len(self.graph) > 0:+                s = next(iter(self.graph))+            else:+                return []  # Graph empty         d.append(s)         visited.append(s)         while d: