CHAPTER 4: Linked Structuresprofesor.uprb.edu/.../lewis_chase_chap04.pdf · * @author Lewis and...
Transcript of CHAPTER 4: Linked Structuresprofesor.uprb.edu/.../lewis_chase_chap04.pdf · * @author Lewis and...
© 2010 Pearson Addison-Wesley. All rights reserved.
Addison Wesley
is an imprint of
CHAPTER 4:
Linked Structures
Java Software Structures:
Designing and Using Data Structures
Third Edition
John Lewis & Joseph Chase
1-2
© 2010 Pearson Addison-Wesley. All rights reserved. 1-2
Chapter Objectives
• Describe the use of references to create linked structures
• Compare linked structures to array-based structures
• Explore the techniques for managing a linked list
• Discuss the need for a separate node to form linked structures
• Implement a stack collection using a linked list
1-3
© 2010 Pearson Addison-Wesley. All rights reserved. 1-3
References as Links
• There are many ways to implement a collection
• In chapter 3 we explored an array-based implementation of a stack collection
• A linked structure uses object reference variables to link one object to another
• Recall that an object reference variable stores the address of an object
• In that sense, an object reference is a pointer to an object
1-5
© 2010 Pearson Addison-Wesley. All rights reserved. 1-5
Self-Referential Objects
• A Person object, for instance, could contain a reference variable to another Person object:
public class Person
{
private String name;
private String address;
private Person next; // a link to another Person object
// whatever else
}
1-6
© 2010 Pearson Addison-Wesley. All rights reserved. 1-6
Linked Lists
• This type of reference can be used to form a linked list, in which one object refers to the next, which refers to the next, etc.
• Each object in a list is often generically called a node
• A linked list is a dynamic data structure in that its size grows and shrinks as needed, unlike an array, whose size is static or fixed
• Java objects are created dynamically when they are instantiated
1-8
© 2010 Pearson Addison-Wesley. All rights reserved. 1-8
Non-linear Structures
• A linked list, as the name implies, is a
linear structure
• Object references also allow us to create
non-linear structures such as hierarchies
and graphs
1-10
© 2010 Pearson Addison-Wesley. All rights reserved. 1-10
Managing Linked Lists
• The references in a linked list must be carefully managed to maintain the integrity of the structure
• Special care must be taken to ensure that the entry point into the list is maintained properly
• The order in which certain steps are taken is important
• Consider inserting and deleting nodes in various positions within the list
1-11
© 2010 Pearson Addison-Wesley. All rights reserved. 1-11
Inserting a node at the front of a linked
list
1-12
© 2010 Pearson Addison-Wesley. All rights reserved. 1-12
Inserting a node in the middle of a linked
list
1-13
© 2010 Pearson Addison-Wesley. All rights reserved. 1-13
Deleting the first node in a linked list
1-14
© 2010 Pearson Addison-Wesley. All rights reserved. 1-14
Deleting an interior node from a linked list
1-15
© 2010 Pearson Addison-Wesley. All rights reserved. 1-15
Elements without Links
• The problem with self-referential objects is that they must "know" they are part of a list
• A better approach is to manage a separate list of nodes that also reference the objects stored in the list
• The list is still managed using the same techniques
• The objects stored in the list need no special implementation to be part of the list
• A generic list collection can be used to store any kind of object
1-16
© 2010 Pearson Addison-Wesley. All rights reserved. 1-16
Using separate node objects to store and
link elements
1-17
© 2010 Pearson Addison-Wesley. All rights reserved. 1-17
Sentinel nodes
• There are variations on the implementation
of linked lists that may be useful in
particular situations
• One such solution is the use of sentinel
nodes or dummy nodes on either end of
the list
• This practice eliminates the special cases
of inserting or deleting the first or last node
1-18
© 2010 Pearson Addison-Wesley. All rights reserved. 1-18
Doubly Linked Lists
• Another useful variation is a doubly linked
list
• In a doubly linked list each node has a
reference to both the next and previous
nodes in the list
• This makes traversing the list easier
1-20
© 2010 Pearson Addison-Wesley. All rights reserved. 1-20
Implementing a stack with links
• We can use a linked list to implement our
stack collection from chapter 3
• First, however, we will need to create a
LinearNode class to represent a node in
the list
1-21
© 2010 Pearson Addison-Wesley. All rights reserved. 1-21
The LinearNode class
/**
* @author Lewis and Chase
*
* Represents a node in a linked list.
*/
package jss2;
public class LinearNode<T>
{
/** reference to next node in list */
private LinearNode<T> next;
/** element stored at this node */
private T element;
/**
* Creates an empty node.
*/
public LinearNode()
{
next = null;
element = null;
}
1-22
© 2010 Pearson Addison-Wesley. All rights reserved. 1-22
The LinearNode class (continued)
/**
* Creates a node storing the specified element.
* @param elem element to be stored
*/
public LinearNode (T elem)
{
next = null;
element = elem;
}
/**
* Returns the node that follows this one.
* @return LinearNode<T> reference to next node
*/
public LinearNode<T> getNext()
{
return next;
}
/**
* Sets the node that follows this one.
* @param node node to follow this one
*/
1-23
© 2010 Pearson Addison-Wesley. All rights reserved. 1-23
The LinearNode class (continued)
public void setNext (LinearNode<T> node)
{
next = node;
}
/**
* Returns the element stored in this node.
* @return T element stored at this node
*/
public T getElement()
{
return element;
}
/**
* Sets the element stored in this node.
* @param elem element to be stored at this node
*/
public void setElement (T elem)
{
element = elem;
}
}
1-24
© 2010 Pearson Addison-Wesley. All rights reserved. 1-24
A linked implementation of a stack
collection
1-25
© 2010 Pearson Addison-Wesley. All rights reserved. 1-25
LinkedStack
/**
* @author Lewis and Chase
*
* Represents a linked implementation of a stack.
*/
package jss2;
import jss2.exceptions.*;
import java.util.Iterator;
public class LinkedStack<T> implements StackADT<T>
{
/** indicates number of elements stored */
private int count;
/** pointer to top of stack */
private LinearNode<T> top;
/**
* Creates an empty stack.
*/
public LinkedStack()
{
count = 0;
top = null;
}
1-27
© 2010 Pearson Addison-Wesley. All rights reserved. 1-27
LinkedStack – the push operation
/**
* Adds the specified element to the top of this stack.
* @param element element to be pushed on stack
*/
public void push (T element)
{
LinearNode<T> temp = new LinearNode<T> (element);
temp.setNext(top);
top = temp;
count++;
}
1-29
© 2010 Pearson Addison-Wesley. All rights reserved. 1-29
LinkedStack – the pop operation
/**
* Removes the element at the top of this stack and returns a
* reference to it. Throws an EmptyCollectionException if the stack
* is empty.
* @return T element from top of stack
* @throws EmptyCollectionException on pop from empty stack
*/
public T pop() throws EmptyCollectionException
{
if (isEmpty())
throw new EmptyCollectionException("Stack");
T result = top.getElement();
top = top.getNext();
count--;
return result;
}
1-31
© 2010 Pearson Addison-Wesley. All rights reserved. 1-31
LinkedStack – the other operations
• Using a linked implementation, the peek
operation is implemented by returning a
reference to top
• The isEmpty operation returns true if the count of
elements is 0, and false otherwise
• The size operation simply returns the count of
elements in the stack
• The toString operation can be implemented by
simply traversing the linked list.
1-32
© 2010 Pearson Addison-Wesley. All rights reserved. 1-32
Analysis of Stack Operations
• Like our ArrayStack operations, the LinkedStack operations work on one end of the collection and are generally efficient
• The push and pop operations, for the linked implementation are O(1)
• Likewise, the other operations are also O(1)
1-33
© 2010 Pearson Addison-Wesley. All rights reserved. 1-33
Using Stacks - Traversing a Maze
• A classic use of a stack is to keep track of
alternatives in maze traversal or other trial
and error algorithms
• Using a stack in this way simulates
recursion
– Recursion is when a method calls itself either
directly or indirectly
1-34
© 2010 Pearson Addison-Wesley. All rights reserved. 1-34
Using Stacks - Traversing a Maze
• Run-time environments keep track of method
calls by placing an activation record for each
called method on the run-time stack
• When a method completes execution, it is
popped from the stack and control returns to the
method that called it
– Which is now the activation record on the top of the
stack
1-35
© 2010 Pearson Addison-Wesley. All rights reserved. 1-35
Using Stacks - Traversing a Maze
• In this manner, we can traverse a maze by trial
and error by using a stack to keep track of moves
that have not yet been tried
1-36
© 2010 Pearson Addison-Wesley. All rights reserved. 1-36
The Maze class
/**
* @author Lewis and Chase
*
* Represents a maze of characters. The goal is to get from the
* top left corner to the bottom right, following a path of 1's.
*/
import jss2.*;
public class Maze
{
/**
* constant to represent tried paths
*/
private final int TRIED = 3;
/**
* constant to represent the final path
*/
private final int PATH = 7;
1-37
© 2010 Pearson Addison-Wesley. All rights reserved. 1-37
The Maze class (continued)
/**
* two dimensional array representing the grid
*/
private int [][] grid = { {1,1,1,0,1,1,0,0,0,1,1,1,1},
{1,0,0,1,1,0,1,1,1,1,0,0,1},
{1,1,1,1,1,0,1,0,1,0,1,0,0},
{0,0,0,0,1,1,1,0,1,0,1,1,1},
{1,1,1,0,1,1,1,0,1,0,1,1,1},
{1,0,1,0,0,0,0,1,1,1,0,0,1},
{1,0,1,1,1,1,1,1,0,1,1,1,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0},
{1,1,1,1,1,1,1,1,1,1,1,1,1} };
/**
* push a new attempted move onto the stack
* @param x represents x coordinate
* @param y represents y coordinate
* @param stack the working stack of moves within the grid
* @return StackADT<Position> stack of moves within the grid
*/
1-38
© 2010 Pearson Addison-Wesley. All rights reserved. 1-38
The Maze class (continued)
private StackADT<Position> push_new_pos(int x, int y,
StackADT<Position> stack)
{
Position npos = new Position();
npos.setx(x);
npos.sety(y);
if (valid(npos.getx(),npos.gety()))
stack.push(npos);
return stack;
}
/**
* Attempts to iteratively traverse the maze. It inserts special
* characters indicating locations that have been tried and that
* eventually become part of the solution. This method uses a
* stack to keep track of the possible moves that could be made.
* @return boolean returns true if the maze is successfully traversed
*/
1-39
© 2010 Pearson Addison-Wesley. All rights reserved. 1-39
The Maze class (continued)
public boolean traverse ()
{
boolean done = false;
Position pos = new Position();
Object dispose;
StackADT<Position> stack = new LinkedStack<Position>();
stack.push(pos);
while (!(done))
{
pos = stack.pop();
grid[pos.getx()][pos.gety()] = TRIED; // this cell has been tried
if (pos.getx() == grid.length-1 && pos.gety() == grid[0].length-1)
done = true; // the maze is solved
else
{
stack = push_new_pos(pos.getx(),pos.gety() - 1, stack);
stack = push_new_pos(pos.getx(),pos.gety() + 1, stack);
stack = push_new_pos(pos.getx() - 1,pos.gety(), stack);
stack = push_new_pos(pos.getx() + 1,pos.gety(), stack);
}
}
1-40
© 2010 Pearson Addison-Wesley. All rights reserved. 1-40
The Maze class (continued)
return done;
}
/**
* Determines if a specific location is valid.
* @param row int representing y coordinate
* @param column int representing x coordinate
* @return boolean true if the given coordinate is a valid move
*/
private boolean valid (int row, int column)
{
boolean result = false;
/** Check if cell is in the bounds of the matrix */
if (row >= 0 && row < grid.length &&
column >= 0 && column < grid[row].length)
/** Check if cell is not blocked and not previously tried */
if (grid[row][column] == 1)
result = true;
return result;
}
1-41
© 2010 Pearson Addison-Wesley. All rights reserved. 1-41
The Maze class (continued)
/**
* Returns the maze as a string.
* @return String representation of the maze grid
*/
public String toString ()
{
String result = "\n";
for (int row=0; row < grid.length; row++)
{
for (int column=0; column < grid[row].length; column++)
result += grid[row][column] + "";
result += "\n";
}
return result;
}
}
1-42
© 2010 Pearson Addison-Wesley. All rights reserved. 1-42
The MazeSearch class
/**
* @author Lewis and Chase
*
* Demonstrates a simulation of recursion using a stack.
*/
public class MazeSearch
{
/**
* Creates a new maze, prints its original form, attempts to
* solve it, and prints out its final form.
* @param args array of Strings
*/
public static void main (String[] args)
{
Maze labyrinth = new Maze();
System.out.println (labyrinth);
if (labyrinth.traverse ())
System.out.println ("The maze was successfully traversed!");
else
System.out.println ("There is no possible path.");
System.out.println (labyrinth);
}
}
1-43
© 2010 Pearson Addison-Wesley. All rights reserved. 1-43
The Position class
/**
* @author Lewis and Chase
*
* Represents a single position in a maze of characters.
*/
public class Position
{
/** x coordinate */
private int x;
/** y coordinate */
private int y;
/**
* Constructs a position and sets the x & y coordinates to 0,0.
*/
Position ()
{
x = 0;
y = 0;
}
1-44
© 2010 Pearson Addison-Wesley. All rights reserved. 1-44
The Position class (continued)
/**
* Returns the x-coordinate value of this position.
* @return int the x-coordinate of this position
*/
public int getx()
{
return x;
}
/**
* Returns the y-coordinate value of this position.
* @return int the y-coordinate of this position
*/
public int gety()
{
return y;
}
1-45
© 2010 Pearson Addison-Wesley. All rights reserved. 1-45
The Position class (continued)
/**
* Sets the value of the current position's x-coordinate.
* @param a value of x-coordinate
*/
public void setx(int a)
{
x = a;
}
/**
* Sets the value of the current position's x-coordinate.
* @param a value of y-coordinate
*/
public void sety(int a)
{
y = a;
}
}
1-46
© 2010 Pearson Addison-Wesley. All rights reserved. 1-46
The java.util.Stack Class
• The Java Collections framework defines a Stack class with similar operations
• It is derived from the Vector class and therefore has some characteristics that are not appropriate for a pure stack
• The java.util.Stack class has been around since the original version of Java, and has been retrofitted to meld with the Collections framework