Exemplo n.º 1
0
def get_shortest_path(graph: Graph, start: Vertex, end: Vertex):
    """
    find shortest path between two vertices of graph

    * graph - instance of class of Graph type
    * start - start point (id or instance of Vertex class)
    * end   - end point (id or instance of Vertex class)

    returns shortest path between ${start} and ${end}
    """
    if not isinstance(graph, Graph):
        return None
    start_vertex = graph.get_vertex(start)
    end_vertex = graph.get_vertex(end)
    bfs = bfs_undirected_cyclic(graph, start_vertex)
    parent = bfs[1]
    if parent is None:
        return []
    result = [end_vertex]
    current = end_vertex
    if current not in parent:
        return []
    while parent[current] is not None:
        current = parent[current]
        result.append(current)
    return result
Exemplo n.º 2
0
def bfs_undirected_cyclic(graph: Graph, start: Vertex):
    """
    implementation of Breath-First-search algorithm for
    undirected cyclic graph
    - visit all nodes reachable from ${start}
    - (V+E) time (V - count of vertexes; E count of edges)
    - avoid duplicates

    graph - instance of class of Graph type
    start - id or instance of Vertex class

    *returns* all nodes reach from given ${start} and their levels
    """
    if not isinstance(graph, Graph):
        return None, None
    start_vertex = graph.get_vertex(start)
    if not start_vertex:
        return None, None
    level = {start_vertex: 0}
    parent = {start_vertex: None}
    i = 1
    frontier = [start_vertex]
    while frontier:
        _next = []
        for parent_vertex in frontier:
            for child_id in parent_vertex.adj:
                child_vertex = parent_vertex.adj[child_id]
                if child_vertex not in level and child_vertex:
                    level[child_vertex] = i
                    parent[child_vertex] = parent_vertex
                    _next.append(child_vertex)
        frontier = _next
        i += 1
    return level, parent
Exemplo n.º 3
0
def dfs_undirected_cyclic_b(graph: Graph, start: Vertex):
    """implementation of Depth-First-search algorithm for
    undirected cyclic graph.
    No vertex can be on the stack in more than one place.
    The size of S is thus not more than n.
    The time complexity is O(n + m).
    - (V+E) time (V - count of vertexes; E count of edges)

    graph - instance of class of Graph type
    start - id or instance of Vertex class

    *returns* all nodes reach from given ${start} and their levels
    """
    if not isinstance(graph, Graph):
        return None, None
    start_vertex = graph.get_vertex(start)
    if not start_vertex:
        return None, None
    level = {start_vertex: 0}
    parent = {start_vertex: None}
    stack = [start_vertex]
    while stack:
        current_vertex = stack.pop()
        for child_id in current_vertex.adj:
            child_vertex = current_vertex.adj[child_id]
            if child_vertex not in level and child_vertex:
                level[child_vertex] = level[current_vertex] + 1
                parent[child_vertex] = current_vertex
                stack.append(current_vertex)
                stack.append(child_vertex)
                break
    return level, parent
Exemplo n.º 4
0
def dfs_undirected_cyclic(graph: Graph, start: Vertex):
    """implementation of Depth-First-search algorithm for
    undirected cyclic graph. Def can have multiple copies on
    the stack at the same time. However, the total number of
    iterations of the innermost loop of Def cannot exceed
    the number of edges of G, and thus the size of S cannot exceed m.
    The running time is O(n + m).
    - (V+E) time (V - count of vertexes; E count of edges)

    graph - instance of class of Graph type
    start - id or instance of Vertex class

    *returns* all nodes reach from given ${start} and their levels
    """
    if not isinstance(graph, Graph):
        return None, None
    start_vertex = graph.get_vertex(start)
    if not start_vertex:
        return None, None
    level = {start_vertex: 0}
    parent = {start_vertex: None}
    stack = [start_vertex]
    while stack:
        current_vertex = stack.pop()
        for child_id in current_vertex.adj:
            child_vertex = current_vertex.adj[child_id]
            if child_vertex not in level and child_vertex:
                level[child_vertex] = level[current_vertex] + 1
                parent[child_vertex] = current_vertex
                stack.append(child_vertex)
    return level, parent
Exemplo n.º 5
0
def bellman_ford(graph: Graph, start, end):
    if not isinstance(graph, Graph):
        return None
    start_vertex = graph.get_vertex(start)
    if not start_vertex:
        return None
    end_vertex = graph.get_vertex(end)
    if not end_vertex:
        return None
    visited = {start_vertex.id: (0, None)}
    for _ in range(0, len(graph.vertexes)):
        for vertex in graph.vertexes.values():
            # current vertex weigh
            weight = None
            if vertex.id in visited:
                weight = visited[vertex.id][0]
            # scanning edges
            for edge_id in vertex.adj.keys():
                adj_weight = vertex.weights[edge_id]
                if edge_id in visited:
                    current_weight = visited[edge_id][0]
                    if weight and current_weight > adj_weight + weight:
                        visited[edge_id] = (adj_weight + weight, vertex.id)
                elif weight is not None:
                    visited[edge_id] = (adj_weight + weight, vertex.id)
    # check for negative cycle
    for vertex in graph.vertexes.values():
        weight = visited[vertex.id][0]
        for edge_id in vertex.adj.keys():
            adj_weight = vertex.weights[edge_id]
            current_weight = visited[edge_id][0]
            if current_weight > adj_weight + weight:
                # negative cycle
                return None
    # restore path
    if end_vertex.id not in visited:
        return None
    result = [end_vertex.id]
    vertex = end_vertex.id
    weight = visited[end_vertex.id][0]
    while vertex != start_vertex.id:
        vertex = visited[vertex][1]
        result.append(vertex)
    result.reverse()
    return weight, result
Exemplo n.º 6
0
def single_path(graph: Graph, start, end):
    """implementation of dijkstra algorithm withOUT priority queue
    O(V**2) where V count vertexes(nodes)
    """
    if not isinstance(graph, Graph):
        return None
    start_vertex = graph.get_vertex(start)
    if not start_vertex:
        return None
    end_vertex = graph.get_vertex(end)
    if not end_vertex:
        return None
    visited = {start_vertex: (0, None)}
    pq = [(0, start_vertex)]
    while pq:
        pq_vertex = heappop(pq)
        vertex = pq_vertex[1]
        weight = visited[vertex][0]
        for child_id, child_vertex in vertex.adj.items():
            adj_weight = vertex.weights[child_id]
            if child_vertex in visited:
                current_weight = visited[child_vertex][0]
                if current_weight > adj_weight + weight:
                    visited[child_vertex] = (adj_weight + weight, vertex)
            else:
                heappush(pq, (adj_weight + weight, child_vertex))
                visited[child_vertex] = (adj_weight + weight, vertex)
    if end_vertex not in visited:
        return None
    result = [end_vertex.id]
    vertex = end_vertex
    weight = visited[end_vertex][0]
    while vertex != start_vertex:
        vertex = visited[vertex][1]
        result.append(vertex.id)
    result.reverse()
    return weight, result
Exemplo n.º 7
0
def dfs_detect_cycle(graph: Graph, start: Vertex) -> bool:
    if not isinstance(graph, Graph):
        return False
    start_vertex = graph.get_vertex(start)
    if not start_vertex:
        return False
    level = {start_vertex: 0}
    stack = [start_vertex]
    while stack:
        current_vertex = stack.pop()
        for child_id in current_vertex.adj:
            child_vertex = current_vertex.adj[child_id]
            if child_vertex not in level and child_vertex:
                level[child_vertex] = level[current_vertex] + 1
                stack.append(child_vertex)
            else:
                return True
    return False