1 / 47

CHAPTER 4: Linked Structures

CHAPTER 4: Linked Structures. Java Software Structures: Designing and Using Data Structures Third Edition John Lewis & Joseph Chase. Chapter Objectives. Describe the use of references to create linked structures Compare linked structures to array-based structures

kare
Download Presentation

CHAPTER 4: Linked Structures

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. CHAPTER 4: Linked Structures Java Software Structures: Designing and Using Data Structures Third Edition John Lewis & Joseph Chase

  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

  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

  4. References as Links

  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 }

  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

  7. A linked list

  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

  9. A complex linked structure

  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

  11. Inserting a node at the front of a linked list

  12. Inserting a node in the middle of a linked list

  13. Deleting the first node in a linked list

  14. Deleting an interior node from a linked list

  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

  16. Using separate node objects to store and link elements

  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

  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

  19. A doubly linked list

  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

  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; }

  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 */

  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; } }

  24. A linked implementation of a stack collection

  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; }

  26. An initial stack

  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++; }

  28. A Linked Stack After a Push Operation

  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; }

  30. A Linked Stack After a Pop Operation

  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.

  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)

  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

  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

  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

  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;

  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 */

  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 */

  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); } }

  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; }

  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; } }

  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); } }

  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; }

  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; }

  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; } }

  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

  47. A UML description of the java.util.Stack class

More Related