Text33 LinkedLists1
Text33 LinkedLists1
Linked Lists I
Chapter XXXIII Topics
33.1 Introduction
33.2 Review of the LinkedList Class
33.3 Multiple Queue Implementations
33.4 Pre-OOP ListNode Class
33.5 OOP ListNode Class
33.6 Loops and Linked Lists
33.7 Considering Cases
33.8 An Ordered Linked List
33.9 Linked Lists and Memory
33.10 The GfxNode Class
33.11 Practice Exercises
33.12 Summary
The Linked list must be an important data structure. You are looking at a chapter
titled Linked List I, which will be immediately followed by Linked List II. Any
topic that gets two chapters exclusively devoted to itself must be a big deal. Yes,
linked lists are very powerful, very flexible and thus very important. Why the big
emphasis on linked lists? Let us investigate the array data structure and see any
potential weaknesses that must be addressed.
We can start with the static array. A Java static array allocates memory once and
the array is stuck with its selected memory block size. If the array is too small, it
is too bad, because you will run out of space to add any additional elements. If
the array is too big, you can add all the elements that you desire, but this is done
at a considerable penalty in using memory space. Look at a multiplex movie
theater and you will see sixteen theaters of varying sizes to fit the demand of a
particular movie. Imagine that it is a requirement that all theaters are the same
size, which is the case with a static array. If you select sixteen small theaters, you
will efficiently handle small crowds for unpopular movies and simultaneously
display sold out signs for new blockbuster movies. You may be concerned about
turning away customers, so you decide to build sixteen large theaters. Now you
can handle any crowd, but you are paying for the construction and air-
conditioning of huge theaters that are almost empty for many movies. It should
make sense that the multi-size theater is the best solution for a multiplex theater
situation.
This is a great solution, but the Java static array allows no such option. You
decide on the number of array elements and there are no changes allowed after
the array object is constructed. Good, bad or just right, you are stuck with your
size decision. I know that many of you clever students already know the solution.
Forget the Java static array and switch over to ArrayList, which is Java's own
solution to allow dynamic resizing during program execution.
This is an excellent idea and yes it is possible to create an ArrayList object and
then happily and merrily alters its size as demands increase or decrease. It seems
like a perfect solution. Why even ponder over any other possibilities? Frankly
you are not totally out off the woods with the use of ArrayList, which will make
sense if you understand the manner in which ArrayList handles its resizing
needs.
I will tell you a secret. The ArrayList object is not really doing much resizing.
Every object is a contiguous block in memory. If more space is needed, then a
new block is allocated, data is transferred from the old block to the new block and
the old block is returned to memory. In other words, there is a considerable
amount of processing that is happening in the background to make resizing
ArrayList Warning
It is precisely for the situations where execution processes become noticeable that
the linked list data structure takes front center and offers a solution. Forget the
requirement to store all the data in one contiguous block. This can be slow and
worse, it can even be impossible if too large a block is requested. Your program
needs to store and process lots of data and you care little how and where this data
is stored. The computer has chunks of memory all over the place. There is no
problem storing elements in many separate blocks if there is some way to connect
these blocks. You may guess where this is going? Blocks of information are
connected with links and the linked list data structure is born. In this chapter we
will start by reviewing the Java LinkedList class. The LinkedList class was
introduced with the other Collection classes along with a brief introduction to
linked lists. The power, flexibility and capabilities of a linked list were not
explored in the Collection chapter. This chapter and the next chapter will emerge
you in the virtues of the linked list data structure and truth be told, you may soon
find yourself overly emerged. You will learn that the Java LinkedList class is
nice, but it has limitations.
The LinkedList class has access to various methods that start with the Collection
interface and continues with the List subinterface. These methods allow adding
new elements, checking for membership, removing elements and altering
elements. It is possible with the add method and the set method to specify a
specific index of an object for access. This makes perfect sense for an ArrayList
object, but a LinkedList object has access to the same methods and it makes for
a slightly peculiar LinkedList implementation. Normally, we do not think about
indexed access with a linked list data structure. Therefore this section will focus
on the methods that are unique to the LinkedList class. These methods allow
access to the first node or the last node of the data structure, which is a traditional
access of a linked list data structure. Program Java3301.java, in figure 33.1,
reviews the addFirst, addLast, getFirst and getLast methods.
Figure 33.1
// Java3301.java
// This program reviews the <LinkedList> class with methods <addFirst>, <addLast>, <getFirst> and <getLast>.
import java.util.LinkedList;
John
Heidi
Figure 33.2
// Java3302.java
// This program creates a linked list with four nodes and displays each node
// starting with the first node to the last node using the <getFirst> and <removeFirst> methods.
import java.util.LinkedList;
Java3302.java Output
JAVA3302.JAVA
John
Greg
Maria
Heidi
Figure 33.3
// Java3303.java
// This program creates a linked list with four nodes and displays each node
// starting with the last node to the first node using the <getLast> and
// <removeLast> methods.
import java.util.LinkedList;
Java3303.java Output
JAVA3303.JAVA
Heidi
Maria
Greg
John
data.addFirst(value);
data.addLast(value);
You have seen two approaches to display the elements of a linked list and frankly,
both methods are quite sad. Anytime you destroy a structure to see its contents,
you are looking at a poorly designed program segment. Imagine that you wish to
determine every student in your school by lining the students up and recording
their names as you kick them out off school, just to have access to the next person
in line. A little strange, is it not?
Well not to worry, because Java has these nifty Iterator and ListIterator classes.
The ListIterator class has the methods available in the Iterator class and then
adds some special methods to make linked list processing simpler. The next two
programs use the ListIterator class, but you could substitute the Iterator class
and get the same result. A later program will demonstrate some unique
ListIterator methods. Program Java3304.java, in figure 33.4, demonstrates the
use of the next method.
Keep in mind that iterator is a noun created from the verb iterate, which means to
repeat. This makes iterator a repeater. Picture an iterator as an office aid who
has to deliver messages to different rooms. The iterator stands in front of the first
room and waits. A command is issued to the information stored in that room.
Now here is the key to this business. The iterator is not in charge of information
display. It just stands in front of the room that may require processing. The next
method processes the program statement for the immediate room and then moves
on to the next room. In truth next is a return method, which returns information
in the room.
Figure 33.4
// Java3304.java
import java.util.LinkedList;
import java.util.ListIterator;
family.addFirst("John");
family.addLast("Greg");
family.addLast("Maria");
family.addLast("Heidi");
Java3304.java Output
JAVA3304.JAVA
John
Greg
Maria
Heidi
Method next moves the iterator to the next element, and then
returns it.
Program Java3304.java takes the attitude that somehow the number of nodes in
the linked list is known. This is hardly logical. The whole point of using a linked
list is for the efficient convenience of constantly changing the size of the data
structure during program execution. This means that a fixed loop makes no sense
with a linked list. Program Java3305.java, in figure 33.5, uses the practical
hasNext method in a conditional loop. Iteration continues as long as hasNext is
true. This is really the only sensible way to work with linked lists.
Figure 33.5
// Java3305.java
// This program demonstrates how to traverse a linked list until the
// end is found, using the <hasNext> method.
import java.util.LinkedList;
import java.util.ListIterator;
family.addFirst("John");
family.addLast("Greg");
family.addLast("Maria");
family.addLast("Heidi");
JAVA3305.JAVA
John
Greg
Maria
Heidi
while (iter.hasNext())
The remove method of the Iterator and ListIterator classes was not shown in
any review program. Method remove is detailed in a highlight window to make
the method review section complete.
iter.remove();
Program Java3306.java, in figure 33.6, reviews the add and set methods. Be
careful with this program example, because you may get fooled. You already
know the add method. It is one of the Collection methods, which adds new
elements to a Collection object. Do not get confused because there is quite a
difference between list.add("Name"); and iter.add("Name");. The first add is
called by the list object and the second add method is called by the iter object.
Same method identifier, but they come from two totally different classes.
Figure 33.6
// Java3306.java
// This program demonstrates how to use the <ListIterator> class to access
// elements in a <LinkedList> object. The <ListIterator> adds the <add>
// and <set> method to the three <Iterator> methods.
import java.util.*;
Java3306.java Output
JAVA3306.JAVA
[9999, 1111, 9999, 1111, 9999, 1111, 9999, 1111, 9999, 1111]
iter.set(new Integer(9999));
Several chapters back you learned how to implement a queue data structure. The
choices at that stage were limited. We wanted to use some type of dynamic
structure that would grow and shrink with calls to enQueue and deQueue. The
choice was pretty much limited to ArrayList, since it was the only dynamic data
structure in our programming tool bag. The ArrayList class did an outstanding
job for us and we were very pleased with our queue implementation. Program
Java3307.java, in figure 33.7, reviews the queue implementation with the help of
an ArrayList object.
Figure 33.7
// Java3307.java
// This program reviews implementing a queue with the <ArrayList> class.
import java.util.ArrayList;
students.enQueue("Luke Watts");
students.enQueue("Brian Sims");
students.enQueue("Mike Lewis");
students.enQueue("Jamie Singbush");
System.out.println("There are " + students.getSize() + " students stored on the queue");
System.out.println();
if (students.isEmpty())
System.out.println("The queue is empty");
else
System.out.println("Queue front contains " + students.peekFront());
System.out.println();
while (!students.isEmpty())
{
String student = (String) students.deQueue();
System.out.println(student);
}
System.out.println();
}
}
class MyQueue
{
public MyQueue()
// Initializes an empty array object with references of private variable data objects.
{
data = new ArrayList();
front = 0;
}
JAVA3307.JAVA
Luke Watts
Brian Sims
Mike Lewis
Jamie Singbush
Each one of the MyQueue methods uses a simple one-line statement. You want
to deQueue? This means you need access the front of the queue, well use
removeFirst. You want to enQueue? That means you need access the end of
the queue, then use addLast. Oh, and if you want only to take a look at the front
element with peekFront, then getFirst is your choice.
It may help to pull the ArrayList implementation of the queue and the
LinkedList implementation into JCreator with two separate vertical windows.
Compare them side-by-side and you may understand better what my point is.
Both implementations do work, but the LinkedList version is shorter, cleaner and
more readable. If such a solution is available, use it.
Figure 33.8
// Java3308.java
import java.util.LinkedList;
students.enQueue("Luke Watts");
students.enQueue("Brian Sims");
students.enQueue("Mike Lewis");
students.enQueue("Jamie Singbush");
System.out.println("There are " + students.getSize() + " students stored on the queue");
System.out.println();
if (students.isEmpty())
System.out.println("The queue is empty");
else
System.out.println("Queue front contains " + students.peekFront());
System.out.println();
while (!students.isEmpty())
{
String student = (String) students.deQueue();
System.out.println(student);
}
System.out.println();
}
}
class MyQueue
{
public MyQueue()
// Initializes an empty array object with references of private variable data objects.
{
data = new LinkedList();
}
JAVA3308JAVA
Luke Watts
Brian Sims
Mike Lewis
Jamie Singbush
You will now make a major shift. Forget that you just learned a variety of
LinkedList tricks. Just imagine that there is a need for a linked list data structure
and you need to implement such a structure in some fashion without any special
classes. In other words, there are no shortcuts unless you create them first.
Right now we will not be concerned with complexities of inserting and deleting
nodes in the middle of a linked list. The simplest way to learn about handling
links is to concentrate on linking at one end of a linked list. The end result of
building a list at one end only is that the list behaves like a stack. However, the
motivation is to learn the easiest type of linked list implementation first, and this
just happens to be a stack.
The secret of implementing a linked list revolves around a rather peculiar looking
data structure. Each node in a linked list stores data as well as information about
This brings up a curious problem. Each node in the linked list will then contain a
field, which is a reference to another node. But the pointer is inside the very
structure that it references. The solution is to use a self-referencing declaration
like the one shown in figure 33.9.
Figure 33.9
class ListNode
{
public Object value;
public ListNode next;
}
ListNode is a short, peculiar class with two fields. There are no constructors and
there are no methods in sight. Keep in mind that this is the pre-OOP approach.
The first field, value, stores the necessary data information. The second field,
next, is a reference and notice that this is a reference of the ListNode class.
Normally, it is not possible to make a reference to anything that is not yet
completely declared. This is allowed in the case of making a reference to some
memory location that will be allocated during program execution.
class ListNode
{
public Object value;
public ListNode next;
}
This is the type of stuff that often causes major confusion. The only reason why
this self-referential stuff is included is for multiple reading purposes. After you
look at a variety of program examples that use this type of structure, you will see
It is also important to realize that ListNode, value, and next are not special Java
keywords at all. Figure 33.10 shows the exact same functionality with the Tiger
class declaration.
Figure 33.10
class Tiger
{
public Object book;
public Tiger giraffe;
}
The first linked list program example will create a small linked list with only
three nodes. Strings are stored as data in the linked list besides the linking
information. Graphically, the linked list looks like figure 33.11
Figure 33.11
David Greg John
The diagonal line in the picture indicates the null pointer or address. It is used to
indicate the end of the list. null is a reference, but it does not reference any
actual memory address. Its only purpose in life is to help identify the end of a
list. The value of null is zero (0). Program Java3309.java, in figure 33.12
shows the syntax of this first program. Every program statement in this example
will be explained in detail following the program.
Figure 33.12
// Java3309.java
// This program demonstrates creating a linked list in an old-fashioned pre-oop
// style that uses a poorly designed <ListNode> class.
p = new ListNode();
p.value = "John";
p.next = temp;
temp = p;
p = new ListNode();
p.value = "Greg";
p.next = temp;
temp = p;
p = new ListNode();
p.value = "David";
p.next = temp;
temp = p;
while (p != null)
{
System.out.println(p.value);
p = p.next;
}
System.out.println();
}
class ListNode
{
public Object value;
public ListNode next;
}
Java3309.java Output
JAVA3309.JAVA
David
Greg
John
ListNode p; // # 01
ListNode temp = null; // # 02
Lines 01 and 02 declare two ListNode variables.
p = new ListNode(); // # 03
Line 03 constructs a ListNode object. Data fields do not have any useful values.
p.value = "John"; // # 04
p.next = temp; // # 05
temp = p; // # 06
Line 04 assigns the string "John" to the value data field.
Line 05 assigns temp's value, which is null, to the next data field.
Line 06 assigns p's value to temp. Both p and temp reference the same address.
p = new ListNode(); // # 07
p.value = "Greg"; // # 08
Line 07 uses p to construct another ListNode object.
Line 08 assigns the string "Greg" to the value data field.
p.next = temp; // # 09
temp = p; // # 10
Line 09 is very significant. temp references the first node created and p
references the second node. The next field of p links the two nodes.
After temp secures a link between the two nodes, temp moves to p.
p = new ListNode(); // # 11
p.value = "David"; // # 12
p.next = temp; // # 13
temp = p; // # 14
When you looked at earlier programs that used the LinkedList class, you had
little control over the manner in which the list elements linked together. The last
program, with the pre-OOP ListNode class linked three nodes together in a LIFO
sequence or a stack. It could also have been linked as a FIFO or queue and the
linking could be done such that new nodes are inserted to maintain a certain
desired order. There is a reason for starting with a stack. The LIFO sequence,
which means a single end access, simplifies the processing for any linked
structure. A linked list data structure is not concerned with the arrangements of
its nodes. As long as each node has the ability to access the next node and you
have a means to identify the beginning and end of the list, you are functional.
Figure 33.13
// Proper OOP ListNode class declaration.
class ListNode
{
It is easier to understand the nature of the new ListNode class, when it is used in
a program example. Program Java3310.java, in figure 33.14, uses the new class
and links four nodes in a stack sequence, and then displays the stored names.
Figure 33.14
// Java3310.java
// This program demonstrates how to create a linked list of four nodes with
// a well-designed <ListNode> class. This linked list behaves like a stack.
ListNode p = null;
ListNode temp = null;
while (p != null)
{
System.out.println(p.getValue());
p = p.getNext();
}
class ListNode
{
public ListNode (Object initValue, ListNode initNext)
{
value = initValue;
next = initNext;
}
JAVA3310.JAVA
Diana
Heidi
Maria
Isolde
How does the new class manage to perform the same linked processes as its
predecessor? Compare the program statements of the last two programs. You will
see that the same exact steps that were shown in the previous program are present
here. The key difference is that several statements of the pre-OOP style are now
consolidated in a single program statement.
ListNode p = null; // # 1
ListNode temp = null; // # 2
Lines 01 and 02 declare two ListNode variables.
So far this is identical to the previous program
You should observe that more variables are used and also more program
statements. A stack builds new nodes at the same location where the stack
removes elements. A queue builds new nodes at one end and removes nodes at
another end. This type of structure will require an additional reference that keeps
track of the front of the list for node removal.
Figure 33.15
// Java3311.java
// This program demonstrates how to create a linked list of four nodes with
// a well-designed <ListNode> class. This linked list behaves like a queue.
ListNode p = null;
ListNode front = null;
ListNode temp = null;
p = front;
while (p != null)
{
System.out.println(p.getValue());
p = p.getNext();
}
System.out.println();
}
class ListNode
{
public ListNode (Object initValue, ListNode initNext)
{
value = initValue;
next = initNext;
}
Isolde
Maria
Heidi
Diana
It is really important to understand why two nodes link as a stack and why the
same nodes also manage to link as a queue. Two sets of statements will be shown
in figure 33.16, to help clarify the difference.
Figure shows the creation of a linked list with three nodes. Two linked lists are
shown and each one has a sequence of three characters, [ X, Y, Z] stored in the
data field. Notice the difference in the linking arrows.
Figure 33.17
X Y Z [top] (stack)
(queue) [front] X Y Z
The number of statements required to construct, and link a node in a linked list, is
not very excessive. If the sequence needs to be a queue there will be some extra
In the case of a stack there are only two statements required. The first statement
constructs a node, enters information for the data field and assigns a value to the
linking field so that it connects to the previous node. Any extra nodes will follow
this same pattern. Program Java3312.java, in figure 33.18, uses a fixed loop to
enter a set of integers in a linked list. Note that two ListNode variables are
declared prior to the loop structure.
Figure 33.18
// Java3312.java
// This program demonstrates how to create a linked list of integers.
// The linked list is created like a stack.
ListNode p = null;
ListNode temp = null;
while (p != null)
{
System.out.print(p.getValue() + " ");
p = p.getNext();
}
System.out.println("\n\n");
}
class ListNode
{
public ListNode (Object initValue, ListNode initNext)
{
value = initValue;
next = initNext;
}
JAVA3312.JAVA
109 108 107 106 105 104 103 102 101 100
You must be careful if you write a program to create a linked list as a queue with
the logic of the previous program. The front reference of a queue should not be
moved inside the loop structure. Your structure will have a serious access
problem if the front reference moves from node to node. front should be
anchored to the first node that is created and not move unless the first node is
removed.
The solution to this dilemma is not too difficult. Start by creating the very first
node prior to any loop structure. Create the node, assign its data value and
reference null for the next field. Makes sure that the front reference accesses
this first node. Once the node is constructed, you are ready to start a loop
structure to complete the building of the linked list. Program Java3313.java, in
figure 33.19, creates a linked list in a queue sequence.
Figure 33.19
// Java3313.java
// This program demonstrates how to create a linked list of integers.
// The linked list is created like a queue.
ListNode p = null;
ListNode temp = null;
ListNode front = null;
p = front;
while (p != null)
{
System.out.print(p.getValue() + " ");
p = p.getNext();
}
System.out.println("\n\n");
}
class ListNode
{
public ListNode (Object initValue, ListNode initNext)
{
value = initValue;
next = initNext;
}
JAVA3313.JAVA
100 101 102 103 104 105 106 107 108 109
All linked list examples up to this point have worked with stacks and queues.
Access to a stack and a queue is always at the end of a linked list and this type of
access simplifies a program. What happens if a node needs to be deleted in a
linked list? I mean a node, with a specified data field, that may be anywhere in
the linked list, or possibly not even exist. How is such a node deleted?
Linked lists can get you into very subtle trouble. Just when you start feeling
comfortable you may encounter some weird outputs for certain situations. The
nature of linked lists involves the consideration of all the possible cases that
might be encountered during some linked list process. This is a major big deal
and has a heavy impact on program reliability.
AP Examination Alert
I will start with a deletion program that appears correct, but fails because of some
subtle mistake. Program Java3314.java, in figure 33.20, demonstrates the
process that is necessary to delete nodes from a linked list. The program does a
good job testing the accuracy of the deleteNode method.
Figure 33.20
// Java3314.java
// This program demonstrates how to delete a node from a linked list.
// The <deleteNode> method of the <List> class does not work in all cases.
// For operating convenience the <ListNode> class uses the <int> type
// for its data <value> field.
class ListNode
{
public ListNode (int initValue, ListNode initNext)
{
value = initValue;
next = initNext;
}
class List
{
ListNode front;
int size;
public List(int n)
{
size = n;
ListNode temp, p;
front = new ListNode(1,null);
temp = front;
for (int k = 2; k <= size; k++)
{
p = new ListNode(k,null);
Java3314.java Output
JAVA3314.JAVA
1 2 3 4 5 6 7 8 9 10
1 2 3 4 6 7 8 9 10
Exception in thread "main" java.lang.NullPointerException
at List.deleteNode(Java3313.java:94)
at Java3313.main(Java3313.java:18)
The program does have correct syntax. It must compile because there is output.
You see a display of the linked list before the first deletion and a display that
proves that the middle number 5 is deleted. After that, a bunch of runtime error
message start with the infamous NullPointerException error. Usually, that error
indicates that an attempt is made to dereference the null value. A reference to a
Figure 33.21
// Java3315.java
// This program correctly implements the <deleteNode> method by considering all the possible delete cases.
class ListNode
{
public ListNode (int initValue, ListNode initNext)
{
value = initValue;
next = initNext;
}
public int getValue () { return value; }
public ListNode getNext () { return next; }
public void setValue (int theNewValue) { value = theNewValue; }
public void setNext (ListNode theNewNext) { next = theNewNext; }
private int value;
private ListNode next;
}
class List
{
ListNode front;
int size;
public List(int n)
{
size = n;
ListNode temp, p;
front = new ListNode(1,null);
temp = front;
for (int k = 2; k <= size; k++)
{
p = new ListNode(k,null);
JAVA3315.JAVA
1 2 3 4 5 6 7 8 9 10
1 2 3 4 6 7 8 9 10
2 3 4 6 7 8 9 10
2 3 4 6 7 8 9
List node value does not exist
The deleteNode method looks long and convoluted. Let us slowly start at the
beginning and build the method with each one of the cases that should be
considered. A good start is the consideration when a node needs to be deleted
from an empty list.
This simple, short question is forgotten so frequently. A method should not make
the assumption that a linked list exists. If front references null, then any process
on front will create a dereferencing null error. Figure 33.22 shows the first step
of the deleteNode method. Note that a local exists boolean variable is used. This
variable adds readability to the code in the method and will be used later in the
method.
Figure 33.22
public void deleteNode(int key)
{
boolean exists = false;
if (front == null)
{
exists = false;
}
}
You have passed the first test. The list does exist. Now you must continue and
carefully check conditions in such a way that you avoid the evil dereferencing
null error. The next logical test is to see if the very first node contains the key.
Keep the following in mind. A node that is deleted in the middle of the list
requires that the preceding node is linked to the succeeding node. If the very first
Now I know that some of you are clever and say, but what if the list has only one
node, then only one node needs to be deleted? You will see that it is the same
process as deleting the first node in a list. If a list has one node then the next
field of the only node is null. If we change first to the value of the next node, it
will be the second node if it exists and null otherwise. This is correct because
deleting a one-node situation should result in an empty list.
Figure 33.23
public void deleteNode(int key)
{
boolean exists = false;
if (front == null)
{
exists = false;
}
else
{
if (front.getValue() == key)
{
front = front.getNext();
exists = true;
}
We are making good progress. We have established if the list is empty, and if it
is not, we checked to see if the first node must be deleted. We have also learned
that deleting the first node in a one-node list requires an identical process as
deleting a node from a multi-node list. Now we must consider the case of a node
in the middle of a list. This situation requires some type of loop to iterate to
every node in the list. We also need to have a reference to the preceding node
and succeeding node. Figure 33.24 shows the code for the loop. temp2 is used
to trail temp1.
Figure 33.24
public void deleteNode(int key)
{
boolean exists = false;
if (front == null)
{
exists = false;
}
You might be confused how this code works to delete a middle node. Figure
33.25 shows an example of a list with characters stored in data field. The object
is to delete the node storing character K. A loop starts with temp1 leading the
search and temp2 follows one node behind temp1.
Figure 33.25
[temp2] [temp1]
A G K M T
[temp2] [temp1]
A G K M T
A G M T
CASE 5: You need to delete the last node.
Deleting the last node may seem like a separate case, just like the deletion of a
single-node linked list. You will find that it is not a special situation and is
handled in precisely the same manner as deleting a node from the middle of a list.
temp1 stops at the last node and temp2 at the second-to-last node. temp2 links
We are almost home free. References are placed at the desirable nodes and some
code is needed to perform the relinking process that was shown in figure 33.25.
A few more statements must be added and then the job is finished. Note in figure
33.26 that we must be careful to check if the node exists. It is quite possible that
the entire loop finished without finding the requested node. If such is the case, a
message is generated that the node could not be found, otherwise one statement
links two nodes around the deleted node and Java automatically returns the
memory space for future use.
Figure 33.26
if (exists)
{
temp2.setNext(temp1.getNext());
}
else
{
System.out.println("List node value does not exist");
}
In the previous section you learned to consider all possible cases when processing
linked lists. In truth the section strictly concentrated on all the possible cases that
may occur when a node needs to be deleted from a linked list. This chapter
started with so many examples that created lists as a stack or a queue that you
may wonder why there is the need to delete a node from somewhere in the middle
of a list. Now stacks and queues certainly have their place in computer science
and they are data structures with few complexities. The simplicity of stacks and
queues make them ideal examples. However, does it not seem more natural to
create a linked list that is ordered in some manner? The list can be ordered
alphabetically by name, numerically by account number, by age, by social
security number or any other order that is desired.
So how do you create an ordered linked list? This involves quite a bit more
processing than creating stacks and queues. A stack inserts a new node at the top
and a queue insert a new node at the end of the list. That is clean and simple, but
an ordered list requires that the desired insert location is known and such
knowledge requires considering various cases.
Figure 33.27
// Java3316.java
// This program demonstrates how to create an ordered list using the
// <ListNode> class with an <insert> method and considering all cases.
class ListNode
{
class List
{
ListNode front;
int size;
p = new ListNode(newValue,null);
if (front == null)
{
front = p;
}
else
{
if (p.getValue() < front.getValue())
{
p.setNext(front);
front = p;
}
else
{
t1 = front;
while (t1 != null && p.getValue() > t1.getValue())
{
t2 = t1;
t1 = t1.getNext();
}
t2.setNext(p);
p.setNext(t1);
}
}
}
JAVA3316.JAVA
Did you see the possible cases considered by the insertNode method? They are
similar, but not precisely the same as the cases considered for the deleteNode
class. One major difference is that it is always possible to insert a new node. It is
not always possible to delete a node, because the requested node must exist. With
that idea in mind see if you found the cases that are listed below
Consider the linked list diagram in figure 33.28. It is a terrific list with five
nodes. Each node has one field for character data and a second field to store the
reference linking to the next node in the list. front references the first node in the
linked list, which is ordered alphabetically.
Figure 33.28
[front] A G K M T
Now all this linked list stuff and diagrams with nodes and arrows is terrific, but
hopefully you do not expect to look inside the computer and find a bunch of
arrows that link different memory locations together. You have worked with
references before. A reference stores a memory address. So let’s get a little more
technical and represent the linked list in a manner that resembles computer reality
more closely.
The linked list diagram, with its arrows, is drawn again above the memory
segment diagram. This allows a clear comparison between the two types of
linked list representations.
Figure 33.29
@7b44 M
@7b94
@7b30 @7b34 @7b38 @7b3c @7b40 @7b44 @7b48 @7b4c
G A
@7b68 @7b30
@7b60 @7b64 @7b68 @7b6c @7b70 @7b74 @7b78 @7b7c
K
@7b1c
T
@0000
Let us step through this diagram and see if you can visualize the linked list that is
represented here. It is possible that many of you have little trouble with the
visualization because you look at the diagram at the top of the page.
This chapter will finish with a tool that will help to visualize the linking process.
I have created a GfxNode class that can draw the linked list diagrams. The
constructor creates a node and there are methods to draw linking arrows.
Program Java3317.java, in figure 33.30, demonstrates the use of this class. You
need to be aware that it does demonstrate how to use the GfxNode class, but it
draws a linked list incorrectly. This is done intentionally, because a lab exercise
at the conclusion of this chapter is devoted to the very process of drawing a
linked list correctly. I did not want to supply the answer to a lab exercise in a
convenient program example.
Figure 33.30
// Java3317.java
// This program demonstrates the use of the GfxNode class.
// The actual drawing does not represent any correct approach to
// creating a linked list.
import java.awt.*;
import java.awt.event.*;
node1.drawNull(g,9);
node1.drawLink(g,node2,0);
node2.drawNull(g,9);
node2.drawLink(g,node3,0);
node3.drawNull(g,9);
node3.drawLink(g,node4,0);
node4.drawNull(g,9);
node4.drawLink(g,node5,0);
node5.drawNull(g,9);
node5.drawLink(g,node6,0);
The best way to understand this class is by starting with a single node. Observe where
the node is placed on the screen and then change the parameters and see how the node
appearance changes. The only time that you are concerned with the location of a node
is during the construction stage. After a node is constructed, it knows it location and
arrows, as well as data, will automatically be drawn in the correct location.
public GfxNode(Graphics g, int tlx, int tly, char ltr, int clr, int dt)
// Method delay allows viewing the sequence in which the linked lists are drawn/
This chapter finishes with a set of exercises that uses a pictorial display of a linked
list in the same manner as the pictures created by the GfxNode class. Each time
you will be shown the same diagram of some initial linked list. This is followed by
a set of program statements and you select the appearance of the linked list after the
executions of the program statements are completed. The initial diagram is the
same for each exercise, but it is still displayed on each page to help visualize the
problem better. Assume that any variables used in the exercises have been declared
correctly and can be used in a logical manner. Furthermore, some of the variables
are not shown in the answer responses to avoid clutter. Everything that is necessary
to solve the problem is displayed.
class ListNode
{
public ListNode (char initValue, ListNode initNext)
{
value = initValue;
next = initNext;
}
Each exercise is shown on a separate page and the ListNode class will be
displayed on each page to assist in solving the problem. After some initial
practice, you will probably remember the logic of the ListNode class and its
methods without needing that help. Until such time this will make the exercises
simpler to solve.
[p1]
A B C D
How is the linked list represented after the program segment below executes?
p2 = new ListNode('E',null);
p1.setValue(p2.getValue());
(A) A B C D
(B) A B C E
(C) E B C D
(D) E E E E
[p1]
A B C D
How is the linked list represented after the program segment below executes?
p2 = new ListNode('E',null);
while (p1.getNext() != null)
p1 = p1.getNext();
p1.setValue(p2.getValue());
(A) A B C D
(B) A E C D
(C) A B C E
(D) A B E D
[p1]
A B C D
How is the linked list represented after the program segment below executes?
p2 = new ListNode('E',null);
while (p1.getNext().getNext() != null)
p1 = p1.getNext();
p1.setValue(p2.getValue());
(A) A B C D
(B) A E C D
(C) A B C E
(D) A B E D
[p1]
A B C D
How is the linked list represented after the program segment below executes?
p2 = new ListNode('E',null);
while (p1.getNext().getNext().getNext() != null)
p1 = p1.getNext();
p2.setValue(p1.getValue());
(A) A B C D
(B) A E C D
(C) A B C E
(D) A B E D
[p1]
A B C D
How is the linked list represented after the program segment below executes?
(A) A B C D
(B) D C B A
(C) D D D D
(D) A A A A
[p1]
A B C D
How is the linked list represented after the program segment below executes?
(A) A B C D
(B) A C C C
(C) A B C C
(D) C C C D
[p1]
A B C D
How is the linked list represented after the program segment below executes?
p2 = new ListNode('E',null);
while (p1.getNext() != null)
p1 = p1.getNext();
p1.setNext(p2);
(A) A B C D E
(B) A B C E D
(C) A B C E
(D) A B D C
[p1]
A B C D
How is the linked list represented after the program segment below executes?
p2 = new ListNode('E',null);
while (p1.getNext().getNext() != null)
{
p2 = p1;
p1 = p1.getNext();
p2.setValue(p1.getValue());
}
(A) A B C D E
(B) B C D E A
(C) B C C D
(D) B C D E
[p1]
A B C D
How is the linked list represented after the program segment below executes?
p2 = new ListNode('E',null);
while (p1.getValue() != 'C')
{
p3 = p1;
p1 = p1.getNext();
}
p3.setNext(p2);
p2.setNext(p1);
(A) A B C E D
(B) A B E C D
(C) A E B C D
(D) A B C D E
[p1]
A B C D
How is the linked list represented after the program segment below executes?
(A) A B C D
(B) A B C E
(C) B C D A
(D) D C B A
If you did these types of exercises for the first time, they probably were pretty
tricky. Many students attempt to find an answer to linked list problems without
drawing any pictures. That is a mistake. Linked list problems rapidly become
confusing and you will quickly forget the changes in the reference values and the
data values.
Handling the practice exercises you just finished is important for two reasons.
First, this type of exercise may very well be representative of some of the
multiple choice questions on the AB examination. Second, as you write solutions
for any linked list lab assignment or free response answer on the AP examination,
you need to be able to trace accurately through your solution. This is even more
significant for the free response questions than the lab assignments. With the lab
assignment you have a computer, which displays the incorrect result of some
illogical solution. It is possible that you cannot trace linked list statement very
well, but your computer will display the actual values in each of the nodes and
give you help in debugging the problem. Free response questions are another
story. You have no computer, which provides feedback. You have very little
time and you need a method to determine accuracy.
33.12 Summary
Chapter XXXIII Linked Lists I 33.61
ArrayList Warning
data.addFirst(value);
data.addLast(value);
Method next moves the iterator to the next element, and then
returns it.
while (iter.hasNext())
iter.remove();
iter.set(new Integer(9999));
class ListNode
{
public Object value;
public ListNode next;
}
AP Examination Alert