zoukankan      html  css  js  c++  java
  • DFS and BFS

    DFS

    https://github.com/Premiumlab/Python-for-Algorithms--Data-Structures--and-Interviews/blob/master/Graphs/Implementation%20of%20Depth%20First%20Search.ipynb

    https://leetcode.com/problems/binary-tree-paths/#/solutions

    Nodes and References Implementation of a Tree

    class BinaryTree(object):
        def __init__(self,rootObj):
            self.key = rootObj
            self.leftChild = None
            self.rightChild = None
    
        def insertLeft(self,newNode):
            if self.leftChild == None:
                self.leftChild = BinaryTree(newNode)
            else:
                t = BinaryTree(newNode)
                t.leftChild = self.leftChild
                self.leftChild = t
    
        def insertRight(self,newNode):
            if self.rightChild == None:
                self.rightChild = BinaryTree(newNode)
            else:
                t = BinaryTree(newNode)
                t.rightChild = self.rightChild
                self.rightChild = t
    
    
        def getRightChild(self):
            return self.rightChild
    
        def getLeftChild(self):
            return self.leftChild
    
        def setRootVal(self,obj):
            self.key = obj
    
        def getRootVal(self):
            return self.key

    Implementation of Depth-First Search

    This algorithm we will be discussing is Depth-First search which as the name hints at, explores possible vertices (from a supplied root) down each branch before backtracking. This property allows the algorithm to be implemented succinctly in both iterative and recursive forms. Below is a listing of the actions performed upon each visit to a node.

    • Mark the current vertex as being visited.
    • Explore each adjacent vertex that is not included in the visited set.

    We will assume a simplified version of a graph in the following form:

    graph = {'A': set(['B', 'C']),
             'B': set(['A', 'D', 'E']),
             'C': set(['A', 'F']),
             'D': set(['B']),
             'E': set(['B', 'F']),
             'F': set(['C', 'E'])}

    Connected Component

    The implementation below uses the stack data-structure to build-up and return a set of vertices that are accessible within the subjects connected component. Using Python’s overloading of the subtraction operator to remove items from a set, we are able to add only the unvisited adjacent vertices.

    def dfs(graph, start, visited=None):
        if visited is None:
            visited = set()
        visited.add(start)
        for nxt in graph[start] - visited:
            dfs(graph, nxt, visited)
        return visited
    
    dfs(graph, 'A')
    {'A', 'B', 'C', 'D', 'E', 'F'}


     

    The second implementation provides the same functionality as the first, however, this time we are using the more succinct recursive form. Due to a common Python gotcha with default parameter values being created only once, we are required to create a new visited set on each user invocation. Another Python language detail is that function variables are passed by reference, resulting in the visited mutable set not having to reassigned upon each recursive call.

    def dfs(graph, start, visited=None):
        if visited is None:
            visited = set()
        visited.add(start)
        for nxt in graph[start] - visited:
            dfs(graph, nxt, visited)
        return visited
    
    dfs(graph, 'A')
    {'A', 'B', 'C', 'D', 'E', 'F'}   



    Paths

    We are able to tweak both of the previous implementations to return all possible paths between a start and goal vertex. The implementation below uses the stack data-structure again to iteratively solve the problem, yielding each possible path when we locate the goal. Using a generator allows the user to only compute the desired amount of alternative paths.

    def dfs_paths(graph, start, goal):
        stack = [(start, [start])]
        while stack:
            (vertex, path) = stack.pop()
            for nxt in graph[vertex] - set(path):
                if nxt == goal:
                    yield path + [nxt]
                else:
                    stack.append((nxt, path + [nxt]))
    
    list(dfs_paths(graph, 'A', 'F'))
    [['A', 'B', 'E', 'F'], ['A', 'C', 'F']]







    Implementation of Breadth First Search

    An alternative algorithm called Breath-First search provides us with the ability to return the same results as DFS but with the added guarantee to return the shortest-path first. This algorithm is a little more tricky to implement in a recursive manner instead using the queue data-structure, as such I will only being documenting the iterative approach. The actions performed per each explored vertex are the same as the depth-first implementation, however, replacing the stack with a queue will instead explore the breadth of a vertex depth before moving on. This behavior guarantees that the first path located is one of the shortest-paths present, based on number of edges being the cost factor.

    We'll assume our Graph is in the form:

    graph = {'A': set(['B', 'C']),
             'B': set(['A', 'D', 'E']),
             'C': set(['A', 'F']),
             'D': set(['B']),
             'E': set(['B', 'F']),
             'F': set(['C', 'E'])}

    Connected Component

    Similar to the iterative DFS implementation the only alteration required is to remove the next item from the beginning of the list structure instead of the stacks last.

    def bfs(graph, start):
        visited, queue = set(), [start]
        while queue:
            vertex = queue.pop(0)
            if vertex not in visited:
                visited.add(vertex)
                queue.extend(graph[vertex] - visited)
        return visited
    
    bfs(graph, 'A')
    {'A', 'B', 'C', 'D', 'E', 'F'}
     

    Paths

    This implementation can again be altered slightly to instead return all possible paths between two vertices, the first of which being one of the shortest such path.

    def bfs_paths(graph, start, goal):
        queue = [(start, [start])]
        while queue:
            (vertex, path) = queue.pop(0)
            for next in graph[vertex] - set(path):
                if next == goal:
                    yield path + [next]
                else:
                    queue.append((next, path + [next]))
    
    list(bfs_paths(graph, 'A', 'F'))
    [['A', 'C', 'F'], ['A', 'B', 'E', 'F']]
     

    Knowing that the shortest path will be returned first from the BFS path generator method we can create a useful method which simply returns the shortest path found or ‘None’ if no path exists. As we are using a generator this in theory should provide similar performance results as just breaking out and returning the first matching path in the BFS implementation.

    def shortest_path(graph, start, goal):
        try:
            return next(bfs_paths(graph, start, goal))
        except StopIteration:
            return None
    
    shortest_path(graph, 'A', 'F')
    ['A', 'C', 'F']


  • 相关阅读:
    在模拟器安装测试APP,给指定设备安装APP
    设置安卓模拟器,打开模拟器,设置语言为中文
    使用appium1.4在android8.0真机上测试程序时报错command failed shell "ps 'uiautomator'"的解决方式
    appium1.4+华为8.0执行自动化脚本,报启动session失败,原因是unicode_ime_apk\Uni codeIMEdebug.apk在手机上已存在,再次安装失败,导致启动session失败,解决办法:换高版本的appium
    搭建appium+maven手机自动化测试环境搭建
    appium1.7的使用
    SDK打开模拟器遇到SDK包里缺少API组件,附上我的解决历程,心累
    简单记录下Jmeter通过CSV保存测试数据,测试用例,及将测试结果导出到Excel里
    基于webpack的React项目搭建(一)
    基于webpack的React项目搭建(二)
  • 原文地址:https://www.cnblogs.com/prmlab/p/6905926.html
Copyright © 2011-2022 走看看