Lecture 13: Running Time Introduction

Announcements

LRC http://www.umass.edu/lrc/ COMPSCI 187 / ECE 242 individual tutoring has been reported as helpful. Group sessions not so much.

Our final exam is Thu 22 Dec 3:30pm. (Listed in SPIRE).

On the MAP

Group work: I hear you, but I’m getting you ready for 187.

More collaboration / coding in class: Are you envisioning a flipped classroom? I’d love to do some version of that, but first we need a textbook and a better friggin’ room.

Want solutions to projects: I can’t, as they end up posted online. Come to office hours to see them. Or keep working; the tests aren’t going to change.

Want more (implementation, architecture): Good news, you can take 187 after this class.

Programming assignments too hard / too ambiguous / directions not specific enough: Some of this is growing pains. Some of this is deliberate:

  • not all problems can be perfectly specified
  • a perfect specification is the solution!
  • not enough time? Start earlier! The code you need to write for most assignments is typically 2–5 methods, and usually under 60 lines total.

Labs too easy: that’s the idea.

Course needs to “step it up” to prep for 187. Bell diagram!

HW wording: Several people suggested making the homework more clear and including examples. Great idea!

Use more diagrams: I’ll try.

Go over HW / quizzes in more detail: great idea! We’ll start doing this more in discussion.

Want more quizzes: maybe!

Want quizzes on computer: Again, we’re resource bound by computer classrooms. I’d like it too, but it’s not available to us yet.

More 187 prep: spoiler: at the end of this semester, go download all the notes and assignments from 187. There ya go!

Today’s agenda

We can (briefly) go over Project 7.

Then we’re going to look back at what we’ve done so far, and what we have left to do over the rest of this semester.

Then we’ll start on it!

Project 7

Questions / answers.

What we’ve done

So far, we reviewed 121 material (including basic control flow, conditionals, expressions, statements, arrays, objects and classes, scope, and references).

We’ve introduced several foundational ADTs:

  • lists
  • sets
  • maps

and covered their properties. We’ve also seen their implementations in the Java API.

We’ve seen their methods, and used them to iterate over, look up items within, and modify them.

And, guess what? For about 80% or more of the programs you’re likely to write out in the real world, this is what you need to know, at least in terms of standard data structures. Lists, sets, maps, will let you represent most problems generally, and if not, you can take 187 to learn how to define your own data structures.

There are actually two or three data types and associated implementations that 187 covers that we don’t: stacks, queues, and priority queues. But they’re pretty straightforward (and we’ll get to two of the three later this semester).

What to do

So what’s left? Are we done for the semester? Of course not!

First, more practice. We’re getting you ready for 187, so there will be more programming assignments, that may start to feel more difficult in various ways. Not all of them will invoke new data structures concepts, but instead they’ll serve to give you more practice. We may also start removing some of the training wheels you’ve had so far (full sets of test cases, for example) so that you can start to get ready for the 187 experience.

Second, more exposure to other topics in computer science and informatics. This course is (or will be) a prerequisite for not just 187 but eventually for various others as well. Some of our lectures and assignments will focus on things like: working with files; simple interactions over the network (with web servers or the like); text processing and data analysis a la digital humanities; database interactions; simple data analysis or data mining; and so on.

Finally, we’re going to touch upon a few more core computer science concepts in detail. In particular, we’re going to continue our study of algorithms – how we do certain tasks – and start to develop language to describe how efficient different approaches to the same problem might be. We’ll continue to focus on “toy problems” here, things like sorting lists of numbers and searching simple graphs, but the algorithms we develop and the approaches we take will be useful to you later when tackling bigger problems. (Some of this you’ll see in later assignments, I hope.)

Thinking about efficiency

So to think about how “efficient” an algorithm, or a piece of code, is, we need a way to quantify how long it takes to run. Our rule of thumb is this: things take either:

  • a small, constant amount of time, which we’ll approximate as ‘about one unit’, or
  • they take an amount of time dependent upon some variable or variables

To simplify things, we say that almost all operators and keywords evaluate in a small, constant amount of time in Java: basic arithmetic, conditionals, assignment, array access, control flow, and method invocation. So you might look at a method like:

int add(int x, int y) {
  int sum = x + y;
  return sum;
}

and say something like: well, when this method runs, first it adds x and y (1). Then it assigns to sum (1). Then it returns (1). So it takes “about” three units of time to execute.

Or you might look at:

void honkIfEven(int x) {
  if (x % 2 == 0) System.out.println("honk");
}

and say something like, well, first x%2 is computed. Then it’s compared to zero. So the method takes at least two units. Then it might take a third to print “honk”.

Does it?

Well, that depends on the implementation of println(). To do a “real” analysis, we have to drill down into any method that’s called and check how it works, and look at methods it calls, and so on. For the purposes of this class, we’ll just state that certain methods are roughly constant time (like println), even though that’s not strictly true, in ways that will probably become clear to you as we go on.

OK, be that as it may, there’s something important to note here, which is that both of these methods take a small, fixed amount of time that doesn’t depend upon anything. Let’s look at something different:

int sum(int[] a) {
  int s = 0;
  for (int i: a) {
    s += i;
  }
  return s;
}

How long does this method take to execute? Well, about one to declare and assign 0 to s.

Then about one to update i each time through the loop, and another to update s each time through the loop.

Then one for returning s.

So what’s the answer? It depends upon the length of the array, right? It depends upon the input in other words, it’s not a constant. Some parts of the runtime are (the initial setup and the return) are constant, but some are not (the loop). Here, we might say the runtime is about 2 + 2 * (a.length). In other words, the runtime here is a function (in the mathematical sense) of the length of a.

Generally, any time you see a loop, you have the possibility of a non-constant runtime, that is, of a runtime that’s a function of (some aspect of) the input.