Held Tuesday, May 9, 2000
Overview
Today we conclude our discussion of graphs.
Notes
- Reminder: Attendance Wednesday is mandatory!
- I"ll bring carrots
- Those who don't attend will receive negative extra credit
Contents
Summary
- Course topics, Revisited
- Object-Oriented Programming and Program Design
- Algorithms: Analysis, Common, Design
- Data Structures: Design issues, Common
- Java Programming
- Time for official course evaluation
- What's the running time of this algorithm?
- We'll need to talk about the number of nodes in the graph (n)
and the number of edges (m).
- During initialization, we visit each node once, which should be
O(n) in any reasonable implementation.
- In the main loop, we remove each node from Est once, so
there are O(n) repetitions of the main loop.
- We look at each edge twice (one for each node connected to the
edge), so the ``update distances'' part takes O(m) across
the whole algorithm. (m is the number of edges)
- How long does it take to find the smallest distance in Est?
For the structures we've learned, O(n).
- We've find the smallest distance O(n) times.
- So, the running time is O(n^2 + m).
- Since m is in O(n^2), the running time is O(n^2).
- That's a significant improvement over the previous algorithm.
- Can we improve this running time? In particular, can we speed up
the determination of the smallest distance in Est?
- We might consider using a Heap, since we're doing a lot
of removeSmallest.
- However, we do change priorities of objects, and Heaps aren't
designed to easily support that operation. (How might you support
a
changePriority method?)
- A data structure that you might learn in 301 (if you take 301),
the Fibonacci heap, provides this method efficiently.
- The algorithm, as given, finds the length of the shortest path,
rather than the actual shortest path. How do we find the
shortest path?
- It turns out a rather minor change to the algorithm makes it
easy to find the shortest path. When we update the distance
to a node, we also keep track of the node that led to that
distance (the prior node).
- The Traveling Salescritter Problem is, in effect, a variant
of shortest path. Instead of finding the shortest path between two
nodes, you find the shortest path (or cycle) that visits every node
in the graph.
- Our ``brute force'' solution works here.
- List all paths
- Find the shortest
- That's an O(n!) algorithm
- Surprisingly, no one has found a substantially better algorithm
(in terms of big-O analysis).
- In fact, there are a class of problems with no known algorithms
that run in time less than O(2n).
- It's an open problem as to whether a better solution can exist.
- An interesting variant of shortest path and traveling salesperson is
the minimum spanning tree (MST) problem.
- The MST of an undirected graph is a set of edges that span the
graph (permit one to get from each node to every other node).
- It is minimum in the sense of having the smallest sum of edge weights.
- Note that the MST is a tree since there is no benefit to including a cycle
(the extra edges can only add cost).
- It is possible to solve the MST problem by a greedy algorithm.
- Actually, I've been told that there are a variety of greedy
algorithms that solve the MST problem.
- Here's one version:
- Separate the nodes into two groups: those in the MST and those not
in the MST. Initially one node is in the MST (it doesn't matter
which one).
- Repeatedly pick the smallest edge between a node in the MST and
a node not in the MST and add it to the MST.
- If there are any nodes left in the set of nodes not in the MST,
then there is no MST.
- Here's another one. Is it likely to be successful?
- Order the edges from smallest to largest
- Add an edge as long as it doesn't form a cycle
- In a directed graph, we can treat the edges as giving an ordering.
- For example, if there is an edge from A to B then we can say that
A is less than B.
- Unlike typical orderings, this isn't necessarily complete. That is,
there can be pairs of elements that are essentially unordered.
- Even if there are edges from A to C and B to C, we still don't
know anything about the relationship of A and B.
- In topological sort, you assign numbers to the elements of
the graph in such a way that
- No two elements have the same number
- If there is a path from X to Y, then X has a lower number than Y.
- How do we implement graphs? There are many techniques, which may
depend on our intended use of the graph.
- The simplest one is to use some sort of
Node structure,
and to treat the graph as a collection of nodes.
- Each node will need a list of nodes for its neighbors.
- We will probably store the nodes in a hash table for each access
(indexed by label).
- If we can number the nodes, we can use an adjacency matrix:
if there is an edge from A to B, then M[A,B] is true.
- In a weighted graph, we give M[A,B] the weight of the edge. We use
some special value (perhaps the largest integer or a negative integer)
for ``not there'').
- We can make a list of all the edges in the graph.
- Which implementation should we use? It depends a lot on the algorithm(s)
we intend to use.
- If we need all the neighbors of a node, we want the simple
``collection of nodes'' implementation.
- If we need all the edges of the graph, we use the list of edges.
- If we need to quickly determine whether there is an edge between
two nodes, we use the adjacency matrix.