ADT: LINKED
LIST
TOPICS
· ADT: Linked List:
Definition, Operations, Examples
· ADT Unordered List
(Linked List Implementation)
· ADT Ordered List
(Linked List Implementation)
OUTLINE
· When we discussed the ADTs unsorted and sorted lists, we looked
at implementations using arrays. All the implementations discussed used a
built-in array stored in contiguous memory locations, implementing operations
to insert and delete by moving list items around in the array, as needed (shift
left or shift right). In general, array implementations of ADTs are not the
most efficient solutions when there is a high number of insertions and
deletions.
· Array limitations:
· The solution would be a dynamic data structure to ensure
that the collection could shrink or grow during program execution as needed (no
size limitations) and the data items don't need to be stored
contiguously in memory. A linked list is such a dynamic data structure =
better alternative to the built-in array implementation.
· The principal benefit of a linked list over a conventional
array is that the order of the linked items may be different from the order
that the data items are stored in memory or on disk. For that reason, linked
lists allow insertion and removal of nodes at any point in the list. On the
other hand, linked lists by themselves do not allow random access to the data,
or any form of efficient indexing. Thus, many basic operations (such as
obtaining the last node of the list, or finding a node that contains a given
data, or locating the place where a new node should be inserted) may require
going over most of the list elements (link list traversal).
· Definition: Linked
list = a collection of nodes, each containing at least one
member that gives the location of the next node in the list. In the simplest
case, each node has 2 members: a data member (the data value of the list
item) and a link member (a value locating the successor of this node).
The fact that the link member is present allows us to place individual nodes
anywhere in memory, not only in contiguous memory locations (as with arrays).
· List nodes can be
"linked" into chains to store a list of values. Each list node object
stores:
· one piece of (some
type) data
· a reference to
another list node
· NOTES:
· Definition: Linked
list traversal = stepping through the nodes of a linked list. Basic
operations of a linked list that require the link to be traversed; search,
insert, delete.
· NOTE: You should not traverse a
linked list using head (the list will be destroyed). Instead, use another
reference variable of the same type as head.
· Linked list traversal (Java code):
Node
current = head;
while (current != null){
//Do something - process
current
current = current.link;
}
· Example of linked list traversal:
display the data /in each node:
Node
current = head;
while (current != null){
System.out.println(current.info
+ " ");
current = current.link;
}
· Definition: Iterator = An object that allows a
client to traverse the elements of a collection, regardless of its
implementation. An iterator as an object that produces each element of a
collection one element at a time.
· Benefit: A common way to examine any collection's elements.
· An iterator remembers a position within a collection, and
allows you to:
· Some common iterator methods:
hasNext(): returns true if there
are more elements in the collection
next():
returns the next element from the collection (throws a NoSuchElementException if there are none left to
examine) - gives access to the next element in the list
remove():
removes from the collection the last value returned by next() (throws IllegalStateException
if you have not
called next() yet)
· Check these notes for some
linked list examples.
· The class LinkedListClass implements
the LinkedListADT interface. This
is an abstract class.
· Reminder: Abstract class = a hybrid between an
interface and a class. An abstract class defines a superclass type that can
contain method declarations (like an interface) and/or method bodies (like a
class).
· Like interfaces, abstract classes cannot be instantiated (cannot
use new to create any objects of their type).
· What goes in an abstract class?
· Structure of a linked list node:
· Definition: Nested class = A class defined inside of
another class. A nested class can be created as static (static nested classes)
or non-static (inner classes). Usefulness:
· Inner classes ensure increased encapsulation. They are hidden
from other classes (encapsulated); inner objects can access/modify the fields
of the outer object.
· Inner classes ensure the grouping of classes that are only used
in one place.
· Inner classes can lead to more readable and maintainable code.
· If an outer class declares a type parameter, inner classes can
also use that type parameter. The inner class should NOT redeclare the type
parameter. (If it does, it will create a second type parameter with the
same name.)
· The classes LinkedListNode
and LinkedListIterator
are inner
classes inside the LinkedListClass class.
· Definition of the LinkedListClass class:
public
abstract class LinkedListClass<T> implements LinkedListADT<T> {
//Place the
definition of the inner class LinkedListNode<T>
here.
//Place the
definition of the inner class LinkedListIterator<T>
here.
//Place the
definition of the LinkedListClass instance variables
here
//Place the
definition of the nonabstract methods here
//Place the
definition of the abstract methods here.
}
· LinkedListNode
class:
public
T info;
public LinkedListNode<T>
link;
public LinkedListNode();
public LinkedListNode(T
elem, LinkedListNode<T>
ptr);
public Object clone();
public String toString();
· Instance variables for LinkedListClass:
protected
LinkedListNode<T> first;//variable to store the address of the first node of the list
protected LinkedListNode<T>
last; //variable to store the address of the last
node of the list
protected int
count; //variable to store the number of nodes in the list
· Nonabstract methods:
public
LinkedListClass();
public boolean isEmptyList();
public void initializeList();
public void print();
public int length();
public T front
public T back();
public Object clone();
· Abstract methods (to be implemented
in the UnorderedLinkedList and OrderedLinkedList
classes):
public
abstract boolean search(T searchItem);
public abstract void insertFirst(T
newItem);
public abstract void insertLast(T
newItem);
public abstract void deleteNode(T
deleteItem);
· The LinkedListClass has two derived classes: UnorderedLinkedList and OrderedLinkedList
· The (Java) implemetation:
//Interface: LinkedListADT
extends
//Class: Cloneable
public interface LinkedListADT<T>
extends Cloneable {
public boolean isEmptyList(); //Method to determine whether the list is empty.
public void initializeList();
//Method to initialize the list to an empty state.
public void
print();
//Method to output the data contained in each node.
public Object
clone();
//Returns a copy of objects data in store (shallow
copy)
public int
length();
//Method to return the number of nodes in the list.
public T
front();
//Method to return a reference to the first node
public T
back();
//Method to return a reference to the last node
public boolean
search(T searchItem); //Method
to determine whether searchItem is in the list.
public void insertFirst(T
newItem); //Method
to insert newItem as the first item in the list.
public void insertLast(T
newItem); //Method
to insert newItem at the end of the list.
public void deleteNode(T
deleteItem);//Method to
delete deleteItem from the list.
}
//Class:
LinkedListClass implements
//Interface:
LinkedListADT
import java.util.*;
public abstract class LinkedListClass<T> implements LinkedListADT<T>
{
protected class LinkedListNode<T> implements Cloneable {
public T info;
public LinkedListNode<T> link;
//Default constructor
public LinkedListNode() {
info = null;
link = null;
}
//Alternate constructor
public LinkedListNode(T elem, LinkedListNode<T>
ptr) {
info = elem;
link = ptr;
}
public Object clone() {
LinkedListNode<T> copy = null;
try {
copy = (LinkedListNode<T>) super.clone();
}
catch (CloneNotSupportedException e) {
return null;
}
return copy;
}
public String toString() {
return info.toString();
}
} //end class LinkedListNode
//Instance variables of the class LinkedListClass
protected LinkedListNode<T> first;//address of the first node/list
protected LinkedListNode<T> last; //address of the last node/list
protected int
count; //number of nodes in the list
//Default constructor
public LinkedListClass() {
first = null;
last = null;
count = 0;
}
public boolean isEmptyList()
{
return (first == null);
}
public void initializeList() {
first = null;
last = null;
count = 0;
}
public void print() {
LinkedListNode<T> current; //variable to
traverse the list
current = first;
while (current != null) {//while more data to print
System.out.print(current.info + " ");
current = current.link;
}
}
public int length() {
return count;
}
public T front() {
return first.info;
}
public T back() {
return last.info;
}
public Object clone() {
LinkedListClass<T> copy = null;
try {
copy = (LinkedListClass<T>) super.clone();
}
catch (CloneNotSupportedException e){
return null;
}
//If the list is not empty clone each node of the list.
if (first != null) {
//Clone the first node
copy.first = (LinkedListNode<T>)
first.clone();
copy.last = copy.first;
LinkedListNode<T> current;
if (first != null)
current = first.link;
else
current = null;
//Clone the remaining nodes of the list
while (current != null) {
copy.last.link = (LinkedListNode<T>)
current.clone();
copy.last = copy.last.link;
current = current.link;
}
}
return copy;
}
//abstract methods
public abstract boolean
search(T searchItem);
public abstract void insertFirst(T
newItem);
public abstract void insertLast(T newItem);
public abstract void deleteNode(T deleteItem);
}
· The implemenation of a UnorderedLinkedList
class extends the abstract class LinkedListClass
(which implements the LinkedListADT interface
previously discussed) --> we need to implement a constructor, and the
abstract methods:
public abstract boolean
search(T searchItem);
public abstract void insertFirst(T
newItem);
public abstract void insertLast(T
newItem);
public abstract void deleteNode(T
deleteItem);
Method search:
In the array-based implementation for the unordered list we used the linear
search algorithm similar approach with the linked list implementation.
Methods insertFirst
and insertLast
insert a new node holding the item at the beginning and at the end of the
linked list. Since the list is unordered, the item to be inserted can be
inserted wherever we choose, and we choose the easiest locations: at the front
or at the end.
Method deleteNode:
To delete an item in a unordered linked list:
· The (Java) implemetation:
//Class: UnorderedLinkedList
extends
//Class: LinkedListClass
public class UnorderedLinkedList<T>
extends LinkedListClass<T> {
//Default constructor
public UnorderedLinkedList()
{
super();
}
public boolean search(T searchItem) {
LinkedListNode<T> current; //variable to traverse the list
current = first;
while (current != null)
if (current.info.equals(searchItem))
return true;
else
current = current.link;
return false;
}
public void insertFirst(T newItem) {
LinkedListNode<T> newNode;
//variable to create the new node
//create and insert newNode before first
newNode = new LinkedListNode<T>(newItem, first);
first = newNode;
if (last == null)
last = newNode;
count++;
}
public void insertLast(T newItem) {
LinkedListNode newNode; //variable to create the new node
//create newNode
newNode = new LinkedListNode(newItem, null);
if (first == null) {
first = newNode;
last = newNode;
}
else {
last.link = newNode;
last = newNode;
}
count++;
}
public void deleteNode(T deleteItem)
{
LinkedListNode<T> current; //variable to traverse the list
LinkedListNode<T> trailCurrent;
//variable just before current
boolean found;
//Case 1; the list is empty
if ( first == null)
System.err.println("Cannot delete from an empty
list.");
else {
//Case 2: the node to be deleted is first
if (first.info.equals(deleteItem))
{
first = first.link;
if (first == null) //the list had only one
node
last = null;
count--;
}
else { //search the list for the given info
found = false;
trailCurrent = first; //trailCurrent points to first node
current = first.link; //current
points to second node
while (current != null && !found) {
if (current.info.equals(deleteItem))
found = true;
else {
trailCurrent = current;
current = current.link;
}
}
//Case 3; if found, delete the node
if (found) {
count--;
trailCurrent.link = current.link;
if (last == current) //node to be deleted was
the last node
last = trailCurrent;
}
else
System.out.println("Item to be deleted is not in
the list.");
}
}
}
}
//Class: ClientUnorderedLinkedListInt
import java.util.*;
public class ClientUnorderedLinkedListInt
{
static Scanner
input = new Scanner(System.in);
public static void
main(String[] args) {
UnorderedLinkedList<Integer>
intList = new UnorderedLinkedList<Integer>();
UnorderedLinkedList
tempList;
Integer num;
System.out.println("Enter integers (999 to stop)");
num
= input.nextInt();
while (!num.equals(999)) {
intList.insertLast((Integer)
num);
num = input.nextInt(); //getInt()?
}
System.out.println("\nTesting .insertLast. The original list is: ");
intList.print();
System.out.println("\nTesting .length. The
length of the original list is: " + intList.length());
if (!intList.isEmptyList()) {
System.out.println("Testing
.front. First element/original list: " + intList.front());
System.out.println("Testing
.back. Last element/original list: " + intList.back());
}
tempList
= (UnorderedLinkedList<Integer>) intList.clone();
System.out.println("Testing .clone. The copy list is: ");
tempList.print();
System.out.println("\nTesting .length. The
length of the copy list is: " + tempList.length());
System.out.print("Testing .search. Enter the number to search
for/original list: ");
num
= input.nextInt();//getInt()?
if (intList.search(num))
System.out.println(num + " found in original
list.");
else
System.out.println(num + " is not in original list.");
System.out.print("Testing .remove. Enter the number to be deleted from
original list: ");
num
= input.nextInt(); //getInt()?
intList.deleteNode(num);
System.out.print("After deleting " + num
+ " the original list is: ");
intList.print();
System.out.println("\nAfter delete, the length
of the original list is: " + intList.length());
System.out.println("The original list is: ");
intList.print();
System.out.println("\nThe length of the
original list is: " + intList.length());
System.out.println("The copy list is: ");
tempList.print();
System.out.println("\nThe length of the copy
list is: " + tempList.length());
}
}
OUTPUT:
Enter integers (999 to
stop)
1 2 3 4 5 6 7 8 9 11 44 22 555 33 66 999
Testing
.insertLast. The original list is:
1
2 3 4 5 6 7 8 9 11 44 22 555 33 66
Testing
.length. The length of the original list is: 15
Testing
.front. First element/original list: 1
Testing
.back. Last element/original list: 66
Testing
.clone. The copy list is:
1
2 3 4 5 6 7 8 9 11 44 22 555 33 66
Testing
.length. The length of the copy list is: 15
Testing
.search. Enter the number to search for/original list: 333
333
is not in original list.
Testing
.remove. Enter the number to be deleted from original list: 22
After
deleting 22 the original list is: 1 2 3 4 5 6 7 8 9 11 44 555 33 66
After
delete, the length of the original list is: 14
The
original list is:
1
2 3 4 5 6 7 8 9 11 44 555 33 66
The
length of the original list is: 14
The
copy list is:
1
2 3 4 5 6 7 8 9 11 44 22 555 33 66
The
length of the copy list is: 15
· The implemenation of an OrderedLinkedList class extends the abstract
class LinkedListClass. The LinkedListClass and the LinkedListADT interface are the same as those
used in the implementation for the UnorderedLinkedList. à We need to implement a constructor, add a method to insert
in place and add the abstract methods:
public
abstract boolean search(T searchItem);
public abstract void insertFirst(T
newItem);
public abstract void insertLast(T
newItem);
public abstract void deleteNode(T
deleteItem);
· Method search: In the array-based implementation for the ordered list we
used the binary search algorithm - cannot be used with a linked list (Why?
Because you cannot get directly to the middle of the list, if no index
available.) To search the list for a particular item we must follow the links
down the list one by one, just like in the unordered linked list. However, this
approach can be improved à if the item is not in the
list, we can stop searching when the value in the node we are currently
examining is larger than the item we are searching for (Why? Because the list
is sorted, we know that the rest of the values are larger still, and cannot
possibly match the search item)
· Method insert: Inserting in an ordered
linked list is more complicated than what we have done so far because we have
to handle more special cases. Note: In the array-based implementation for the
ordered list we found first the location for the new item; next, we had to
shift right all the elements to make room for the new item. With the linked
list approach we don’t have to shift any elements. To insert an item in an
ordered linked list
· Methods insertFirst and insertLast don’t make much sense for
the ordered list à they just make calls to insert to insert in place (to keep
the list ordered)
· Method deleteNode: To delete an item in an
ordered linked list:
· The (Java) implemetation:
//Class: OrderedLinkedList
extends
//Class: LinkedListClass
public class OrderedLinkedList<T>
extends LinkedListClass<T> {
//Default constructor
public OrderedLinkedList()
{
super();
}
public boolean search(T searchItem)
{
LinkedListNode<T> current; //variable to traverse the list
boolean found;
current = first; //set current to point to
the first node in the list
found = false;
while (current != null && !found ) {
Comparable<T> temp = (Comparable<T>) current.info;
if (temp.compareTo(searchItem)
>= 0)
found = true;
else
current = current.link; //make
current point to the next node
}
if (found)
found = current.info.equals(searchItem);
return found;
}
public void insert(T insertItem) {
LinkedListNode<T> current; //variable to traverse the list
LinkedListNode<T> trailCurrent;
//variable just before current
LinkedListNode<T> newNode;
//variable to create a node
boolean found;
newNode = new LinkedListNode<T>(insertItem, null); //create the
node
//Case 1; the list is empty
if (first == null) {
first = newNode;
last = newNode;
count++;
}
else {
trailCurrent = first;
current = first;
found = false;
while (current != null && !found) {//search
the list
Comparable<T> temp = (Comparable<T>) current.info;
if (temp.compareTo(insertItem)
>= 0)
found = true;
else {
trailCurrent = current;
current = current.link;
}
}
//Case 2
if (current == first) {
newNode.link = first;
first = newNode;
count++;
}
//Case 3
else {
trailCurrent.link = newNode;
newNode.link = current;
if (current == null)
last = newNode;
count++;
}
}
}
public void insertFirst(T newItem) {
//the list is sorted - will call insert!
insert(newItem);
}
public void insertLast(T newItem) {
//the list is sorted - will call insert!
insert(newItem);
}
public void deleteNode(T deleteItem)
{
LinkedListNode<T>
current; //variable
to traverse the list
LinkedListNode<T> trailCurrent;
//variable just before current
boolean found;
//list is empty.
if (first == null)
System.err.println("Cannot delete from an empty
list.");
else {
if (first.info.equals(deleteItem))
{
first = first.link;
if (first == null)
last = null;
count--;
}
else { //search the list for the node with the
given info
found = false;
trailCurrent = first; //trailCurrent points to the first node
current = first.link; //current
points to the second node
while (current != null && !found) {
Comparable<T> temp = (Comparable<T>) current.info;
if (temp.compareTo(deleteItem)
>= 0)
found = true;
else {
trailCurrent = current;
current = current.link;
}
}
if (current == null)
System.out.println("Item to be deleted is not in
the list.");
else
if (current.info.equals(deleteItem))
{ //item to be deleted is in the list
if (first == current) {
first = first.link;
if (first == null)
last = null;
count--;
}
else {
trailCurrent.link = current.link;
if (current == last)
last = trailCurrent;
count--;
}
}
else
System.out.println("Item to be deleted is not in
the list.");
}
}
}
}
//Class:
ClientOrderedLinkedListInt
import java.util.*;
public class ClientOrderedLinkedListInt
{
static Scanner
input = new Scanner(System.in);
public static void
main(String[] args) {
OrderedLinkedList<Integer>
intList = new OrderedLinkedList<Integer>();
OrderedLinkedList
tempList;
Integer num;
System.out.println("Enter integers (999 to stop)");
num
= input.nextInt();
while (!num.equals(999)) {
intList.insert((Integer) num);
num = input.nextInt();//getInt()?
}
System.out.println("\nTesting .insert. The
original list is: ");
intList.print();
System.out.println("\nThe length of the
original list is: " + intList.length());
if (!intList.isEmptyList()) {
System.out.println("\nTesting .front. First element/original list: " + intList.front());
System.out.println("Testing
.back. Last element/original list: " + intList.back());
}
tempList
= (OrderedLinkedList<Integer>) intList.clone();
System.out.println("Testing .clone. The copy list is: ");
tempList.print();
System.out.println("\nThe length of the copy
list is: " + tempList.length());
System.out.print("Testing .search. Enter the number to search
for/original list: ");
num
= input.nextInt();//getInt()?
if (intList.search(num))
System.out.println(num + " found in original list.");
else
System.out.println(num + " is not in original list.");
System.out.println("Testing shallow copy/deep copy. Delete from original
list. What about the clone? ");
System.out.print("Enter the number to be deleted from original list:
");
num
= input.nextInt();//getInt()?
intList.deleteNode(num);
System.out.println("\nAfter deleting " + num + " the original list is: ");
intList.print();
System.out.println("\nThe new length of the
original list is: " + intList.length());
System.out.println("The copy list is: ");
tempList.print();
System.out.println("\nThe length of the copy
list is: " + tempList.length());
}
}
OUTPUT:
Enter integers (999 to
stop)
9
8 7 6 5 4 3 2 1 99 88 44 55 11 33 77 66 999
Testing
.insert. The original list is:
1
2 3 4 5 6 7 8 9 11 33 44 55 66 77 88 99
The
length of the original list is: 17
Testing
.front. First element/original list: 1
Testing
.back. Last element/original list: 99
Testing
.clone. The copy list is:
1
2 3 4 5 6 7 8 9 11 33 44 55 66 77 88 99
The
length of the copy list is: 17
Testing
.search. Enter the number to search for/original list: 55
55
found in original list.
Testing
shallow copy/deep copy. Delete from original list. What about the clone?
Enter
the number to be deleted from original list: 44
After
deleting 44 the original list is:
1
2 3 4 5 6 7 8 9 11 33 55 66 77 88 99
The
new length of the original list is: 16
The
copy list is:
1
2 3 4 5 6 7 8 9 11 33 44 55 66 77 88 99
The
length of the copy list is: 17
Key Terms:
Abstract class: A hybrid between an
interface and a class, created with the abstract reserved word.
Circular linked list: A linked list
in which the last node points to the first node.
Doubly linked list: A linked list in which
every node has a next pointer and a back pointer.
Head (first): A reference variable
that stores the address of the first node in a list.
Inner class: A non-static nested
class.
Link: The component of a node that
stores the address of the next node in a list.
Linked list: A collection of
components, called nodes.
Nested class: A class defined within
a class.
Node: A data structure that has two
components: info and link.
Additional
Resources:
1. (Oracle) The Java Tutorials, Nested classes: : http://java.sun.com/docs/books/tutorial/java/IandI/abstract.html
2. (Oracle) The Java Tutorials, Abstract methods and classes: http://java.sun.com/docs/books/tutorial/java/javaOO/nested.html
3. Linked List: http://en.wikipedia.org/wiki/Linked_list
4. Iterators: http://en.wikipedia.org/wiki/Iterators
References:
[1] Java Programming: From Problem Analysis to Program Design, by D.S. Malik,
Thomson Course Technology, 2008
[2] Building Java Programs: A Back to Basics Approach, by Stuart Reges, and Marty Stepp, Addison
Wesley, 2008.