An ordered, finite, mutable data structure
What about sort?
An interface class is a class that is 100% abstract (no concrete members).
There’s special keyword for it: interface
implements)“This interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class’s natural ordering, and the class’s compareTo method is referred to as its natural comparison method.”
Here’s what the Comparable interface looks like:
public class Grade implements Comparable<Grade> {
private double grade;
public Grade(double grade) {
this.grade = grade;
}
public double getGrade() {
return grade;
}
public int compareTo(Grade o) {
if (o.getGrade() > this.getGrade()) {
return -1;
}
if (o.getGrade() < this.getGrade()) {
return 1;
}
return 0;
}
}import java.util.Arrays;
public class UseGradeComparison {
public static void main(String[] args) {
Grade[] grades = new Grade[]{new Grade(10.3), new Grade(0.3), new Grade(3)};
Arrays.sort(grades); // this works because Grade implements Comparable
for (Grade g : grades) {
System.out.println(g.getGrade());
}
}
}How do we do lists?
create list of a specific size, append, prepend, remove, insert, getLength, search, sort
| Front of List | Middle of List | End of List | |
|---|---|---|---|
| get | O(1) | O(1) | O(1) |
| set | O(1) | O(1) | O(1) |
| insert | O(n) | O(n) | O(1) |
| append | N/A | N/A | O(1) |
| prepend | O(n) | N/A | N/A |
| pop | O(n) | O(n) | O(1) |
What happens when we try to append to a list/array that is already full?
Here’s how we are setting up the private instance variable: private T[] data;
Constructor:
Methods:
get(int index) – throw an error if out of rangelength() returns how many items in the listset(int index, T value) – changes the value of item at index (return a bollean if value was set successfully)toString() for testing purposesMethods:
What happens when length is the same as size?
The arrayExpand process is \(O(n)\) (gotta copy the array!) BUT it doesn’t run every time, so how do we handle the affect on append?
Best case: \(O(1)\) Worst case: \(O(n)\)
What we often care about is not the runtime of myList.append(4); but instead:
double array vs. increase array size by 10 plots
One way to think about it:
public class List<T> {
private T[] data;
private int size = 50;
private int length = 0;
public List() {
data = (T[]) new Object[size];
}
public T get(int index) {
if (index < length) {
return data[index];
}
throw new RuntimeException("index out of range");
}
public int length() {
return length;
}
public boolean set(int index, T value) {
if (index < length) {
data[index] = value;
return true;
}
return false;
}
@Override
public String toString() {
String message = "";
for (int i = 0; i < length; i++) {
message += data[i] + " ";
}
return message.trim();
}
public void append(T value) {
if (length == size) {
expandArray();
}
data[length] = value;
length++;
}
private void expandArray() {
size *= 2;
T[] newData = (T[]) new Object[size];
for (int i = 0; i < length; i++) {
newData[i] = data[i];
}
data = newData;
}
private void shiftRight(int startIndex) {
length++;
if (length == size) {
expandArray();
}
for (int i = length-1; i > startIndex; i--) {
data[i] = data[i-1];
}
}
public void prepend(T value) {
if (length == size) {
expandArray();
}
shiftRight(0);
data[0] = value;
}
public void insert(int index, T value) {
if (length == size) {
expandArray();
}
shiftRight(index);
data[index] = value;
}
private void shiftLeft(int startIndex) {
for (int i = startIndex; i < length; i++) {
data[i] = data[i+1];
}
length--;
}
public T pop() {
T value = data[0];
shiftLeft(0);
return value;
}
public void remove(int index) {
shiftLeft(index);
}
}