## Announcements

• Let’s just go over the goddamn exam.
• Yes, we will have class next Tuesday, sorry
• There’s a lot of material to cover, okay?
• Project 4.. has no coding!
• You’ll basically be designing/documenting an ADT interface
• And this will give you practice with javadoc as well
• I will make it due a week after whenever it’s released.
• We’re gonna be going into a lot of detail on designing an ADT today, so pay attention!

## Lists

• We’ve been talking about sorting and ordered data and stuff
• And arrays in Java have been a mainstay of your code for years now
• But we keep running into the same problems with arrays over and over
• They can’t be resized, so if you want to grow/shrink them dynamically, you have to do it yourself
• If you want to insert/remove something in the middle, you have to shift all the items yourself
• So let’s design an ADT to abstract some of this stuff away.
• What two things does an ADT specify?
• What data it holds
• What operations you can do on the data
• It’s actually going to be very similar to, say, Bag
• Let’s think of a list. What does it hold?
• A collection of items
• In a particular order
• And probably of the same or similar type, cause it wouldn’t make much sense otherwise…
• It also knows how many items there are.
• How can you change a list?
• Add more things to it
• Where can we add things?
• Remove things from it
• Change the things that are in it
• Sort it?
• Clear it (remove all items)
• How can you inspect a list?
• Get an item from a particular position
• See how long it is
• See if it’s empty
• See if it contains something
• See where something is in the list

## Designing the Java List interface

• Let’s keep it simple and assume all lists are dynamically resizable, so adding can never fail.
• What should the parameter(s) be? (What were they for Bag?)
• Just add(E item) I guess
• But lists also have an order and it’s useful to put the item in a place
• So maybe a second overload for add(int position, E item)
• For add(E item) what should it do?
• What’s the most “natural” place to write something new on a list?
• At the end.
• So let’s try to be very precise about what it should do. How will it change the data in the list?
• The existing items will remain unchanged.
• The new item will be placed at position size.
• The size of the list will increase by 1.
• Now for add(int position, E item). How will it change the data in the list?
• Actually, what positions should we allow?
• We’d like to be able to insert items at the beginning…
• or anywhere in the middle…
• or at the end.
• So let’s say that the position argument means “what item it will be inserted in front of.”
• And if position == size, it will insert the item at the very end, like add(E).
• So how will this method change the list?
• The items from 0 to position - 1 will remain unchanged.
• The items from position to size - 1 will move to position + 1 to size.
• The new item will be placed at position.
• The size of the list will increase by 1.
• For add(E item), what should the return value be?
• Do we really need one? I mean, not really…
• But we could make it return the position of the newly-added item.
• So either int or void would work.
• For add(int position, E item), what should the return value be?
• Could return the position, but that’s a parameter…
• I’d go with void myself.
• Should these methods throw any exceptions?
• Neither can “run out of room.”
• add(E) always knows where it will add the item.
• add(int, E) might fail…
• What if the user gives a negative position?
• What if the user gives a position greater than size?
• Let’s throw IllegalArgumentException in this case.
• What about null values? Is that really a problem?
• It’s pretty common to have lists of objects which have nulls.
• Then again, it’s not common to have lists of numbers with nulls…
• Java doesn’t really have a great way to deal with this. :P
• Let’s just say that null values are not allowed, and both these methods will throw NullPointerException in that case.
• Whew!
• This is what ADT design is really like.
• This is what good programming is really like.
• Either an implementor or a client could look at this interface and know exactly what to do.
• The better you can explain what/how a piece of code works, the better your code will be.
• Human language is not the most precise way of specifying programs, but it is still super important in all kinds of engineering!
• This is what project 4 will be about.
• Let’s think about the other methods
• int size()
• boolean isEmpty()
• E remove(int position)
• boolean remove(E value)
• E get(int position)
• void set(int position, E value)
• sadly Java has no way to make [] work on our own types…
• int indexOf(E value)
• We can also use this to see if the list contains something
• void sort()???
• What will this require of the type E?
• Do we necessarily want to enforce this?
• Maybe let’s not put this in the ADT…
• This might be a good choice for another interface that implements ListInterface
• Maybe SortableList?

## What are lists good for?

• All kinds of things!
• Pretty much anywhere you’d use an array, you could use a List instead.
• (sadly in Java it’s not a drop-in replacement)
• (since you have to use e.g. .get() and .set() and .size())
• (oh well.)
• Could you use a List as a Stack?
• Sure!
• push(E) is just add(E)
• E pop() is just remove(size() - 1)
• Could you use a List as a first-in, first-out data structure?
• Like the line at a grocery store?
• Sure!
• You would always add to one end and remove from the other.
• Could you use a List as a Bag?
• Sure!
• Is a List the best choice for these situations?
• Mmmmmmmaybe not necessarily…
• We’ll talk about performance soon.

## Implementing a List

• What’s the most obvious way to store the data of a List?
• An array!
• But do we need to keep track of anything else? (Think back to our resizable Bag.)
• A size.
• Huh, this looks pretty similar to Bag already…
• Let’s implement the easy ones first.
• int size()
• boolean isEmpty()
• Now for add(E).
• Don’t forget to check for invalid parameters.
• It’s gonna be just like Bag or Stack.
• Gotta make sure the array is big enough first…
• Now for add(int, E).
• Don’t forget to check for invalid parameters.
• What do we do when inserting at the beginning or middle of the list?
• We have to slide the items down.
• Are there any special cases to consider?
• What about when the item is being inserted at the end?
• Now for E remove(int).
• This is gonna be kind of the opposite of add(int, E)
• We can’t “cheat” like we did for Bag, because order matters now.
• The other methods…
• Well I’ll leave that to you 😉

## Implementing a List another way?

• I mean, the name’s right there.
• Linked lists have some nice properties.
• If we want to remove an item from a linked list, how do we do it?
• We just “stitch” the node before the item to remove to the node after it.
• There is no “sliding” needed - the list just stays in the right order.
• Same deal, but in reverse.
• But linked lists have one big issue…
• If we want to get the ith item, what do we have to do?
• Hop through every item before it.
• Linked lists have some special cases to watch out for, too.
• What if you remove the first node (the head)?
• What if there’s only one node and you remove it?
• What if you add an item to a list with no nodes?

• How long does it take to get to a position in the list?
• $O(n)$.
• add and remove both need to get to a position…
• So even though the actual operation of adding or removing a node is $O(1)$
• add and remove themselves will be $O(n)$.
• But add(E) is a common operation… it’s dumb for it to be $O(n)$!
• What’s the problem? What’s slowing us down?
• Why don’t we just keep track of the last node (the tail)?
• Now we can get the first or last items in the list in $O(1)$ time!
• So adding or removing those items is $O(1)$, which is neat.
• But keeping track of the tail adds some special cases…
• What if you remove the last node (the tail)?
• What if you add an item after the tail?
• How will the cases when you add to an empty list or you remove the only node from a list?

## Comparing performance

• Let’s compare the two implementations (array and linked).
• getting to a position
• With arrays, this is $O(1)$ - you just index the array.
• With linked lists, this is $O(n)$.
• get() and set()
• These both use “getting to a position”, so they have the same runtime as that.
• add(E)
• This is amortized $O(1)$ for arrays
• This is $O(n)$ for linked lists, if we don’t keep track of the tail..
• But it’s also $O(1)$ for linked lists if we do.
• add(int, E)
• For arrays, this is $O(n)$ because we have to slide things down.
• For linked lists, this is $O(n)$ because we have to get to the position.
• However, if you’re adding to the front of the list a lot…
• linked lists would be the better choice, since that’s a best case ($O(1)$) operation.
• this is a worst case for arrays.
• remove(int)
• Same as add() for the same reasons.
• So which do you use?
• It depends on your use case!
• If you are doing random accesses to the list, an array makes more sense.
• If you are doing lots of adds and removes to the ends of the list, a linked list makes more sense.
• If you need to sort the lists…
• Gosh, how do you even sort a linked list?
• It’s possible, but awkward.

## An Average-Case analysis

• Remember how to do this?
• For a List of length n
• Consider the probability of accessing each position
• And consider the cost of accessing each position
• Multiply together and sum up over all possibilities
• A “weighted average”
• Let’s assume all positions are equally likely to be accessed.
• Then the probability $P(i) = \frac{1}{n}$ for all items.
• How many steps does it take to access any item in a linked list?
• As many steps as its position.
• So, if it’s index is i, then it takes i steps. $Cost(i) = i$
• So it looks like this…

• This is still $O(n)$… but in practice, it’ll be a bit less.
• But of course, this analysis can change based on the probability!
• What if the probabilities were distributed such that 100% of the accesses were to the last item?
• Then all the other terms of the sum drop out
• And now the average case is $O(1)$.