Ejemplo n.º 1
0
class KruskalMST:
    """
    The KruskalMST class represents a data type for computing a
    minimum spanning tree in an edge-weighted graph.
    The edge weights can be positive, zero, or negative and need not
    be distinct. If the graph is not connected, it computes a minimum
    spanning forest, which is the union of minimum spanning trees
    in each connected component. The weight method returns the
    weight of a minimum spanning tree and the edges method
    returns its edges.
    This implementation uses Kruskal's algorithm and the
    union-find data type.
    The constructor takes time proportional to E log E
    and extra space (not including the graph) proportional to V,
    where V is the number of vertices and E is the number of edges-
    Afterwards, the weight method takes constant time
    and the edges method takes time proportional to V.
    """
    def __init__(self, G):
        """
        Computes a minimum spanning tree (or forest) of an edge-weighted graph.
        :param G: the edge-weighted graph
        """
        self._weight = 0
        self._mst = Queue()
        pq = MinPQ()

        for e in G.edges():
            pq.insert(e)

        uf = WeightedQuickUnionUF(G.V())
        while not pq.is_empty() and self._mst.size() < G.V() - 1:
            e = pq.del_min()
            v = e.either()
            w = e.other(v)
            if not uf.connected(v, w):
                uf.union(v, w)
                self._mst.enqueue(e)
                self._weight += e.weight()

    def edges(self):
        """
        Returns the edges in a minimum spanning tree (or forest).
        :return: the edges in a minimum spanning tree (or forest)
        """
        return self._mst

    def weight(self):
        """
        Returns the sum of the edge weights in a minimum spanning tree (or forest).
        :return: the sum of the edge weights in a minimum spanning tree (or forest)
        """
        return self._weight
Ejemplo n.º 2
0
 def keys_with_prefix(self, prefix):
     if prefix is None:
         raise ValueError("calls keys_with_prefix with null argument"
                          )  # TODO IllegalArgumentException
     queue = Queue()
     x = self._get(self.root, prefix, 0)
     if x is None:
         return queue
     if x.val is not None:
         queue.enqueue(prefix)
     self._collect(x.mid, prefix, queue)
     return queue
Ejemplo n.º 3
0
    def edges(self):
        """
        Returns the edges in a minimum spanning tree (or forest).
        :returns: the edges in a minimum spanning tree (or forest) as
                an iterable of edges
        """
        mst = Queue()
        for v in range(len(self._edge_to)):
            e = self._edge_to[v]
            if e is not None:
                mst.enqueue(e)

        return mst
Ejemplo n.º 4
0
    def __init__(self, G):
        """
        Compute a minimum spanning tree (or forest) of an edge-weighted graph.
        :param G: the edge-weighted graph
        """
        self._weight = 0.0  # total weight of MST
        self._mst = Queue()  # edges in the MST
        self._marked = [False] * G.V()  # marked[v] = True if v on tree
        self._pq = MinPQ()  # edges with one endpoint in tree

        for v in range(G.V()):  # run Prim from all vertices to
            if not self._marked[v]:
                self._prim(G, v)  # get a minimum spanning forest

        # check optimality conditions
        assert self._check(G)
Ejemplo n.º 5
0
 def keys(self):
     """
     Returns all keys in the symbol table.
     :return: all keys in the symbol table
     """
     if self.is_empty():
         return Queue()
     return self.keys_range(self.min(), self.max())
Ejemplo n.º 6
0
 def _bfs(self, G, s):
     # breadth-first search from a single source
     queue = Queue()
     self._marked[s] = True              # Mark the source
     queue.enqueue(s)                    #   and put it on the queue.
     while not queue.is_empty():
         v = queue.dequeue()             # Remove next vertex from the queue.
         for w in G.adj(v):
             if not self._marked[w]:
                 self._edgeTo[w] = v     # For every unmarked adjacent vertex,
                 self._marked[w] = True  # mark it because path is known,
                 queue.enqueue(w)        # and add it to the queue.
Ejemplo n.º 7
0
    def __init__(self, G, s):
        self._distTo = [sys.float_info.max
                        ] * G.V()  #distTo[v] = distance  of shortest s->v path
        self._edgeTo = [None
                        ] * G.V()  #edgeTo[v] = last edge on shortest s->v path
        self._onQueue = [False
                         ] * G.V()  #onQueue[v] = is v currently on the queue?
        self._queue = Queue()  #queue of vertices to relax
        self._cost = 0  #number of calls to relax()
        self._cycle = None  #negative cycle (or None if no such cycle)

        #Bellman-Ford algorithm
        self._distTo[s] = 0.0
        self._queue.enqueue(s)
        self._onQueue[s] = True
        while not self._queue.is_empty() and not self.has_negative_cycle():
            v = self._queue.dequeue()
            self._onQueue[v] = False
            self._relax(G, v)
        assert self._check(G, s)
Ejemplo n.º 8
0
    def __init__(self, G):
        """
        Computes a minimum spanning tree (or forest) of an edge-weighted graph.
        :param G: the edge-weighted graph
        """
        self._weight = 0
        self._mst = Queue()
        pq = MinPQ()

        for e in G.edges():
            pq.insert(e)

        uf = WeightedQuickUnionUF(G.V())
        while not pq.is_empty() and self._mst.size() < G.V() - 1:
            e = pq.del_min()
            v = e.either()
            w = e.other(v)
            if not uf.connected(v, w):
                uf.union(v, w)
                self._mst.enqueue(e)
                self._weight += e.weight()
Ejemplo n.º 9
0
    def keys_between(self, lo, hi):
        """
        Returns all keys in this symbol table in the given range,
        as an  Iterable.
        
        :param lo: minimum endpoint
        :param hi: maximum endpoint
        :returns: all keys in this symbol table between lo 
            (inclusive) and hi (inclusive)
        :raises ValueError: if either lo or hi are None
        """
        if lo is None: raise ValueError("first argument to keys() is None") 
        if hi is None: raise ValueError("second argument to keys() is None") 

        queue = Queue() 
        if lo > hi: return queue

        i = self.rank(lo)
        end = self.rank(hi)
        while i < end:
            queue.enqueue(self._keys[i])
            i += 1

        if self.contains(hi): queue.enqueue(self._keys[self.rank(hi)])
        return queue 
Ejemplo n.º 10
0
    def __init__(self, digraph):
        """
        Determines a depth-first order for the digraph.
        
        :param digraph: the digraph to check
        """
        self._pre = [0] * digraph.V()
        self._post = [0] * digraph.V()
        self._preorder = Queue()
        self._postorder = Queue()
        self._marked = [False] * digraph.V()

        self._pre_counter = 0
        self._post_counter = 0

        if isinstance(digraph, Digraph):
            dfs = self._dfs
        else:
            dfs = self._dfs_edge_weighted

        for v in range(digraph.V()):
            if (not self._marked[v]):
                dfs(digraph, v)
Ejemplo n.º 11
0
 def keys_range(self, lo, hi):
     """
     Returns all keys in the symbol table in the given range.
     :param lo: minimum endpoint
     :param hi: maximum endpoint
     :return: all keys in the symbol table between lo (inclusive) and hi (inclusive)
     :raises IllegalArgumentException: if either lo or hi is None
     """
     if lo is None:
         raise IllegalArgumentException("first argument to keys() is None")
     if hi is None:
         raise IllegalArgumentException("second argument to keys() is None")
     queue = Queue()
     self._keys(self._root, queue, lo, hi)
     return queue
Ejemplo n.º 12
0
 def keys_that_match(self, pattern):
     queue = Queue()
     self._collect_match(self.root, "", 0, pattern, queue)
     return queue
Ejemplo n.º 13
0
    def id(self, v):
        return self._id[v]

    def count(self):
        return self._count    

if __name__ == "__main__":
    import sys
    from algs4.fundamentals.queue import Queue
    from algs4.stdlib.instream import InStream    
    from algs4.stdlib import stdio    
    from algs4.graphs.graph import Graph    

    In = InStream(sys.argv[1])
    G = Graph.from_stream(In)
    cc = CC(G)

    # number of connected components
    m = cc.count()
    stdio.writef("%i components\n", m)

    # compute list of vertices in each connected component
    components = [Queue() for _ in range(m)]
    for v in range(G.V()):
        components[cc.id(v)].enqueue(v)

    # print results
    for i in range(m):
        for v in components[i]:
            stdio.writef("%i ", v)
        stdio.writeln()
Ejemplo n.º 14
0
class LazyPrimMST:
    """
    The LazyPrimMST class represents a data type for computing a
    minimum spanning tree in an edge-weighted graph.
    The edge weights can be positive, zero, or negative and need not
    be distinct. If the graph is not connected, it computes a minimum
    spanning forest, which is the union of minimum spanning trees
    in each connected component. The weight() method returns the 
    weight of a minimum spanning tree and the edges() method
    returns its edges.

    This implementation uses a lazy version of Prim's algorithm
    with a binary heap of edges.
    The constructor takes time proportional to E log E
    and extra space (not including the graph) proportional to E,
    where V is the number of vertices and E is the number of edges.
    Afterwards, the weight() method takes constant time
    and the edges() method takes time proportional to V.
    """
    FLOATING_POINT_EPSILON = 1E-12

    def __init__(self, G):
        """
        Compute a minimum spanning tree (or forest) of an edge-weighted graph.
        :param G: the edge-weighted graph
        """
        self._weight = 0.0  # total weight of MST
        self._mst = Queue()  # edges in the MST
        self._marked = [False] * G.V()  # marked[v] = True if v on tree
        self._pq = MinPQ()  # edges with one endpoint in tree

        for v in range(G.V()):  # run Prim from all vertices to
            if not self._marked[v]:
                self._prim(G, v)  # get a minimum spanning forest

        # check optimality conditions
        assert self._check(G)

    def _prim(self, G, s):
        # run Prim's algorithm
        self._scan(G, s)
        while not self._pq.is_empty():  # better to stop when mst has V-1 edges
            e = self._pq.del_min()  # smallest edge on pq
            v = e.either()  # two endpoints
            w = e.other(v)
            assert self._marked[v] or self._marked[w]
            if self._marked[v] and self._marked[
                    w]:  # lazy, both v and w already scanned
                continue
            self._mst.enqueue(e)  # add e to MST
            self._weight += e.weight()
            if not self._marked[v]: self._scan(G, v)  # v becomes part of tree
            if not self._marked[w]: self._scan(G, w)  # w becomes part of tree

    def _scan(self, G, v):
        # add all edges e incident to v onto pq if the other endpoint has not yet been scanned
        assert not self._marked[v]
        self._marked[v] = True
        for e in G.adj(v):
            if not self._marked[e.other(v)]:
                self._pq.insert(e)

    def edges(self):
        """
        Returns the edges in a minimum spanning tree (or forest).
        :returns: the edges in a minimum spanning tree (or forest) as
            an iterable of edges
        """
        return self._mst

    def weight(self):
        """
        Returns the sum of the edge weights in a minimum spanning tree (or forest).
        :returns: the sum of the edge weights in a minimum spanning tree (or forest)
        """
        return self._weight

    def _check(self, G):
        # check optimality conditions (takes time proportional to E V lg* V)

        totalWeight = 0.0  # check weight
        for e in self.edges():
            totalWeight += e.weight()

        if abs(totalWeight -
               self.weight()) > LazyPrimMST.FLOATING_POINT_EPSILON:
            error = "Weight of edges does not equal weight(): {} vs. {}\n".format(
                totalWeight, self.weight())
            print(error, file=sys.stderr)
            return False

        # check that it is acyclic
        uf = UF(G.V())
        for e in self.edges():
            v = e.either()
            w = e.other(v)
            if uf.connected(v, w):
                print("Not a forest", file=sys.stderr)
                return False
            uf.union(v, w)

        # check that it is a spanning forest
        for e in G.edges():
            v = e.either()
            w = e.other(v)
            if not uf.connected(v, w):
                print("Not a forest", file=sys.stderr)
                return False

        # check that it is a minimal spanning forest (cut optimality conditions)
        for e in self.edges():
            # all edges in MST except e
            uf = UF(G.V())
            for f in self._mst:
                x = f.either()
                y = f.other(x)
                if f != e:
                    uf.union(x, y)

            # check that e is min weight edge in crossing cut
            for f in G.edges():
                x = f.either()
                y = f.other(x)
                if not uf.connected(x, y):
                    if f.weight() < e.weight():
                        error = "Edge {} violates cut optimality conditions".format(
                            f)
                        print(error, file=sys.stderr)
                        return False
        return True
Ejemplo n.º 15
0
 def keys_that_match(self, pattern):
     results = Queue()
     self._collect_match(self._root, '', pattern, results)
     return results
Ejemplo n.º 16
0
 def keys_with_prefix(self, prefix):
     results = Queue()
     x = self._get(self._root, prefix, 0)
     self._collect(x, prefix, results)
     return results
Ejemplo n.º 17
0
# created for BADS 2018
# See README.md for details
# Python 3

import sys
from algs4.fundamentals.queue import Queue
from algs4.stdlib import stdio
try:
    q = Queue()
    q.enqueue(1)
except AttributeError:
    print('ERROR - Could not import algs4 queue')
    sys.exit(1)
"""
 *  The TrieST class represents an symbol table of key-value
 *  pairs, with string keys and generic values.
 *  It supports the usual put, get, contains,
 *  delete, size, and is-empty methods.
 *  It also provides character-based methods for finding the string
 *  in the symbol table that is the longest prefix of a given prefix,
 *  finding all strings in the symbol table that start with a given prefix,
 *  and finding all strings in the symbol table that match a given pattern.
 *  A symbol table implements the associative array abstraction:
 *  when associating a value with a key that is already in the symbol table,
 *  the convention is to replace the old value with the new value.
 *  This class uses the convention that
 *  values cannot be None, setting the
 *  value associated with a key to None is equivalent to deleting the key
 *  from the symbol table.
 *  This implementation uses a 256-way trie.
 *  The put, contains, delete, and
Ejemplo n.º 18
0
class DepthFirstOrder:
    """
    The DepthFirstOrder class represents a data type for determining depth-first 
    search ordering of the vertices in a digraph or edge-weighted digraph, including 
    preorder, postorder, and reverse postorder.
    
    This implementation uses depth-first search. The constructor takes time proportional 
    to V + E (in the worst case), where V is the number of vertices and E is the number 
    of edges. Afterwards, the preorder, postorder, and reverse postorder operation takes 
    take time proportional to V.

    For additional documentation, see Section 4.2 of Algorithms, 4th Edition by Robert Sedgewick and Kevin Wayne.
    """
    def __init__(self, digraph):
        """
        Determines a depth-first order for the digraph.
        
        :param digraph: the digraph to check
        """
        self._pre = [0] * digraph.V()
        self._post = [0] * digraph.V()
        self._preorder = Queue()
        self._postorder = Queue()
        self._marked = [False] * digraph.V()

        self._pre_counter = 0
        self._post_counter = 0

        if isinstance(digraph, Digraph):
            dfs = self._dfs
        else:
            dfs = self._dfs_edge_weighted

        for v in range(digraph.V()):
            if (not self._marked[v]):
                dfs(digraph, v)

    def post(self, v=None):
        """
        Either returns the postorder number of vertex v or, if v is None, 
        returns the vertices in postorder.
        
        :param v: None, or the vertex to return the postorder number of
        :return: if v is None, the vertices in postorder, otherwise the postorder
        number of v
        """
        if v is None:
            return self._postorder
        else:
            self._validate_vertex(v)
            return self._post[v]

    def pre(self, v=None):
        """
        Either returns the preorder number of vertex v or, if v is None, 
        returns the vertices in preorder.
        
        :param v: None, or the vertex to return the preorder number of
        :return: if v is None, the vertices in preorder, otherwise the preorder
                number of v
        """
        if v is None:
            return self._preorder
        else:
            self._validate_vertex(v)
            return self._pre[v]

    def reverse_post(self):
        """
        Returns the vertices in reverse postorder.
        
        :return: the vertices in reverse postorder, as an iterable of vertices
        """
        reverse = Stack()
        for v in self._postorder:
            reverse.push(v)
        return reverse

    # run DFS in digraph G from vertex v and compute preorder/postorder
    def _dfs(self, digraph, v):
        self._marked[v] = True
        self._pre[v] = self._pre_counter
        self._pre_counter += 1
        self._preorder.enqueue(v)
        for w in digraph.adj(v):
            if not self._marked[w]:
                self._dfs(digraph, w)
        self._postorder.enqueue(v)
        self._post[v] = self._post_counter
        self._post_counter += 1

    # run DFS in edge-weighted digraph G from vertex v and compute preorder/postorder
    def _dfs_edge_weighted(self, graph, v):
        self._marked[v] = True
        self._pre[v] = self._pre_counter
        self._pre_counter += 1
        self._preorder.enqueue(v)
        for edge in graph.adj(v):
            w = edge.to_vertex()
            if not self._marked[w]:
                self._dfs_edge_weighted(graph, w)
        self._postorder.enqueue(v)
        self._post[v] = self._post_counter
        self._post_counter += 1

    # throw an IllegalArgumentException unless 0 <= v < V
    def _validate_vertex(self, v):
        V = len(self._marked)
        if v < 0 or v >= V:
            raise ValueError("vertex {} is not between 0 and {}", v, V - 1)

    # check that pre() and post() are consistent with pre(v) and post(v)
    def _check(self):
        # check that post(v) is consistent with post()
        r = 0
        for v in self.post():
            if self.post(v) != r:
                print("post(v) and post() inconsistent")
                return False
            r += 1

        # check that pre(v) is consistent with pre()
        r = 0
        for v in self.pre():
            if self.pre(v) != r:
                print("pre(v) and pre() inconsistent")
                return False
            r += 1

        return True
Ejemplo n.º 19
0
# Created for BADS 2018
# See README.md for details
# Python 3
import sys
from algs4.stdlib import stdio
from algs4.fundamentals.queue import Queue

# is this really useful??
try:
    q = Queue()
    q.enqueue(1)
except AttributeError:
    print('ERROR - Could not import algs4 queue')
    sys.exit(1)

# Execution:    python lookup_index.py movies.txt "/"
# Dependencies: queue.py stdio.py
# % python lookup_index.py aminoI.csv ","
# Serine
#   TCT
#   TCA
#   TCG
#   AGT
#   AGC
# TCG
#   Serine
#
# % python lookup_index.py movies.txt "/"
# Bacon, Kevin
#   Animal House (1978)
#   Apollo 13 (1995)
Ejemplo n.º 20
0
 def keys(self):
     queue = Queue()
     self._collect(self.root, "", queue)
     return queue
Ejemplo n.º 21
0
class BellmanFordSP:
    # Computes a shortest paths tree from s to every other vertex in
    # the edge-weighted digraph G.
    # @param G the acyclic digraph
    # @param s the source vertex
    # @throws IllegalArgumentException unless 0 <= s < V
    def __init__(self, G, s):
        self._distTo = [sys.float_info.max
                        ] * G.V()  #distTo[v] = distance  of shortest s->v path
        self._edgeTo = [None
                        ] * G.V()  #edgeTo[v] = last edge on shortest s->v path
        self._onQueue = [False
                         ] * G.V()  #onQueue[v] = is v currently on the queue?
        self._queue = Queue()  #queue of vertices to relax
        self._cost = 0  #number of calls to relax()
        self._cycle = None  #negative cycle (or None if no such cycle)

        #Bellman-Ford algorithm
        self._distTo[s] = 0.0
        self._queue.enqueue(s)
        self._onQueue[s] = True
        while not self._queue.is_empty() and not self.has_negative_cycle():
            v = self._queue.dequeue()
            self._onQueue[v] = False
            self._relax(G, v)
        assert self._check(G, s)

    #relax vertex v and put other endpoints on queue if changed
    def _relax(self, G, v):
        for e in G.adj(v):
            w = e.to_vertex()
            if self._distTo[w] > self._distTo[v] + e.weight():
                self._distTo[w] = self._distTo[v] + e.weight()
                self._edgeTo[w] = e
                if not self._onQueue[w]:
                    self._queue.enqueue(w)
                    self._onQueue[w] = True
            if self._cost % G.V() == 0:
                self._find_negative_cycle()
                if self.has_negative_cycle():
                    return  #found a negative cycle
            self._cost += 1

    # Is there a negative cycle reachable from the source vertex s?
    # @return true if there is a negative cycle reachable from the
    #    source vertex s, and false otherwise
    def has_negative_cycle(self):
        return self._cycle is not None

    # Returns a negative cycle reachable from the source vertex s, or None
    # if there is no such cycle.
    # @return a negative cycle reachable from the soruce vertex s
    #    as an iterable of edges, and None if there is no such cycle
    def negative_cycle(self):
        return self._cycle

    #by finding a cycle in predecessor graph
    def _find_negative_cycle(self):
        V = len(self._edgeTo)
        spt = EdgeWeightedDigraph(V)
        for v in range(V):
            if self._edgeTo[v] is not None:
                spt.add_edge(self._edgeTo[v])

        finder = EdgeWeightedDirectedCycle(spt)
        self._cycle = finder.cycle()

    # Returns the length of a shortest path from the source vertex s to vertex v.
    # @param  v the destination vertex
    # @return the length of a shortest path from the source vertex s to vertex v;
    #         sys.float_info.max if no such path
    # @throws UnsupportedOperationException if there is a negative cost cycle reachable
    #         from the source vertex s
    # @throws IllegalArgumentException unless 0 <= v < V
    def dist_to(self, v):
        self._validate_vertex(v)
        if self.has_negative_cycle():
            raise UnsupportedOperationException("Negative cost cycle exists")
        return self._distTo[v]

    # Is there a path from the source s to vertex v?
    # @param  v the destination vertex
    # @return true if there is a path from the source vertex
    #         s to vertex v, and false otherwise
    # @throws IllegalArgumentException unless 0 <= v < V
    def has_path_to(self, v):
        self._validate_vertex(v)
        return self._distTo[v] < sys.float_info.max

    # Returns a shortest path from the source s to vertex v.
    # @param  v the destination vertex
    # @return a shortest path from the source s to vertex v
    #         as an iterable of edges, and None if no such path
    # @throws UnsupportedOperationException if there is a negative cost cycle reachable
    #         from the source vertex s
    # @throws IllegalArgumentException unless 0 <= v < V
    def path_to(self, v):
        self._validate_vertex(v)
        if self.has_negative_cycle():
            raise UnsupportedOperationException("Negative cost cycle exists")
        if not self.has_path_to(v): return None
        path = Stack()
        e = self._edgeTo[v]
        while e is not None:
            path.push(e)
            e = self._edgeTo[e.from_vertex()]
        return path

    #check optimality conditions: either
    #(i) there exists a negative cycle reacheable from s
    #    or
    #(ii)  for all edges e = v->w:            distTo[w] <= distTo[v] + e.weight()
    #(ii') for all edges e = v->w on the SPT: distTo[w] == distTo[v] + e.weight()
    def _check(self, G, s):

        #has a negative cycle
        if self.has_negative_cycle():
            weight = 0.0
            for e in self.negative_cycle():
                weight += e.weight()
            if weight >= 0.0:
                print("error: weight of negative cycle = {}".format(weight))
                return False

        #no negative cycle reachable from source
        else:

            #check that distTo[v] and edgeTo[v] are consistent
            if self._distTo[s] != 0.0 or self._edgeTo[s] is not None:
                print("distanceTo[s] and edgeTo[s] inconsistent")
                return False

            for v in range(G.V()):
                if v == s: continue
                if self._edgeTo[v] is None and self._distTo[
                        v] != sys.float_info.max:
                    print("distTo[] and edgeTo[] inconsistent")
                    return False

            #check that all edges e = v->w satisfy distTo[w] <= distTo[v] + e.weight()
            for v in range(G.V()):
                for e in G.adj(v):
                    w = e.to_vertex()
                    if self._distTo[v] + e.weight() < self._distTo[w]:
                        print("edge {} not relaxed".format(e))
                        return False

            #check that all edges e = v->w on SPT satisfy distTo[w] == distTo[v] + e.weight()
            for w in range(G.V()):
                if self._edgeTo[w] is None: continue
                e = self._edgeTo[w]
                v = e.from_vertex()
                if w != e.to_vertex(): return False
                if self._distTo[v] + e.weight() != self._distTo[w]:
                    print("edge {} on shortest path not tight".format(e))
                    return False

        print("Satisfies optimality conditions")
        print()
        return True

    #raise an IllegalArgumentException unless 0 <= v < V
    def _validate_vertex(self, v):
        V = len(self._distTo)
        if v < 0 or v >= V:
            raise IllegalArgumentException(
                "vertex {} is not between 0 and {}".format(v, V - 1))