## Lecture 6: More on Lists

** Textbook reading:** DJW Chap. 7, except 7.1.

### Doubly Linked List

Doubly linked list; no header nodes; pointer to the end; no length
field; separate List and Node classes; list may share tails.
MyNode2.java

MyList2.java

### Java library list classes

Sample usage:
LL1.java
`Iterator` is an interface with methods hasNext() and next().

hasNext() is a boolean which is true if the collection has more
elements to iterate over.

next() returns the next item and advances the iterator.

Note that next() always advances the iterator; if you need an element
in the collection more than once, you have to save it in a variable.

Three ways to use an iterator

- Explicitly in a while loop.
- Explicitly in a for loop.
- Implicitly in the "for each" construction

`for (class variable : collection)`

Iterators and the "for each" construction are defined in any
class that implements the `Iterable` interface.
### Ordered Lists

An ordered list is one in which the terms appear in increasing (or decreasing)
order. For simplicity, we will consider ordered lists with no duplicates.
#### Ordered array list

OrderedArray.java

Methods add and delete take only one argument, because there is no choice
about where to put a new element.

#### Binary Search

Method ` Search(X)` implements * binary search*:

- Find the middle element.
- Compare X to the middle element. If X is smaller, look in the first
half of the array. If X is larger, look in the second half.
- Repeat (either recursively or iteratively).

**Time requirement:**
Suppose there are 2^{K} elements in the list. In the first
iteration, you divide the list in half, so you are now looking at
2^{K-1} elements. In the second iteration, you divide this in
half, so you are looking at 2^{K-2} elements. If you continue,
you will reach a single element in K steps. Since the number of
elements in the list N = 2^{K} we have K=log_{2} N.
So the time requirement for a binary search through N elements is
proportional to log_{2}N.
** Useful powers of 2**

2^{4} = 16. So log_{2}16 = 4.

2^{8} = 256. So log_{2}256 = 8.

2^{10} = 1024. So log_{2}1000 ≈ 10 .

2^{16} = 65,336. So log_{2}65,336 = 16.

2^{20} ≈ 1,000,000. So log_{2}1,000,000 ≈ 20.

2^{30} ≈ 1,000,000,000.
So log_{2}1,000,000,000 ≈ 30.

2^{32} ≈ 4,000,000,000.
So log_{2}4,000,000,000 ≈ 32.

### Ordered Lists

OrderedList.java

No setters for the data fields.

#### Generic Ordered Lists

GOrderedList.java

#### Comparable

`Comparable` is a Java library interface. One method is
`compareTo(y)`. If `x` and `y` are objects in a
class where `compareTo` is defined, then `x.compareTo(y)`
returns:
- a negative integer if x is less than y
- 0 if x and y are equal
- a positive integer if x is greater than y.

in whatever sense of "less", "equal", and "greater" make sense for this class.
Standard Java library classes in which "less" etc. make sense are defined as
extensions of "Comparable" and have "compareTo" methods defined.

For a user-defined class, the programmer can feel free to define a "compareTo"
method. But it has to satisfy the following properties:

- Compatability with "equals". That is,
`x.compareTo(y)` should return
0 if and only if `x.equals(y)` returns `true`.
- Antisymmetry. The sign of
`y.compareTo(x)` must be the
negative of the sign of `x.compareTo(y)`
- Transitivity. If
` x.compareTo(y)` and `y.compareTo(z)`
are both positive, then `x.compareTo(z)` must be positive.

A piece of code that uses `compareTo` generically
should not make any *other*
assumptions about its properties. However, if someone defines a
`compareTo` method that does not satisfy these, then code that
uses `compareTo` may behave very strangely.