3. Linear lists, simple searching, and sorting Lists are an important structure, not just in Computer Science, but in life in general.
If the number of elements in a list is known beforehand, then most programming languages already provide a very good data structure for it: (one-dimensional) arrays.
But if we do not know the required length of a list, then we need to put some effort into creating an
appropriate data structure for it.
Depending on the operations we want to perform on a list, there are several possibilities: singly, circularly, and doubly linked lists.
CPSC 319 J. Denzinger
1
The abstract data type (ADT) “List”
public interface List<E> {
// in Java ADTs usually are implemented as an interface;
// E denotes the type of the list elements public void size();
// returns the number of elements in the list (can also be called length()).
public void isEmpty();
// returns true if list is empty, false otherwise public E get(int i);
// returns the element of the list at position i.
public void set(int i, E e);
// replaces the element at position i by the element e.
public void add(int i, E e);
// inserts e at position i in the list (can also be called insert).
CPSC 319 J. Denzinger
2
The abstract data type (ADT) “List” (cont.)
public void remove(int i);
// removes the element at position i from the list // (if the list has i or more elements).
}
Note that for some types of lists there are other methods, often to help with implementing the above ones.
Also, these methods have different complexities for different implementations.
CPSC 319 J. Denzinger
3
3.1 Lists as arrays
While the core data structure for implementing a list by an array is naturally said array, it makes sense to have additional information as part of an (array) list object which allow more efficient implementation of some of the methods:
} the maximum size of the list (array)
} the current size of the list and
} the current position in the list (to help methods that need to traverse the list)
This leads to the following class:
CPSC 319 J. Denzinger
4
ListasArray
class ListasArray<E> implements List<E> { private static final int sizeDefault = 100;
private int maxSize;
private int listSize;
private int currPos; // Position of current element private E[] listArray;
// constructors
public ListasArray() { this(sizeDefault); } public ListasArray(int capacity) {
maxSize = capacity-1;
listSize = currPos = 0;
listArray = (E[]) new Object[capacity];
}
… } // what is in … will be presented on following slides
ListasArray: the methods
public int size() {return listSize;}
Complexity: O(1)
public void isEmpty() {return listSize == 0 ;}
Complexity: O(1)
public E get(int i) throws IndexOutOfBoundsException {
if (i < 0 ||i > listSize-1) // remember: index of last element is listSize-1 throw new IndexOutOfBoundsException(“Illegal index”);
return listArray[i];
}
Complexity: O(1)
Note, by using the Java exception we allow users of this
implementation to deal with errors in their main programs if they
want to.
ListasArray: the methods
public void set(int i, E e) throws IndexOutOfBoundsException { if (i < 0 ||i > listSize-1)
throw new IndexOutOfBoundsException(“Illegal index”);
listArray[i] = e;
}
Complexity: O(1)
CPSC 319 J. Denzinger
7
ListasArray: the methods
public void add(int i, E e) throws IndexOutOfBoundsException, IllegalStateException { if (i < 0 ||i > listSize-1)
throw new IndexOutOfBoundsException(“Illegal index”);
if listSize == maxSize
throw new IllegalStateException(“list is full”);
for (int j = listSize-1; j >= i; j--) // need to move right and at insert point to listArray[j+1] = listArray[j]; // right to make room for new element listArray[i] = e;
listSize++; // do not forget that list is now 1 element longer }
Complexity: O(n) n list size
CPSC 319 J. Denzinger
8
ListasArray: the methods
public E remove(int i) throws IndexOutOfBoundsException { if (i < 0 ||i > listSize)
throw new IndexOutOfBoundsException(“Illegal index”);
E result = listArray[i];
for (int j = i; j < listSize; j++) // need to move elements from the list listArray[j] = listArray[j+1]; // beyond i one to the left listArray[listSize] = null;
listSize--;
return result;
}
Complexity: O(n) n list size
CPSC 319 J. Denzinger
9
ListasArray: pros and cons
+ very quick in accessing an element at known position
- potentially rather slow when adding or deleting an element
- what to do, when we are running out of room (length needs to be known beforehand)
☛ good for lists that do not change often
CPSC 319 J. Denzinger
10
3.2 Singly linked lists General idea:
A list element (link) consists of the data element we want to store in the list and a pointer to the next list element:
(this is the main data structure in Lisp-programs).
CPSC 319 J. Denzinger
1 2 3
listHead
⊥ (null)
11
ListSingleLinked: class for a link
class Link<E> { private E element;
private Link<E> next;
//Constructors
Link(E item, Link<E> nextlink) { element = item; next = nextlink; } Link(Link<E> nextlink)
{ next = nextlink; } //Access/set values Link<E> next() { return next; }
Link<E> setNext(Link<E> nextlink) { return next = nextlink; } E element() { return element; }
E setElement(E item) { return element = item; } }
CPSC 319 J. Denzinger
12
ListSingleLinked
class ListSingleLinked<E> implements List<E> { private Link<E> head; //points to first element of list private Link<E> last; //points to last element of list private Link<E> current; //current element of list private int length; //number of elements in list //Constructors
ListSingleLinked(int size) { this(); } //size not really needed ListSingleLinked() {
current = last = head = new Link<E> (null) ; //creates header of list length = 0; //no element in list, yet, only header
}
… //see following slides }
CPSC 319 J. Denzinger
listHead
⊥
13
ListSingleLinked: the methods
public int size() {return length;}
Complexity: O(1)
public boolean isEmpty() {return length == 0 ;}
Complexity: O(1)
Some navigating in the list (help for other methods):
public void goToEnd() { current = last ; } public void next() {
if (current != last) current = current.next() ; }
Complexity: O(1) for both
CPSC 319 J. Denzinger
14
ListSingleLinked: the methods
public void prev() { if (current == head) return ; Link<E> check = head ;
while (check.next() != current) check = check.next();
current = check;
}
public void moveToPos(int position) throws IndexOutOfBoundsException { if (position < 0 ||position > length)
throw new IndexOutOfBoundsException(“Illegal index”);
current = head
for (int i=0 ; i < position ; i++) current = current.next() ; }
Complexity: O(n)
CPSC 319 J. Denzinger
15
ListSingleLinked: the methods
public E get(int i) throws IndexOutOfBoundsException { moveToPos(i);
return current.element();
}
public void set(int I, E e) throws IndexOutOfBoundsException { moveToPos(i);
current.setElement(e);
}
Complexity: O(n) (due to method call)
CPSC 319 J. Denzinger
16
ListSingleLinked: the methods
public void add(int i, E e) throws IndexOutOfBoundsException { moveToPos(i);
if (current == head) {
head = new Link<E>(e,current.next());
return;
}
current.setNext(new Link<E>(e,current.next()));
if (current == last) last = current.next();
length++;
}
Complexity: O(n) (due to first method call)
ListSingleLinked: the methods
i i+1
current
ListSingleLinked: the methods
CPSC 319 J. Denzinger
i i+1
current
e new Link<E>( e)
19
ListSingleLinked: the methods
CPSC 319 J. Denzinger
i i+1
current
e new Link<E>( e,current.next())
20
ListSingleLinked: the methods
CPSC 319 J. Denzinger
i i+1
current
e after
current.setNext(new Link<E>( e,current.next()))
21
ListSingleLinked: the methods
public E remove(int i) throws IndexOutOfBoundsException { moveToPos(i);
if (current.next() == null) return null;
E result = current.element();
if (current == head) { head = current.next();
length- -;
return result; } prev();
if (current.next() = last) last = current current.setNext(current.next().next());
length- -;
return result;
}
Complexity: O(n) (due to first method call)
Can be done better, but still only in O(n)
CPSC 319 J. Denzinger
22
ListSingleLinked: the methods
CPSC 319 J. Denzinger
i-1 i i+1
current after moveToPos:
23
ListSingleLinked: the methods
CPSC 319 J. Denzinger
i-1 i i+1
current after prev():
24
ListSingleLinked: the methods
CPSC 319 J. Denzinger
i-1 i i+1
current
after current.setNext(current.next().next()):
25
ListSingleLinked: pros and cons + can deal with arbitrary length lists
- every method using prev or moveToPos potentially needs to traverse the whole list (although depending on the application, if we work on the same part of the list for some time current can be used to speed up things)
☛ good for lists that change often near the head
CPSC 319 J. Denzinger