Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Ian Kenny
October 28, 2016
Software Workshop
Lecture 5b
Announcements
Class layout.
static data.
non-static data.
static methods.
constructors.
other methods.
In this lecture
Data Structures: ArrayList, LinkedList.
Introduction
In Java, the term data structure refers to an object that holds
multiple other objects. An object could be called a ’data structure’
because it holds data, but that is not the sense in which the term
is used. Data structures hold collections of data, usually of the
same type1 . The whole point of a data structure is to hold
collections of other objects.
1
As we shall see, they can also hold multiple objects of different types.
More on that on another day.
Introduction
In the previous lectures we have used the built-in Java arrays as
data structures. The built-in arrays are, however, inconvenient. We
must know how many items we will want to store in the collection
when we create the array, and they can become fragmented if we
’delete’ items from them2 . We also need to keep track of how
many items we think are in the array because the only information
available from the array itself is the size it was created with (which
is the array’s maximum and minimum size).
2
We cannot literally delete items from them. (If it holds reference types we
can set them to null).
The Java Collections Framework (JCF)
The Java Collections Framework (JCF) is a group of data
structures that support the holding of collections of data.
They provide functionality to allow you to access, find, add and
remove the elements of the data structure easily.
There are a large number of data structures available and we can
only cover some of the key ones.
Which data structure you select depends on the type of task you
are undertaking: some are better suited to certain tasks than
others, as we shall see.
We will now look at some of the most commonly used data
structures.
ArrayList
ArrayList is one of the most commonly used data structures in
Java. The underlying storage in ArrayList is a regular built-in
Java array hence it offers random access.
But ArrayList is a dynamic structure which means that you do
not have to specify the size of the array upon creation and that it
will grow (and can shrink) to accommodate the elements added to
it.
However, since the underlying implementation uses an array, if you
add an item to an ArrayList when it is ’full’ (up to its current
capacity), then a new larger array needs to be created and all of
the current items (plus the new one) added to it. This is a bit
time-consuming3 .
3
Remember: this is all going on ’under the hood’. The programmer doesn’t
need to do this reallocation.
Using ArrayList
What will the output be?
package com.ianskenny.testdatastructures;
import java.util.ArrayList;
public class TestArrayList {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
String s = "abc";
arrayList.add(s);
String t = arrayList.get(0);
System.out.println(t);
}
}
Listing 1 : TestArrayList.java
ArrayList
This won’t work because we didn’t specify that the ArrayList
contained Strings. Since we didn’t specify what the ArrayList
contains, it contains objects of type Object. These cannot be
converted automatically to Strings.
We can use ArrayList in this way if we insist, but we need to
cast the result of get() as shown on the next slide.
ArrayList
This will work but it involves a bit of extra work.
package com.ianskenny.testdatastructures;
import java.util.ArrayList;
public class TestArrayList2 {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
String s = "abc";
arrayList.add(s);
// a cast is required.
String t = (String)arrayList.get(0);
System.out.println(t);
}
}
Listing 2 : TestArrayList2.java
ArrayList
But, we can avoid this extra work by simply specifying which type
we wish to store in the ArrayList as shown here.
package com.ianskenny.testdatastructures;
import java.util.ArrayList;
public class TestArrayList3 {
public static void main(String[] args) {
ArrayList<String> arrayList = new
ArrayList<String>();
String s = "abc";
arrayList.add(s);
String t = arrayList.get(0); // no cast required.
System.out.println(t);
}
}
Listing 3 : TestArrayList3.java
Generics
The JCF classes use the concept of Java Generics. This facility
enables us to parameterise classes. In the example shown on the
previous slide, we create an object of type ArrayList and tell it
that we wish it to contain objects of type String using the angle
brackets < >. String is the parameter.
Using ArrayList
Some of the most common operations we will need to use with the
Java collections are iteration, adding, removing, getting. We will
now look at some examples of these operations.
Adding
We have already seen how to add to an ArrayList. We use the
add() method. The default behaviour is to add at the end of the
array.
package com.ianskenny.testdatastructures;
import java.util.ArrayList;
public class TestArrayList3 {
public static void main(String[] args) {
ArrayList<String> arrayList = new
ArrayList<String>();
String s = "abc";
arrayList.add(s);
String t = arrayList.get(0); // no cast required.
System.out.println(t);
}
}
Listing 4 : TestArrayList3.java
Removing
Removing an element is also straightforward. We use the
remove() method.
package com.ianskenny.testdatastructures;
import java.util.ArrayList;
public class TestArrayList5 {
public static void main(String[] args) {
ArrayList<String> beatles = new
ArrayList<String>();
beatles.add("John Lennon"); // element 0
beatles.add("Paul McCartney"); // element 1
beatles.add("George Harrison"); // etc.
beatles.add("Pete Best");
beatles.remove(3); // Pete Best was sacked
beatles.add("Ringo Starr");
for (int i = 0; i < beatles.size(); i++) {
System.out.println(beatles.get(i));
}
}
}
Listing 5 : TestArrayList5.java
Removing
Does the same thing but shows a different method of using
remove().
package com.ianskenny.testdatastructures;
import java.util.ArrayList;
public class TestArrayList6 {
public static void main(String[] args) {
ArrayList<String> beatles = new
ArrayList<String>();
String
String
String
String
s1
s2
s3
s4
=
=
=
=
"John Lennon";
"Paul McCartney";
"George Harrison";
"Pete Best";
beatles.add(s1); // element 0
beatles.add(s2); // element 1
beatles.add(s3); // etc.
beatles.add(s4);
beatles.remove(s4); // Pete Best was sacked
s4 = "Ringo Starr";
beatles.add(s4);
for (int i = 0; i < beatles.size(); i++) {
System.out.println(beatles.get(i));
}
}
}
Listing 6 : TestArrayList6.java
get()
We have already seen the use of get(). It retrieves an element of
the array.
package com.ianskenny.testdatastructures;
import java.util.ArrayList;
public class TestArrayList6 {
public static void main(String[] args) {
ArrayList<String> beatles = new
ArrayList<String>();
String
String
String
String
s1
s2
s3
s4
=
=
=
=
"John Lennon";
"Paul McCartney";
"George Harrison";
"Pete Best";
beatles.add(s1); // element 0
beatles.add(s2); // element 1
beatles.add(s3); // etc.
beatles.add(s4);
beatles.remove(s4); // Pete Best was sacked
s4 = "Ringo Starr";
beatles.add(s4);
for (int i = 0; i < beatles.size(); i++) {
System.out.println(beatles.get(i));
}
}
}
Listing 7 : TestArrayList6.java
Iteration
We can use regular for loops with these collections, as we have
seen above.
package com.ianskenny.testdatastructures;
import java.util.ArrayList;
public class TestArrayList4 {
public static void main(String[] args) {
ArrayList<String> beatles = new
ArrayList<String>();
beatles.add("John Lennon"); // element 0
beatles.add("Paul McCartney"); // element 1
beatles.add("George Harrison"); // etc.
beatles.add("Pete Best");
for (int i = 0; i < beatles.size(); i++) {
System.out.println(beatles.get(i));
}
}
}
Listing 8 : TestArrayList4.java
Iteration
We can also use the newer for-each style loop. We don’t need to
use get() here.
package com.ianskenny.testdatastructures;
import java.util.ArrayList;
public class TestArrayList7 {
public static void main(String[] args) {
ArrayList<String> beatles = new
ArrayList<String>();
String
String
String
String
s1
s2
s3
s4
=
=
=
=
"John Lennon";
"Paul McCartney";
"George Harrison";
"Ringo Starr";
beatles.add(s1); // element 0
beatles.add(s2); // element 1
beatles.add(s3); // etc.
beatles.add(s4);
for (String s: beatles) {
System.out.println(s);
}
}
}
Listing 9 : TestArrayList7.java
Other methods
Those are the most commonly used methods. There are many
others. Check the Java API documentation to see which other
methods are available for ArrayList. Some other useful methods
include clear(), toArray(), indexOf(), subList().
Performance
The performance of a data structure, in terms of how long it takes
to add and remove items, find items, etc. can be a consideration.
Arrays have the advantage of being random access i.e. it takes the
same length of time to access any element.
However, insertion into an array can be costly especially if the
system has to resize the array to accommodate it.
To place an item in the array at any position other than the end of
the array requires all of the subsequent elements to be moved this
could be costly if you are constantly adding and removing items.
ArrayList is good for situations where you want to store a lot of
data but then not change it very often, and also for situations
where you will only ever insert at the end of the array.
Linked lists
A linked list is a data structure in which each element in the
collection is linked to either the next one (singly-linked list ), or
the next one and the previous one (doubly linked list). The
elements are stored in nodes. Each node contains an element and
a link to exactly one or exactly two other nodes.
This arrangement means that the elements in a collection organised
as a linked list do not have to be stored contiguously in memory.
Linked lists do not offer random access but sequential access. To
access an element in the collection requires traversing the links in
the collection to find the item. In the worst case, if the item is at
the end of the list, then you may have to traverse the entire list to
find the item. However, list implementations generally provide easy
access to the head (start) of the list and tail (end) of the list.
Linked lists
This is a singly-linked list.
https://linuxjunkies.wordpress.com/2012/02/04/linked-lists-in-java/
LinkedList
Java has an implementation of a linked list called LinkedList. For
many purposes its operation is very similar to that of ArrayList.
LinkedList
What will the output be?
package com.ianskenny.testdatastructures;
import java.util.LinkedList;
public class TestLinkedList1 {
public static void main(String[] args) {
LinkedList<String> beatles = new
LinkedList<String>();
String
String
String
String
s1
s2
s3
s4
=
=
=
=
"John Lennon";
"Paul McCartney";
"George Harrison";
"Pete Best";
beatles.add(s1); // element 0
beatles.add(s2); // element 1
beatles.add(s3); // etc.
beatles.add(s4);
beatles.removeLast();
beatles.addFirst("Ringo Starr");
for (String s: beatles) {
System.out.println(s);
}
}
}
Listing 10 : TestLinkedList1.java
Linked lists: insertion
This is a singly-linked list.
https://linuxjunkies.wordpress.com/2012/02/04/linked-lists-in-java/
Performance
Insertion into a linked list requires the insertion point to be found,
a new node to be created and the links to the other nodes to be
set. This is generally a less expensive operation than insertion into
an array which may involve resizing the array and/or shifting
elements of the array. Deletion from a linked list is similar but, of
course, does not require the creation of a new node. Deletion from
an array may involve shifting elements in the array ’downwards’ to
close the gap.
Finding items in a linked list is likely to be a slower operation than
for arrays since linked lists do not offer random access.
ArrayList is perhaps better when you need to access data
frequently but not change it. LinkedList might be better when
you want to access data less frequently but change it more often.
Removing elements: what will happen?
package com.ianskenny.testdatastructures;
import java.util.ArrayList;
public class TestArrayList8 {
public static void main(String[] args) {
ArrayList<String> beatles = new ArrayList<String>();
String
String
String
String
s1
s2
s3
s4
=
=
=
=
"John Lennon";
"Paul McCartney";
"George Harrison";
"Pete Best";
beatles.add(s1); // element 0
beatles.add(s2); // element 1
beatles.add(s3); // etc.
beatles.add(s4);
for (String s: beatles) {
System.out.println(s);
}
for (String s: beatles) {
if (s.equals("Pete Best") || s.equals("John Lennon")) {
beatles.remove(s);
}
}
}
}
Listing 11 : TestArrayList8.java
Removing elements
This will cause an exception:
Exception in thread "main"
java.util.ConcurrentModificationException
Because this program modifies a collection and the continues
operating on it. This is not allowed.
There are various ways of getting around this. For now, we will
look at a simple approach.
Removing elements: a fix
package com.ianskenny.testdatastructures;
import java.util.ArrayList;
public class TestArrayList9 {
public static void main(String[] args) {
ArrayList<String> beatles = new ArrayList<String>();
String
String
String
String
s1
s2
s3
s4
=
=
=
=
"John Lennon";
"Paul McCartney";
"George Harrison";
"Pete Best";
beatles.add(s1); // element 0
beatles.add(s2); // element 1
beatles.add(s3); // etc.
beatles.add(s4);
ArrayList deleteList = new ArrayList();
for (String s: beatles) {
if (s.equals("Pete Best") || s.equals("John Lennon")) {
deleteList.add(s);
}
}
beatles.removeAll(deleteList);
for (String s: beatles) {
System.out.println(s);
}
}
}
Listing 12 : TestArrayList9.java