Chapter 24
Implementing Lists, Stacks, Queues and Priority Queues
1
2
26.2 Common List Features
The MyList<E> Object Model
3
Class Deconstructed <MyList.java>
4
package inclass.lists;
public interface MyList<E> { /* Add a new element at the end of this list. */ public void add(E e); /* Add a new element at the specified index in this list. */ public void add(int index, E e); /* Clear the list. */ public void clear(); /* Return true is this list contains the element. */ public boolean contains(E e);
MyList<E> Deconstructed <MyList.java>
5
/* Return the element from this list at the specified index. */ public E get(int index); /* Return the index of the first matching element in this list. * Return -1 if no match. */ public int indexOf(E e); /* Return the index of the last matching element in this list. * Return -1 if no match. */ public int lastIndexOf(E e); /* Return true is this list contains no elements. */ public boolean isEmpty();
MyList<E> Deconstructed <MyList.java>
6
/* Remove the first occurrence of the element e from this list. * Shift any subsequent elements to the left. * Return true if the element is removed. */ public boolean remove(E e); /* Remove the element at the specified position in this list. * Shift any subsequent elements to the left. * Return the element that was removed from the list. */ public E remove(int index); /* Replace the element at the specified position in this list * with the specified element and return the old element. */ public E set(int index, E e); /* Return the number of elements in this list. */ public int size();} // end interface MyList
Class Deconstructed <MyAbstractList.java>
7
package inclass.lists;
public abstract class MyAbstractList<E> implements MyList<E> { protected int size; /* Create a default list. */ protected MyAbstractList() { size = 0; } /* Create a list from an array of objects. */ protected MyAbstractList(E[] objects) { for (int i = 0; i <= objects.length - 1; i++) { add(objects[i]); } }
MyAbstractList<E> Deconstructed <MyAbstractList.java>
8
/* Add a new element at the end of this list. */ public void add(E e) { add(size, e); } /* Return true is this list contains no elements. */ public boolean isEmpty() { return size == 0; } /* Return the number of elements in this list. */ public int size() { return size; }
MyAbstractList<E> Deconstructed <MyAbstractList.java>
9
/* Remove the first occurrence of the element e from this list. * Shift any subsequent elements to the left. * Return true is the element is removed. */ public boolean remove(E e) { int index = indexOf(e); boolean success; if (index >= 0) { remove(index); success = true; } else { success = false; } return success; }} // end of MyAbstractList<E>
10
26.3 Array Lists
MyArrayList<E> uses an array
11
Class Deconstructed <MyArrayList.java>
12
package inclass.lists;
public class MyArrayList<E> extends MyAbstractList<E> { public static final int INITIAL_CAPACITY = 16; private E[] data; /* Create a default list. */ public MyArrayList() { this(null); } /* Create a list from an array of objects. */ public MyArrayList(E[] objects) { data = (E[]) new Object[INITIAL_CAPACITY]; if (objects != null) for (int i = 0; i <= objects.length - 1; i++) add(objects[i]); }
Class Deconstructed <MyArrayList.java>
13
/* Add a new element at the specified index in this list. */ public void add(int index, E e) { ensureCapacity(); // double the array when full // Move the elements to the right after the specified index. for (int i = size - 1; i >= index; i--) data[i + 1] = data[i]; data[index] = e; size++; }
[0] [1] [2] [3] [4] [5] [6] [7] [8]
1 6 2 3 4 null null null null
index = 1e = 6
[0] [1] [2] [3] [4] [5] [6] [7] [8]
1 2 3 4 null null null null null
Class Deconstructed <MyArrayList.java>
14
/* Create a new larger array, double the current size + 1. */ private void ensureCapacity() { if (size >= data.length) { E[] newData = (E[]) new Object[size * 2 + 1]; System.arraycopy(data, 0, newData, 0, size); data = newData; } }
[0] [1] [2] [3]
1 2 3 4
[0] [1] [2] [3] [4] [5] [6] [7] [8]
1 2 3 4 null null null null null
size = 4length = 4
size = 4length = 9
Class Deconstructed <MyArrayList.java>
15
/* Clear the list. */ public void clear() { data = (E[]) new Object[INITIAL_CAPACITY]; size = 0; }
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15]
null null null null null null null null null null null null null null null null
data
Class Deconstructed <MyArrayList.java>
16
/* Return true is this list contains the element. */ public boolean contains(E e) { boolean found = false; int i = 0; while (!found && i <= size - 1) { if (e.equals(data[i])) { found = true; } else { i++; } } return found; }
Class Deconstructed <MyArrayList.java>
17
/* Return the element from this list at the specified index. */ public E get(int index) { return data[index]; }
/* Replace the element at the specified position in this list with * the specified element. */ public E set(int index, E e) { E old = data[index]; data[index] = e; return old; }
Class Deconstructed <MyArrayList.java>
18
/* Return the index of the first matching element in this list. * Return -1 if no match. */ public int indexOf(E e) { for (int i = 0; i <= size - 1; i++) if (e.equals(data[i])) return i; return -1; } /* Return the index of the last matching element in this list. * Return - 1 if no match. */ public int lastIndexOf(E e) { for (int i = size - 1; i >= 0; i--) if (e.equals(data[i])) return i; return -1; }
Warning: Use of the for not appropriate, use a while instead.
Use only one return at the end of any method.
Class Deconstructed <MyArrayList.java>
19
/* Remove the element at the specified position in this list. * Shift any subsequent elements to the left. * Return the element that was removed from the list. */ public E remove(int index) { E e = data[index]; for (int j = index + 1; j <= size - 1; j++) data[j - 1] = data[j]; data[size - 1] = null; size--; return e; }
[0] [1] [2] [3] [4] [5] [6] [7] [8]
1 3 4 null null null null null null
index = 1[0] [1] [2] [3] [4] [5] [6] [7] [8]
1 2 3 4 null null null null null
Class Deconstructed <MyArrayList.java>
20
/* Override toString() to return elements in the list. */ @Override public String toString() { StringBuilder result = new StringBuilder("["); for (int i = 0; i <= size - 2; i++) { result.append(data[i] + ", "); } result.append(data[size - 1] + "]"); return result.toString(); }
Class Deconstructed <MyArrayList.java>
21
/* Trim the capacity to current size. */ public void trimToSize() { if (size != data.length) { // If size == capacity, no need to trim. E[] newData = (E[]) new Object[size]; System.arraycopy(data, 0, newData, 0, size); data = newData; } }} // end MyArrayList
[0] [1] [2] [3] [4] [5] [6] [7] [8]
1 2 3 4 null null null null null
[0] [1] [2] [3]
1 2 3 4
size = 4length = 9
size = 4length = 4
Application Deconstructed <TestArrayList.java>
22
(1) [America](2) [Canada, America]
(3) [Russia, Spain, Italy, France, Great Britain]
remove(2): Italy(4) [Russia, Spain, France, Great Britain]
remove("Russia"):(5) [Spain, France, Great Britain]
Application Deconstructed <TestArrayList.java>
23
package inclass.lists;
public class TestArrayList { public static void main(String[] args) { MyList<String> list = new MyArrayList<String>(); list.add("America"); System.out.println("(1) " + list); list.add(0, "Canada"); System.out.println("(2) " + list);
Application Deconstructed <TestArrayList.java>
24
String[] arr = {"Russia", "Spain", "Italy", "France", "Great Britain"}; MyList<String> list2 = new MyArrayList<String>(arr); System.out.println("\n(3) " + list2); list2.remove(2); System.out.println("\nremove(2): Italy"); System.out.println("(4) " + list2); list2.remove("Russia"); System.out.println("\nremove(\"Russia\"):"); System.out.println("(5) " + list2); }} // end TestArrayList
25
26.4 Linked Lists
The MyLinkedList<E> usesa linked list
26
Each link is a node
27
element next
head tail
element next element null
Node
Class Deconstructed < Node<E> >
28
// Implemented as a private static class.private static class Node<E> { public E element; public Node<E> next;
public Node(E element) { this(element, null); }
public Node(E element, Node<E> next) { this.element = element; this.next = next; }}
Create an empty linked list
29
head tail
Node<String> head = null;Node<String> tail = null;
null null
Add a node
30
head = tail = new Node<String>("USA");
USA null
head tail
Add a node to the front
31
head = new Node<String>("Canada", head);
Canada next
head tail
USA null
USA null
head tail
Add a node to the back
32
tail = tail.next = new Node<String>("Germany", null);
Canada next
head tail
USA null
Canada next
head tail
USA next Germany null
Class Deconstructed < MyLinkedList<E> >
33
package inclass.lists;
public class MyLinkedList<E> extends MyAbstractList<E> { private Node<E> head; private Node<E> tail; public MyLinkedList() { } public MyLinkedList(E[] objects) { /* In a linked list we could call the super's constructor, * since the structure is dynamic and the add(index, E) adds * one node at a time. */ super(objects); }
Class Deconstructed < MyLinkedList<E> >
34
public void addFirst(E element) { if (size == 0) { // Empty list. head = tail = new Node<E>(element, head); } else { // List has at least one node. head = new Node<E>(element, head); } // end if
size++; }
element null
head tail
element nullelement next
head tail
35
public void addLast(E element) { if (size == 0) { // Empty list. head = tail = new Node<E>(element, null); } else { // List has at least one node. tail = tail.next = new Node<E>(element, null); } // end if size++; }
Class Deconstructed < MyLinkedList<E> >
element null
head tail
element nullelement next
head tail
36
public E getFirst() { return (size == 0)? null : head.element; }
public E getLast() { return (size == 0)? null : tail.element; }
Class Deconstructed < MyLinkedList<E> >
37
public E removeFirst() { E element = null; if (size == 1) { // Remove the only node. element = head.element; head = tail = null; } else if (size > 1) { // Remove the first node. element = head.element; head = head.next; } // end if size--; return element; }
Class Deconstructed < MyLinkedList<E> >
element null
head tail
element nullelement next
head tail
element next
head tail
nullnull
38
public E removeLast() { E element = null; if (size == 1) { // Remove the only node. element = tail.element; head = tail = null; } else if (size > 1) { // Remove the last node. Node<E> before = head; element = tail.element; while (before.next != tail) { before = before.next; } // end while tail = before; tail.next = null; } // end if size--; return element; }
Class Deconstructed < MyLinkedList<E> >
element nullelement next
head tail
element next
before
null
39
@Override public void add(int index, E element) { if (index <= 0 ) { addFirst(element); } else if (index >= size) { addLast(element); } else { Node<E> before = head; for (int i = 1; i <= index - 1; i++) before = before.next; // Add the node after before.
Node<E> after = before.next; before.next = new Node<E>(element, after); size++; } // end if }
Class Deconstructed < MyLinkedList<E> >
element nullelement next
head tailbeforeindex
element next
after
40
@Override public E remove(int index) { E element; if (index < 0 || index >= size) { // If index is invalid, return null. element = null; } else if (index == 0) { // Remove the first node. element = head.element; removeFirst(); } else if (index == size - 1) { // Remove the last node. element = tail.element; removeLast(); }
Class Deconstructed < MyLinkedList<E> >
41
else { // Remove a node inside the list. Node<E> before = null; Node<E> del = head; for (int i = 1; i <= index; i++) { before = del; del = del.next; } // end for element = del.element; Node<E> after = del.next; before.next = after; } // end if
del = null; return element; }
Class Deconstructed < MyLinkedList<E> >
element nullelement next
head tail
element next
before del
index
after
42
@Override public String toString() { StringBuilder result = new StringBuilder("["); Node<E> iter = head; while (iter.next != null) { result.append(iter.element + ", "); iter = iter.next; } // end while result.append(iter.element + "]"); return result.toString(); }
Class Deconstructed < MyLinkedList<E> >
43
@Override public void clear() { head = tail = null; size = 0; }
@Override public boolean contains(E element) { Node<E> iter = head; boolean found = false; while (!found && iter != null) { if (element.equals(iter.element)) found = true; else iter = iter.next; } return found; }
Class Deconstructed < MyLinkedList<E> >
44
@Override public E get(int index) { E element; if (size == 0) { element = null; } else if (index < 0) { element = head.element; } else if (index >= size) { element = tail.element; } else { Node<E> iter = head; for (int i = 1; i <= index; i++) { iter = iter.next; } // end for element = iter.element; } // end if return element; }
Class Deconstructed < MyLinkedList<E> >
45
@Override public int indexOf(E element) { int index = -1; int count = 0; boolean found = false; Node<E> iter = head; while (!found && iter != null) { if (element.equals(iter.element)) { index = count; found = true; } else { count += 1; iter = iter.next; } // end if } // end while return index; }
Class Deconstructed < MyLinkedList<E> >
element nullelement next
head tail
element next
count = 1index = 1found = true
iter
46
@Override public int lastIndexOf(E element) { int index = -1; int count = 0; Node<E> iter = head; while (iter != null) { if (element.equals(iter.element)) { index = count; } count += 1; iter = iter.next; } // end while return index; }
Class Deconstructed < MyLinkedList<E> >
element nullelement next
head tail
element next
count = 1index = 1
count = 2index = 2
iter null
47
@Override public E set(int index, E element) { E oldElement; if (index < 0 || index >= size) { oldElement = null; else { Node<E> iter = head; for (int i = 1; i <= index; i++) { iter = iter.next; } // end for oldElement = iter.element; iter.element = element; } // end if return oldElement; }
Class Deconstructed < MyLinkedList<E> >
Application Deconstructed < TestMyLinkedList<E> >
48
list: [USA, Canada, Mexico, Costa Rica, Guatemala]list: [Honduras, USA, Canada, Mexico, Costa Rica, Guatemala, El Salvador]
list: [Canada, Mexico, Costa Rica, Guatemala]list: contains USA = falselist: size = 4
49
package inclass.lists;
public class TestMyLinkedList { public static void main(String[] args) { MyLinkedList<String> list = new MyLinkedList<String>(); list.add("USA"); list.add("Canada"); list.add("Mexico"); list.add("Costa Rica"); list.add("Guatemala"); System.out.println("list: " + list);
Application Deconstructed < TestMyLinkedList<E> >
list: [USA, Canada, Mexico, Costa Rica, Guatemala]
50
list.addFirst("Honduras"); list.addLast("El Salvador"); System.out.println("list: " + list);
Application Deconstructed < TestMyLinkedList<E> >
list: [USA, Canada, Mexico, Costa Rica, Guatemala]list: [Honduras, USA, Canada, Mexico, Costa Rica, Guatemala, El Salvador]
51
list.removeFirst(); list.removeLast(); list.remove(0); System.out.println("\nlist: " + list); System.out.println("list: contains USA = " + list.contains("USA")); System.out.println("list: size = " + list.size()); } // end main()} // end TestMyLinkedList
Application Deconstructed < TestMyLinkedList<E> >
list: [USA, Canada, Mexico, Costa Rica, Guatemala]list: [Honduras, USA, Canada, Mexico, Costa Rica, Guatemala, El Salvador]
list: [Canada, Mexico, Costa Rica, Guatemala]list: contains USA = falselist: size = 4
52
26.5 Variations of Linked Lists
A circular linked list wraps
53
element next
list
element next element next
A doubly linked list is bidirectional
54
element nextnull element nextprevious element nullprevious
head tail
private static class Node<E> { public E element; public Node<E> previous; public Node<E> next;
public Node(E element) { this(element, null, null); } public Node(E element, Node<E> previous, Node<E> next) { this.element = element; this.previous = previous; this.next = next;}
A circular doubly linked list is bidirectional and wraps
55
element nextprevious element nextprevious element nextprevious
list
56
26.6Stacks
and Queues
Stacks are LIFO structures
57
data 3
data 2data 1
data 3data 2data 1
Last In
data 2data 1
First Out data 3
Queues are FIFO structures
58
data 3
data 2data 1
data 3data 2data 1First In
data 3data 2
First Outdata 1
MyQueue<E> using a LinkedList<E>
59
Class Deconstructed < MyQueue<E> >
60
package inclass.lists;
public class MyQueue<E> { private MyLinkedList<E> list; public MyQueue() { list = new MyLinkedList<E>(); } // end MyQueue() public void enqueue(E element) { list.addLast(element); } // end enqueue() public E dequeue() { return list.removeFirst(); } // end dequeue()
61
public int getSize() { return list.size(); } // end getSize() @Override public String toString() { return list.toString(); } // end toString() } // end TestMyQueue
Class Deconstructed < MyQueue<E> >
Application Deconstructed < TestMyQueue<E> >
62
[Alpha, Beta, Gamma, Delta] size = 4[Gamma, Delta] size = 2
63
package inclass.lists;
public class TestMyQueue { public static void main(String[] args) { MyQueue<String> queue = new MyQueue<String>(); queue.enqueue("Alpha"); queue.enqueue("Beta"); queue.enqueue("Gamma"); queue.enqueue("Delta"); System.out.println(queue + " size = " + queue.getSize());
Application Deconstructed < TestMyQueue<E> >
[Alpha, Beta, Gamma, Delta] size = 4
64
queue.dequeue(); queue.dequeue(); System.out.println(queue + " size = " + queue.getSize()); } // end main() } // end TestMyQueue
Application Deconstructed < TestMyQueue<E> >
[Alpha, Beta, Gamma, Delta] size = 4[Gamma, Delta] size = 2
65
26.7 Priority Queues
A priority queue removes itemwith highest priority
66
P = 10
P = 9
P=2 P = 3
P = 7
P = 1
P = 9
P = 3
P=2 P = 1
P = 7
Heap