0% found this document useful (0 votes)
4 views48 pages

Slides 34

The document discusses various linked list implementations in Java, including ordered linked lists, circular linked lists, and doubly linked lists. It highlights the importance of avoiding null dereferencing to prevent runtime errors, particularly in the context of the APCS exam. Additionally, it provides code examples for creating and manipulating these data structures.

Uploaded by

murtazaazm065
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views48 pages

Slides 34

The document discusses various linked list implementations in Java, including ordered linked lists, circular linked lists, and doubly linked lists. It highlights the importance of avoiding null dereferencing to prevent runtime errors, particularly in the context of the APCS exam. Additionally, it provides code examples for creating and manipulating these data structures.

Uploaded by

murtazaazm065
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
You are on page 1/ 48

Dereferencing null

If front is an object of the ListNode class


than any statement like front.getNext()
or front.getValue() dereferences front.

If front == null, then a statement like


front.getNext() results in dereferencing
null and displays a NullPointerException
error.
Short Circuiting
Short Circuiting occurs in Java whenever a compound
condition guarantees the value of the entire condition by
only checking the first condition. In such a case any
additional conditions are not checked anymore.

With a logical and, Condition B


is not checked if A equals false,
because the entire condition
will be false.

if (Condition A && Condition B)

With a logical or, Condition B is not checked if A equals


true, because the entire condition will be true.

if (Condition A || Condition B)
// Java3401.java
// This program reviews the creation of an "ordered" linked list.
// The <ListNode> class uses the <int> type for operating convenience.
// Remember that many different cases must be considered.

public class Java3401


{
public static void main (String args[])
{
System.out.println("\nJAVA3401.JAVA\n");
int[] intArray = {150,100,130,120,160,110,140};
List list = new List(intArray);
list.displayLinkedList();
System.out.println();
}
}

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[] lst)


{
front = null;
for (int k = 0; k < lst.length; k++)
insertNode(lst[k]);
}

public void displayLinkedList()


{
System.out.println("\nDISPLAY OF LINKED LIST ELEMENTS\n");
ListNode p = front;
for (int k = 1; k <= 5; k++)
{
System.out.print(p.getValue() + " ");
p = p.getNext();
}
System.out.println();
}
void insertNode(int newValue)
{
ListNode p = null;
ListNode t1 = null;
ListNode t2 = null;
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);
}
}
}
}
// Java3402.java
// This program declares <nodeObj>, but does not instantiate the object.
// An attempt is made to access the <value> field by dereferencing <nodeObj>,
// which results in a runtime error because you cannot "dereference" <null>.

public class Java3402


{
public static void main (String args[])
{
System.out.println("\nJAVA3402.JAVA\n");
ListNode nodeObj = null;
nodeObj.setValue(100);
int num = nodeObj.getValue();
System.out.println();
}
}

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;
}
// Java3403.java
// This program demonstrates how to avoid "dereferencing" <null>
// with a conditional statement prior to working with <nodeObj>.

public class Java3403


{

public static void main (String args[])


{
System.out.println("\nJAVA3403.JAVA\n");
ListNode nodeObj = null;
if (nodeObj != null)
{
nodeObj.setValue(100);
int num = nodeObj.getValue();
}
System.out.println();
}
}

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;
}
AP Exam Alert
Dereferencing NULL is a definite
issue on the APCS exam.

You may be required to write


methods that manipulate linked
structures in different ways.

Many students lose points with their solutions


because there is no protection provided
against the dreaded dereferencing null
problem.
// Java3404.java
// This program implements a <MyStack> class using the <ListNode> class.
// This <MyStack> class handles only <int> stack values.
public class Java3404
{
public static void main (String args[])
{
System.out.println("\nJAVA3404.JAVA\n");
MyStack numbers = new MyStack();
numbers.push(123);
numbers.push(234);
numbers.push(345);
numbers.push(456);
System.out.println("Top number: " + numbers.peek());
System.out.println();
while (!numbers.emptyStack())
System.out.println(numbers.pop());
System.out.println();
System.out.println("Top number: " + numbers.peek());
System.out.println();
}
}

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 MyStack public int pop()
{ {
private ListNode top; if (top != null)
private ListNode temp;
{
public MyStack() { clearStack(); } int topValue = top.getValue();
top = top.getNext();
public void clearStack() return topValue;
{ }
top = null; else
temp = null; return 0;
} }
public boolean emptyStack()
{ public int peek()
return top == null; {
} if (top != null)
return top.getValue();
public void push(int num) else
{ return 0;
temp = new ListNode(num,top);
}
top = temp;
}
}
// Java3405.java
// This program implements a <MyStack> class using the <ListNode> class, but
// now stores <Object> stack values for more general processing.

public class Java3405


{
public static void main (String args[])
{
System.out.println("\nJAVA3405.JAVA\n");
MyStack names = new MyStack();
names.push("John");
names.push("Greg");
names.push("Maria");
names.push("Heidi");
System.out.println("Top name: " + names.peek());
System.out.println();
while (!names.emptyStack())
System.out.println(names.pop());
System.out.println();
System.out.println("Top name: " + names.peek());
System.out.println();
}
}

class ListNode
{
public ListNode (Object initValue, ListNode initNext) { value = initValue; next = initNext; }
public Object getValue () { return value; }
public ListNode getNext () { return next; }
public void setValue (Object theNewValue) { value = theNewValue; }
public void setNext (ListNode theNewNext) { next = theNewNext; }
private Object value;
private ListNode next;
}
class MyStack public Object pop()
{ {
private ListNode top; if (top != null)
private ListNode temp; {
Object stackItem = top.getValue();
public MyStack() { clearStack(); }
top = top.getNext();
public void clearStack() return stackItem;
{ }
top = null; else
temp = null; return null;
} }

public boolean emptyStack()


public Object peek()
{
{
return top == null;
if (top != null)
} return top.getValue();
else
public void push(Object stackItem) return null;
{ }
temp = new ListNode(stackItem,top);
top = temp; }
}
// Java3406.java
// This program implements a <MyQueue> class using the <ListNode> class with <Object>
// queue values.
public class Java3406
{
public static void main (String args[])
{
System.out.println("\nJAVA3406.JAVA\n");
MyQueue names = new MyQueue();
names.enQueue("John");
names.enQueue("Greg");
names.enQueue("Maria");
names.enQueue("Heidi");
System.out.println("Front name: " + names.peek());
System.out.println();
while (!names.emptyQueue())
System.out.println(names.deQueue());
System.out.println();
System.out.println("Front name: " + names.peek());
System.out.println();
}
}
class ListNode
{
public ListNode (Object initValue, ListNode initNext) { value = initValue; next = initNext; }
public Object getValue () { return value; }
public ListNode getNext () { return next; }
public void setValue (Object theNewValue) { value = theNewValue; }
public void setNext (ListNode theNewNext) { next = theNewNext; }
private Object value;
private ListNode next;
}
class MyQueue public boolean emptyQueue()
{ {
private ListNode front, back, temp; return front == null;
}
public MyQueue() { clearQueue(); }
public Object deQueue()
{
public void clearQueue() if (front != null)
{ {
front = back = temp = null; Object queueItem = front.getValue();
} front = front.getNext();
return queueItem;
public void enQueue(Object queueItem) }
{ else
temp = new ListNode(queueItem,null); return null;
if (front == null) }
front = back = temp;
public Object peek()
else
{
{ if (front != null)
back.setNext(temp); return front.getValue();
back = temp; else
} return null;
} }
}
Circular Linked List
Definition
A circular linked list is a structure where the nodes are
linked in a continuous, circular sequence without a null
reference value for the last node.

Most circular linked lists are created in a queue


sequence, such that new nodes are linked between the
last node and the first node.

Nodes are removed starting with the first node that was
created.

Circular linked lists are sometimes called rings.


How a Queue becomes a Ring
(or Circular Linked List)
The difference between a Queue and a Ring is
that the next field of the last node in the Ring
does not point to null. Instead it points to the
first node.

A B C D E

A B C D E
// Java3407.java
// This program creates a queue with the <ListNode> class.
// At the conclusion the queue becomes a "circular linked List".
public class Java3407
{
public static void main (String args[])
{
System.out.println("\nJAVA3407.JAVA\n");
ListNode temp = new ListNode("John",null);
ListNode front = temp;
ListNode back = temp;
temp = new ListNode("Greg",null);
back.setNext(temp);
back = temp;
temp = new ListNode("Maria",null);
back.setNext(temp);
back = temp;
temp = new ListNode("Heidi",null);
back.setNext(temp);
back = temp;
back.setNext(front); // turns linear linked list into a circular linked list
for (int k = 1; k <= 12; k++)
{
System.out.println(front.getValue());
front = front.getNext();
}
System.out.println();
}
}
// Java3408.java
// This program demonstrates the <MyRing> class, which creates circular linked lists.
public class Java3408
{
public static void main (String args[])
{
System.out.println("\nJAVA3408.JAVA\n");
MyRing numbers = new MyRing();
for (int k = 10; k <= 18; k++)
numbers.enRing(String.valueOf(k));
numbers.resetPeek();
for (int k = 1; k <= 25; k++)
System.out.print(numbers.nextPeek() + " ");
System.out.println("\n\n");
}
}

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 MyRing public void enRing(Object ringItem)
{ {
private ListNode start, end, temp; temp = new ListNode(ringItem,null);
if (start == null) {
start = end = temp;
public MyRing() { clearRing(); } start.setNext(end);
}
else {
public void clearRing() end.setNext(temp);
{ end = temp;
start = end = temp = null; end.setNext(start);
}
} }

public boolean emptyRing() public Object deRing()


{
{ if (start != null) {
return start == null; Object ringItem = start.getValue();
} if (end == start)
start = end = null;
else {
public void resetPeek() { temp = end; } start = start.getNext();
end.setNext(start);
}
public Object nextPeek() return ringItem;
{ }
temp = temp.getNext(); else
return null;
return temp.getValue(); }
} }
Doubly Linked Lists
In a doubly linked list, there are 2 reference
fields, one for the next node, and one for the
previous node. Separate front and back
references are needed to access both ends of
the linked list.

Ann Joe Meg Sue Tom


AP Exam Alert
A survey of previously released free-response
examinations shows that doubly-linked lists
are a frequent question topic on the APCS
examination.
// Java3409.java
// This program uses a <DoubleNode> class to construct a "doubly" linked list.
// This type of list can be traversed in both directions.
public class Java3409
{
public static void main (String args[])
{
System.out.println("\nJAVA3409.JAVA\n");
DoubleNode front, back, temp;
temp = new DoubleNode(String.valueOf(100),null,null);
front = temp;
back = temp;
for (int k = 200; k < 1000; k+= 100) {
temp = new DoubleNode(String.valueOf(k),null,back);
back.setForward(temp);
back = temp;
}
temp = front;
while (temp != null) {
System.out.print(temp.getValue() + " ");
temp = temp.getForward();
}
System.out.println("\n\n");
temp = back;
while (temp != null) {
System.out.print(temp.getValue() + " ");
temp = temp.getBack();
}
System.out.println("\n\n");
}
}
class DoubleNode
{
public DoubleNode (Object initValue, DoubleNode initForward, DoubleNode initBack)
{
value = initValue;
forward = initForward;
back = initBack;
}

public Object getValue () { return value; }


public DoubleNode getForward () { return forward; }
public DoubleNode getBack () { return back; }
public void setValue (Object theNewValue) { value = theNewValue; }
public void setForward (DoubleNode theNewForward) { forward = theNewForward; }
public void setBack ( DoubleNode theNewBack) { back = theNewBack; }

private Object value;


private DoubleNode forward;
private DoubleNode back;
}
What is a Sparse Matrix?
Imagine a matrix with 1000 rows and 1000 columns.

Imagine also that 99% of the cells in this matrix


contain a value of 0. Only 1% of the matrix contains
interesting data.

As a 2D array, this would store 1,000,000 cells when


only 10,000 are required.

This is a profound waste of memory.

Linked Lists give us a better way…


Linked Lists of Linked Lists
A 2D array is really an array of arrays. In the same manner we can
have a “2D Linked List” by having a Linked List of Linked Lists.

rowNr nextRow nextCol colNr data nextCol colNr data nextCol

24 15 34.678 54 117.03
rowNr nextRow nextCol colNr data nextCol colNr data nextCol

92 105 234.76 389 51.003


rowNr nextRow nextCol colNr data nextCol

237 589 111.11


rowNr nextRow nextCol colNr data nextCol colNr data nextCol

734 308 9643.2 735 91.098


Row Nodes vs Column Nodes
Row Nodes contain no data and have 2 references.
Column Nodes contain data and have 1 reference.

rowNr nextRow nextCol colNr data nextCol colNr data nextCol

24 15 34.678 54 117.03
rowNr nextRow nextCol colNr data nextCol colNr data nextCol

92 105 234.76 389 51.003


rowNr nextRow nextCol colNr data nextCol

237 589 111.11


rowNr nextRow nextCol colNr data nextCol colNr data nextCol

734 308 9643.2 735 91.098


rowNode & colNode classes
class RowNode class ColNode
{ {
public RowNode (int initRowNumber, ColNode public ColNode (int initValue, int initColNumber,
initNextCol, RowNode initNextRow) ColNode initNextCol)
{ {
rowNumber = initRowNumber; value = initValue;
nextCol = initNextCol; colNumber = initColNumber;
nextRow = initNextRow; nextCol = initNextCol;
} }
public int getRowNumber () { return rowNumber; } public int getValue () { return value; }
public ColNode getNextCol () { return nextCol; } public int getColNumber () { return colNumber; }
public RowNode getNextRow () { return nextRow; } public ColNode getNextCol () { return nextCol; }
public void setNextCol (ColNode theNewNextCol) public void setValue (int theNewValue)
{ {
nextCol = theNewNextCol; value = theNewValue;
} }
public void setNextRow (RowNode theNewNextRow) public void setNextCol (ColNode theNewNextCol)
{ {
nextRow = theNewNextRow; nextCol = theNewNextCol;
} }
private int rowNumber; private int colNumber;
private ColNode nextCol; private ColNode nextCol;
private RowNode nextRow; private int value;
Sparse class Beginning
class Sparse
{
private RowNode head; // points to the header node of the first linked list
private boolean first; // determines if first node is created or not

public Sparse()
{
head = null;
first = true;
}
}
Sparse class Methods
initializes the head reference to null
constructor and sets the boolean variable first to
true
responsible for gathering data from the
enterSparse program user and calling the proper
methods to handle the new information
If first is true then enterSparse will
firstNode call this method, which will create the
very first header node and well as the
first column node.
This is the workhorse method in the
insertNode group. It insures that new nodes are
properly inserted in the existing matrix.
Traverses the entire matrix structure
displaySparse and displays all the row values, column
values and data values that are stored.
// Java3410.java The simplicity of the main method hides
// This program implementsthe real work performed
a "sparse by this
matrix" class usingprogram.
// a linked list of linkedSeveral
lists. other methods will do the real
work of this program, but these methods
import java.util.*; are not called from the main method body.

public class Java3410 The next several slides will continue to


{ look at different parts of this program.
public static void main (String args[])
{
System.out.println("\nJAVA3410.JAVA\n");
Sparse sparse = new Sparse();
sparse.enterSparse();
sparse.displaySparse();
System.out.println("\n\n");
}
}
public void enterSparse()
{
Scanner input = new Scanner(System.in);
System.out.println("\nEnter [ -999 <cr> ] after last data entry to exit\n");
boolean done = false;
do
{
System.out.println();
System.out.print("Enter row number ===>> ");
int row = input.nextInt();
done = row == -999;
if (!done)
{
System.out.print("Enter col number ===>> ");
int col = input.nextInt();
System.out.print("Enter sparse value ===>> ");
int val = intput.nextInt();
if (first)
{
firstNode(val,row,col);
first = false;
}
else
{
insertNode(val,row,col);
}
}
}
while (!done);
}
The First Node
The first node must be created in a special way
and will actually require the creation of 2 nodes.

public void firstNode(int value, int row, int col)


{
ColNode temp = new ColNode(value,col,null);
head = new RowNode(row,temp,null);
}

rowNr nextRow nextCol colNr data nextCol

24 15 34.678
public void insertNode(int value, int row, int col)
{
ColNode c1 = null, c2 = null, c3 = null; // used to create new col nodes
RowNode r1 = null, r2 = null, r3 = null; // used to create new row nodes

// create new col node with new value


c1 = new ColNode(value,col,null);

/****************************************************************
/* The first consideration is to determine if the new node needs
/* to be placed ahead of the existing first header node. This
/* situation occurs if the row value is less than the row number
/* value of the first header node. If this is true, a new header
/* node needs to be created, which will be linked to the
/* insertion node and the previous first header node.
/****************************************************************/

if (row < head.getRowNumber())


// create new first header node if row is less than current first row
{
r1 = new RowNode(row,c1,head);
head = r1;
}
/*****************************************************************
/* If the insertion node does not create a new linked list before
/* the first header node, a search needs to be performed to first
/* identify the proper row location of the insertion node.
/* Reference r2 starts at the head reference and traverses
/* ”downward” as the row value is greater than the row number of
/* each header node along the traversal. Note that dereferencing
/* null is avoided by the compound decisions, which will
/* ”short circuit” in the event that r2 == null.
/****************************************************************/

else
{
r2 = head;
while (r2 != null && row > r2.getRowNumber())
// traverse to find the proper row location
{
r3 = r2;
r2 = r2.getNextRow();
}
/****************************************************************
/* When the loop exits, it is possible that row is equal to the
/* current row number. In that case it is not necessary to create
/* a new header node. A check is made to see if this is true by
/* comparing row and the current row number.
/****************************************************************/

if (r2 != null && row == r2.getRowNumber())

// new node is inserted in an existing row


/****************************************************************
/* It is now established that the current header node is the
/* correct linked list for the insertion node. The next step is
/* to identify the column position. Reference c2 is assigned to
/* the first column node in the linked list. Before starting any
/* traversal, a comparison is made to see if the insertion node
/* needs to be linked before the first column node in the current
/* linked list. If that is true, the current header node links
/* to the insertion node, and the insertion node links to the
/* previous first column node.
/****************************************************************/

{
c2 = r2.getNextCol();
if (col < c2.getColNumber())
// new node fits between header node and the first col node
{
r2.setNextCol(c1);
c1.setNextCol(c2);
}
/****************************************************************
/* If the insertion node does not link at the head of the current
/* linked list, a search must be performed to find the proper
/* column position. The c2 reference traverses with a while loop
/* as long as col is greater than the column number. Note that once
/* again short-circuiting prevents dereference problems.
/* Another reference, c3 trails c2 one node behind. When c2 stops
/* there are now two references at the location for the insertion
/* node. c3 links to the insertion node c1 and the insertion
/* node links to c2.
/****************************************************************/

else
{
while (c2 != null && col > c2.getColNumber())
// find proper col insertion position
{
c3 = c2;
c2 = c2.getNextCol();
}
c3.setNextCol(c1);
c1.setNextCol(c2);
}
}
/****************************************************************
/* It is easy to think that the job is done. However, there
/* exists one more very important case. This is the situation
/* of placing the insertion node neither before the first header
/* node nor in a linked list with an existing header node. In
/* this case a new header node needs to be established to start
/* a new linked list. The insertion node will be the first
/* column node in the new linked list. After all the previous
/* checks and loops, r2 is now at the location in the sparse
/* matrix where the new linked list needs to be created
/****************************************************************/

else
{
r1 = new RowNode(row,c1,r2);
r3.setNextRow(r1);
}
}

}
insertNode Warning
The logic and the code of method insertNode is
quite complex, especially the first time around.

It will be helpful to take some sample data and


draw the growing linked list of linked lists as it
develops.

A drawing is absolutely essential to clarify the


complexity of the various links and conditions
that arise.
public void displaySparse()
{
System.out.println();
RowNode r = head;
ColNode c = null;
while (r != null)
{
c = r.getNextCol();
while (c != null)
{
int row = r.getRowNumber();
int col = c.getColNumber();
int val = c.getValue();
System.out.println("[" + row + "," + col + "] \t= " + val);
c = c.getNextCol();
}
r = r.getNextRow();
}
}
AP Exam Alert
The ability to study a provided program
and then alter existing methods or add
new methods is a typical requirement
for free response questions on the
AP Computer Science
Examination.
"There are no pointers in Java."
You will hear several people say this about Java.

After the previous 2 chapters, which seamed to have a


lot of pointing go on, the statement seams ludicrous.

However, the statement is completely true!

Java has no pointers, but it does have references.

The difference between the two is that a


pointer is declared to store the memory
address of a particular data type.

A reference simply stores a memory address with no


knowledge of what it is pointing to.

NOTE: Java still manages to have NullPointerExceptions as


appose to NullReferenceExceptions.

You might also like