1 / 68

Chapter 14: Stacks

Chapter 14: Stacks. Stacks. This chapter explores the idea of collections in general and introduces one classic collection: a stack Chapter 14 focuses on the concept of a collection a classic collection: stacks generic types and their use in collection classes

venices
Download Presentation

Chapter 14: Stacks

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 14: Stacks

  2. Stacks • This chapter explores the idea of collections in general and introduces one classic collection: a stack • Chapter 14 focuses on • the concept of a collection • a classic collection: stacks • generic types and their use in collection classes • fixed (arrays) and dynamic (linked lists) structures • stack implementations • the Java Collections API

  3. Outline • Introduction to Collections • A Stack Collection • Generics • Using Stacks: Postfix Expressions • Implementing a Stack: with Arrays • References as Links • Implementing a Stack: with Links • Packages

  4. 14.1 – Introduction to Collections • We are used to collections of items: stamps, CDs, keys, etc. • A collection is an object that serves as a repository for other objects • A collection provides services to add, remove, and manage the elements it contains • The underlying data structure used to implement the collection is independent of the operations provided

  5. 14.1 – Introduction to Collections • Collections can be separated into two categories • linear: elements are organized in a straight line • nonlinear: elements are organized in something other than a straight line • Organization elements, relative to each other, is usually determined by • the order in which they were added to the collection • some inherent relationship among the elements

  6. 14.1 – Separating Interface from Implementation • An abstract data type (ADT) is a set of data and the particular operations that are allowed on that data • An ADT is considered abstract because the operations you can perform on it are separated from the underlying implementation • A collection • is an abstract data type • defines interface operations through which the user can manage the objects in the collection, such as adding / removing elements

  7. 14.1 – Separating Interface from Implementation • The details of how a collection is implemented to fulfill that definition should be an independent issue • For every collection we examine, we should consider • How does the collection operate, conceptually? • What operations are included in the interface to the collection? • What kinds of problems does the collection help us solve? • How might the collection be implemented? • How do the implementations compare from an efficiency point of view?

  8. 14.1 – Separating Interface from Implementation Class thatimplementsthe collection Services provided by collection that adhere to an interface Interface to collection Class that usesthe collection

  9. 14.1 – The Java Collections API An API (Application Programming Interface) is a set of classes that support some particular aspect of software development The Java Collections API is a set of classes that represent collections, implemented in various ways As we explore collections, we will examine both our own implementations and look at what support is provided by the Java Collections API

  10. Outline • Introduction to Collections • A Stack Collection • Generics • Using Stacks: Postfix Expressions • Implementing a Stack: with Arrays • References as Links • Implementing a Stack: with Links • Packages

  11. 14.2 – Stacks • A stack is a linear collection whose elements are added and removed from the same end • Stacks are processed in a last in, first out (LIFO) manner • Usually, stacks are depicted vertically, and we refer to the top of the stack as the end to which elements are added and removed

  12. 14.2 – Stacks Adding an element Removingan element Top of stack

  13. 14.2 – Stack Operations

  14. Outline • Introduction to Collections • A Stack Collection • Generics • Using Stacks: Postfix Expressions • Implementing a Stack: with Arrays • References as Links • Implementing a Stack: with Links • Packages

  15. 14.3 - Generics Chapters 8 and 9 discussed the object-oriented concepts of inheritance and polymorphism They are based on rules of type compatibility which lead to type checking done by the compiler An Object reference can refer to any kind of object, because of inheritance But that is a little too forgiving, so Java also provides a more formal way to establish such a relationship: generics

  16. 14.3 – Generic Types • A class can be based on a generic type • The class will then be able to operate on, store, and manage objects whose type is not specified until the class is instantiated • Example: suppose we wanted to define a class called Group that stores and manages a group of objects. • Using polymorphism, we can informally make Group generic by having it store references to Object

  17. 14.3 – Generic Types • However, any type of object could then be stored in our Group, resulting in a loss of control • A better approach is to define the Group to store a generic type T as follows class Group<T> { // declarations and code that manages objects of type T } • T is just a placeholder; you can use any identifier • The actual class that T represents is delayed until you instantiate a Group object

  18. 14.3 – Generic Types • Instantiating a Groupof Productobjects: Group<Product> group1 = new Group<Product>(); • Instantiating a Groupof Friendobjects: Group<Friend> group2 = new Group<Friend>(); • Only objects compatible with the Productclass (a Productor any of its descendents) can be stored in group1 • This is checked by the compiler, providing better type safety

  19. 14.4 – A Stack ADT Generic types and containers go hand in hand A container class can be defined to operate on a generic type T, and then each instantiation of that collection can be used to manage specific types of objects Interfaces can be defined with generic types, too The Stack<T> interface on the next slide defines an abstract data type (ADT) for a stack

  20. 14.4 – A Stack Interface //******************************************************************** // Stack.java Java Foundations // // Defines the interface to a stack collection. //******************************************************************** package javafoundations; public interface Stack<T> { // Adds the specified element to the top of the stack. public void push (T element); // Removes and returns the top element from the stack. public T pop(); // Returns a reference to the top element of this stack // without removing it. public T peek(); // Returns true if the stack contains no elements and false // otherwise. public boolean isEmpty(); // Returns the number of elements in the stack. public int size(); // Returns a string representation of the stack. public String toString(); }

  21. Outline • Introduction to Collections • A Stack Collection • Generics • Using Stacks: Postfix Expressions • Implementing a Stack: with Arrays • References as Links • Implementing a Stack: with Links • Packages

  22. 14.5 – Evaluating Postfix Expressions • Before looking further at the implementation of a stack, let's first see how one might be used • Arithmetic operations are traditionally written in infix notation, meaning that the operator is placed between its operands in the form <operand> <operator> <operand> • When evaluating infix expressions, we rely on precedence rules to determine the order of operator evaluation • In a postfix expression, the operator comes after its two operands <operand> <operand> <operator>

  23. 14.5 – Evaluating Postfix Expressions • The process of evaluating a postfix expression can be stated simply: • scan from left to right, • apply each operation to the two previous operands immediately preceding it and • replace the operator with the result • Consider the infix expression: 4 + 5 * 2 • In postfix notation, it would be written as: 4 5 2 * +

  24. 14.5 – Evaluating Postfix Expressions • Consider the design of a program that can compute the result of a postfix expression • The evaluation rule relies on being able to retrieve the previous two operands whenever we encounter an operator • A large postfix expression will have many operators and operands to manage • A stack is the perfect collection to use in this solution

  25. 14.5 – Evaluating Postfix Expressions • Solution algorithm: • scan the expression from left to right, identifying each token as an operator or operand • if the scanned token is an operand, push it onto the stack • if the scanned token is an operator • pop the top two elements off the stack, • apply the operation to them, and • push the result onto the stack • If we reach the end of the expression the remaining element on the stack is the result of the expression (otherwise the expression was not well formed)

  26. 14.5 – Using a Stack to Evaluate a Postfix Expression Given the expression: 7 4 -3 * 1 5 + / * + * 5 / 1 6 * -3 -2 -12 4 top 7 -14

  27. 14.5 – Postfix.java //******************************************************************** // Postfix.java Java Foundations // // Demonstrates the use of a stack to evaluate postfix expressions. //******************************************************************** import java.util.Scanner; public class Postfix { //------------------------------------------------------------------ // Reads and evaluates multiple postfix expressions. //------------------------------------------------------------------ public static void main (String[] args) { String expression, again; int result; try { Scanner in = new Scanner(System.in); (more…)

  28. 14.5 – Postfix.java do { PostfixEvaluator evaluator = new PostfixEvaluator(); System.out.println ("Enter a valid postfix expression: "); expression = in.nextLine(); result = evaluator.evaluate (expression); System.out.println(); System.out.println ("That expression equals " + result); System.out.print ("Evaluate another expression [Y/N]? "); again = in.nextLine(); System.out.println(); } while (again.equalsIgnoreCase("y")); } catch (Exception IOException) { System.out.println("Input exception reported"); } } }

  29. 14.5 – PostfixEvaluator.java //******************************************************************** // PostfixEvaluator.java Java Foundations // // Represents an integer evaluator of postfix expressions. Assumes // the operands are constants. //******************************************************************** import javafoundations.LinkedStack; import java.util.Scanner; public class PostfixEvaluator { private final char ADD = '+', SUBTRACT = '-'; private final char MULTIPLY = '*', DIVIDE = '/'; private LinkedStack<Integer> stack; //------------------------------------------------------------------ // Sets up this evalutor by creating a new stack. //------------------------------------------------------------------ public PostfixEvaluator() { stack = new LinkedStack<Integer>(); } (more…)

  30. 14.5 – PostfixEvaluator.java //------------------------------------------------------------------ // Evaluates the specified postfix expression. If an operand is // encountered, it is pushed onto the stack. If an operator is // encountered, two operands are popped, the operation is // evaluated, and the result is pushed onto the stack. //------------------------------------------------------------------ public int evaluate (String expr) { int op1, op2, result = 0; String token; Scanner tokenizer = new Scanner (expr); while (tokenizer.hasNext()) { token = tokenizer.next(); if (isOperator(token)) { op2 = (stack.pop()).intValue(); op1 = (stack.pop()).intValue(); result = evalSingleOp (token.charAt(0), op1, op2); stack.push (result); } else stack.push (Integer.parseInt(token)); } return result; } (more…)

  31. 14.5 – PostfixEvaluator.java //------------------------------------------------------------------ // Determines if the specified token is an operator. //------------------------------------------------------------------ private boolean isOperator (String token) { return (token.equals("+") || token.equals("-") || token.equals("*") || token.equals("/")); } //------------------------------------------------------------------ // Peforms integer evaluation on a single expression consisting of // the specified operator and operands. //------------------------------------------------------------------ private int evalSingleOp (char operation, int op1, int op2) { int result = 0; switch (operation) { case ADD: result = op1 + op2; break; case SUBTRACT: result = op1 - op2; break; case MULTIPLY: result = op1 * op2; break; case DIVIDE: result = op1 / op2; } return result; } }

  32. Outline • Introduction to Collections • A Stack Collection • Generics • Using Stacks: Postfix Expressions • Implementing a Stack: with Arrays • References as Links • Implementing a Stack: with Links • Packages

  33. 14.7 – Implementing Stacks with Arrays • Using an array is an efficient and straightforward solution to implement a stack • Given that all activity on a stack occurs at one end, fixing the bottom of the stack at array index 0 makes the implementation relatively easy • In addition, we’ll also need an integer variable to indicate • the number of elements that are currently on the stack, and • to represent the index in the array where the next item pushed onto the stack will be stored

  34. 14.7 – Implementing Stacks with Arrays • Our array-based version of a stack will be located in a class named ArrayStack

  35. 14.8 – The ArrayStack Class //******************************************************************** // ArrayStack.java Java Foundations // // Represents an array implementation of a stack. The bottom of // the stack is kept at array index 0. //******************************************************************** package javafoundations; import javafoundations.exceptions.*; public class ArrayStack<T> implements Stack<T> { private final int DEFAULT_CAPACITY = 10; private int count; private T[] stack; //----------------------------------------------------------------- // Creates an empty stack using the default capacity. //----------------------------------------------------------------- public ArrayStack() { count = 0; stack = (T[]) (new Object[DEFAULT_CAPACITY]); } (more…)

  36. 14.8 – The ArrayStack Class //----------------------------------------------------------------- // Adds the specified element to the top of this stack, expanding // the capacity of the stack array if necessary. //----------------------------------------------------------------- public void push (T element) { if (count == stack.length) expandCapacity(); stack[count] = element; count++; } //----------------------------------------------------------------- // Returns a string representation of this stack. //----------------------------------------------------------------- public String toString() { String result = "<top of stack>\n"; for (int index=count-1; index >= 0; index--) result += stack[index] + "\n"; return result + "<bottom of stack>"; } (more…)

  37. 14.8 – The ArrayStack Class //----------------------------------------------------------------- // Creates a new array to store the contents of this stack with // twice the capacity of the old one. //----------------------------------------------------------------- private void expandCapacity() { T[] larger = (T[])(new Object[stack.length*2]); for (int index=0; index < stack.length; index++) larger[index] = stack[index]; stack = larger; } //----------------------------------------------------------------- // The following methods are left as Programming Projects. //----------------------------------------------------------------- // public T pop () throws EmptyCollectionException { } // public T peek () throws EmptyCollectionException { } // public boolean isEmpty() { } // public int size() { } }

  38. Outline • Introduction to Collections • A Stack Collection • Generics • Using Stacks: Postfix Expressions • Implementing a Stack: with Arrays • References as Links • Implementing a Stack: with Links • Packages

  39. 14.9 – References as Links • An array is one way we can implement a linear collection • Arrays however are limited in one sense because they have a fixed size • Resizing as needed must be done carefully and is sometimes not an efficient implementation • A linked structure is a data structure that uses object reference variables to create links between objects • Linked structures are the primary alternative to an array-based implementation of a collection

  40. 14.9 – Linked Lists • A class can define as instance data an object reference to another object of the same class • Suppose we have a class named Person as follows: public class Person { private String name; private String address; private Person next; // a link to another Person object // whatever else }

  41. 14.9 – Linked Lists • Using only this one class, a linked structure can be created • One Person object contains a link to another Person object • This second object contains a reference to a third Person, etc. • This type of object is sometimes called self-referential • This kind of relationship forms the basis of a linked list • a linked structure in which one object refers to the next • creates a linear ordering on the objects in the list • Often the objects stored in a linked list are referred to generically as the nodes in the list

  42. 14.9 – Linked Lists • A linked list has no upper bound on its capacity other than the limitations of memory in the computer • It's considered to be a dynamic structure because its size grows and shrinks as needed front

  43. 14.9 – Linked Lists • A simple linked list is only one kind of linked structure • In a doubly linked list, each node in the list stores both a reference to the next element and a reference to the previous one front rear

  44. entry 14.9 – Nonlinear Linked Structures • Linked structures need not be linear – more on that later

  45. 14.10 – Managing Linked Lists • Stacks only update one end of a list, but lists can be used for many collections • There are a few basic techniques involved in managing nodes on the list, no matter what the list is used to store • Special care must be taken when dealing with the first node in the list • Stacks only update one end of a list, but for other collections a node may be inserted or deleted anywhere in the list

  46. 14.10 – Inserting a node at the front node 2 front 1

  47. 14.10 – Inserting a node in the middle front current 2 1 node

  48. 14.10 – Deleting the first node in the list front 2 3 1 node

  49. 14.10 – Deleting an interior node front previous 1 current 2

  50. 14.11 – Elements Without Links • We still need to examine one key aspect of linked lists • We need to separate the details of the linked list structure from the elements that the list stores • The flaw in our earlier logic (see Person class) is that the self-referential Person class must be designed so that it “knows” it may become a node in a linked list • This violates the goal of separating the implementation details from the parts of the system that use the collection

More Related