CS62 - Spring 2011 - Lecture 39

  • revisit big-O calculation for DFS (and variants)
       - What is the worst case input for checking connectedness?
          - when it is connected (we'll have to examine all of the nodes/edges)
          - how can we do this?
             - use DFS to search, marking nodes as visited
          - how many times is dfs called?
             - once for each vertex
          - what is the main cost for a call to dfs?
             - finding the neighbors
          - what is the cost to find the neighbors with an adjacency matrix?
             - O(|V|), we have to traverse an entire row
          - so, what is the cost of dfs with an adjacency matrix?
             - O(|V|*|V|) = O(|V|^2)
          - what is the cost to find the neighbors with an adjacency list?
             - depends on how many neighborsÉ
          - let's look at it another way, how many times is each edge considered as a neighbor?
             - twice! once for each vertex it connects
             - walkthrough an example
          - so, we have O(|V| + 2 |E|) = O(|V| + |E|)
       - how does O(|V| + |E|) relate to O(|V|^2)?
          - O(|V| + |E|) <= O(|V|^2)
          - in the extreme |E| = |V|^2
       - notice that this is a big O expression with respect to two different variables/concepts
          - we will see this behavior sometimes in other algorithm analysis, if for example, we have two inputs
          - for example, say we wanted to write a method that takes two vectors as parameters and returns the concatenation of the two vectors:
             vector<int> join(const vector<int>& vec1, const vector<int>& vec2){
                ...
             }
          - if n is the length of vec1 and m the length of vec2, what is the big-O running time?
             O(n + m)

  • look at Dijkstra slides

  • single source shortest paths: given a weighted graph and a starting vertex v, find the shortest paths from v to all other vertices
       - how would we find shortest paths in an unweighted graph?
          - use breadth first search

          enqueue start;
          while (queue not empty) {
             dequeue v;
             if (v is not visited) {
                visit v;
                enqueue all vŐs neighbors;
             }
          }

          we visit nodes at distance 1, then 2, then 3, etc. from the start vertex. Therefore, we always find the shortest path. At each iteration, we visit the next closest node to the vertex (or one of the next closest if there is a tie).

          - how is our problem different?
             - edges have different lengths
          - Basic idea: Same as breadth first search, we'd like to visit the next closest node to the vertex each time. Keep track of three sets of vertices:
             - visited: those we've visited and have the shortest paths for
             - frontier: those we've seen as a neighbor and we have a POSSIBLE path to them, but it may not be the shortest path
             - unseen

  • random C++ for the day: makefiles!
       - for more information look at the references on the course web page
       - a command-line tool to help you compile things
       - can save you a lot of time as your C++ programs get more complicated
       - can use for Java, or other compiled languages
       - look at example makefile for assignment 11 (in /common/cs/cs062/assignments/assignment11)
          - '#' is a comment, like //
          - makefile entries are of the form:
          target: prerequisites
             instructions

          (note that you can have multiple instructions and that each instruction is preceded by a tab)

          - on the command-line you type:

          make <target>

          and it will do the following:
             - for each entry in the prerequisites:
                - if a target exists, recurse on that target
                - otherwise, do some default behavior
                   - for many file types, it just checks to make sure they exists e.g. .cpp, .h
             - once all the prerequisites have been checked and run successfully, run the instructions

          - for example:

             make mg

             - jumps to graph_movie.o
                - checks to make sure graph_movie.cpp and graph_examples.h exist
                - g++ -c graph_movie.cpp
             - jumps to graph_operations.o
                - checks to make sure graph_operations.cpp graph_operations.h priorityqueue62.h
                - g++ -c graph_operations.cpp
             - jumps to priorityqueue62.cpp
                - checks ...
                - g++ -c priorityqueye62.cpp
             - finally, after all prerequisites are satisfied:
                g++ -o mg graph_movie.o graph_operations.o priorityqueue62.o
          
          - if we type "make mg" again, make checks to see if any work needs to be done (i.e. if we've updated any files)
             - if not, tell is that mg is up to date
             - if so, will only update the required targets and rebuild
          - look at clean
             - common in Makefiles
             - removes all of the temporary files we may have made
             - allows you to start from scratch by typing "make clean"
          - .PHONY specifies that the "clean" target does not generate a file
          - we can just type "make" without any parameters
          - it runs the first target in the file
             - often a convention is to make the first target a "default" target

  • Assignment 11
       - you may work with a partner (I would encourage you to!)
       - two parts
          - three graph algorithms (closely related to what we looked at in class)
          - netflix data
             - some I/O
             - applying algorithms to real data
       - lab is important this week for getting primed for the assignment
          - if you can't make the lab, make sure to look at the material covered in the lab (in particular, the second part)
       - I've provided you with code to generate some test graphs. Use it!