Advanced Java Concepts Unit 3: Stacks and Queues Stacks are linear collections in which access is completely restricted to just one end, called the top. Stacks adhere to a last-in, first-out protocol (LIFO). Think of a stack of plates; the last plate placed on the stack is the first one you take off. Java does have a Stack Class; here are some of its methods. Method Boolean empty() E peek() E pop() void push( E element) int size() Description Precondition: the stack is not empty Returns the object at the top of the stack (but does not remove it) Precondition: the stack is not empty Removes and returns the object at the top of the stack Adds an element to the top of the stack Note. Java implements the Stack class as a subclass of the Vector class which implements the List interface. You will need an import statement whenever you need to use this class. 1. Why do people criticize Java s stack class? What alternative could have been used? 2. What does this code snippet display? 3. This code compiles. Will there be a run-time error? If yes, explain. If no error, what is displayed? Stack<Integer> st = new Stack<Integer>(); st.push( 1 ); st.push( 2 ); st.push( 3 ); import java.util.*; public class TryStacks { public static void main(string[] args) { Stack<String> st = new Stack<String>(); st.push( "A" ); st.push( "B" ); System.out.println( st.peek() ); Page 1
One area where stacks are used is in memory management. The exact details of how computer memory is managed depend on the computer s operating system and the programming language. However, the following simplified description can be useful. Whenever a method is called, an activation record is created. This activation record includes any parameters, local variables, and probably other things I m not aware of. This activation record is placed on the stack an area of program memory reserved for this purpose. When the method is complete, the activation record is popped off the stack. The top most activation record on the stack is the method currently being executed. 4. A program has a main method and two other methods: method A and method B. The figure to the right shows the current state of the program s stack. Which statement is TRUE? a) methoda is currently running. b) methodb is currently running. c) The main method is currently running. d) There is not enough information to answer this. 5. Given the current state of the program s stack, what do you know about methoda? Note. While nothing may be technically correct for you, it is not the correct answer for this question. methodb methoda main methoda methoda main top of stack top of stack Program. Here is an algorithm for converting a non-negative base 10 number to a base 2 number. 1. Find the remainder when the number is divided by two. Push the remainder onto a stack. 2. Number = number / 2 3. Go back to step 1. Keep repeating as long as the number is greater than zero. 4. Print out the contents of the stack (i.e. print the topmost first, then the second and so on). Write a program that implements the above algorithm. After you get the basic version working, clean it up as follows: Instruct the user to enter an integer between 0 and 65535. Convert the number into base 2. Add leading zeroes (if needed) so that there is a total of 16 zeroes and ones. When you print the result, add a blank space between every four bits. For example, If the user enters 513, your program should display 0000 0010 0000 0001 If the user enters 60013, your program should display 1110 1010 0110 1101 If the user enters 0, your program should display 0000 0000 0000 0000 Your prompt to the user must be: System.out.println( "Integer?" ); Page 2
Evaluating Arithmetic Expressions. Before we discuss how stacks are used in evaluating arithmetic expressions, we need to discuss the three ways an expression can be written. Form Description Example infix Each operator is located between its operands. 3 + 4 This is the form you know and love. prefix The operator is placed to the left of the operands. This is + 3 4 also known as Polish notation. postfix The operator is placed to the right of the operands. This is also known as Reverse Polish notation. 3 4 + Infix notation sometimes requires the use of parentheses. Prefix and postfix notation do not require (and therefore do not use) parentheses. In fact, in prefix and postfix notation the order of operations is completely determined by the order of the operators. Some early (1970 s and 80 s) handheld calculators required that users enter the expressions in reverse Polish notation. Please read the Wikipedia articles, http://en.wikipedia.org/wiki/polish_notation (prefix) and http://en.wikipedia.org/wiki/reverse_polish_notation (postfix) on these topics. To evaluate an expression in prefix notation, you scan the statement from left to right. As soon as you see two adjacent operands, you perform the operation specified by the operator immediately preceding it. Then you replace the operator and two operands with the result. Keep repeating until you have a result. IMPORTANT. If the result of a particular operation is a negative number, then the resulting operand is negative (you are not adding a subtraction operator to the expression). Here are a couple of examples. + * 3 4 5 scanning left to right we find the operands 3 and 4 and the operator right before them is * so we multiply them together and replace them with 12 + 12 5 so we add 12 and 5 together 17 is the result Another example. + - 4 + 6 / 8 2 3 scanning left to right the first pair of operands we find is 8 and 2 so we divide them and replace / 8 2 with 4 + - 4 + 6 4 3 replace + 6 4 with 10 + - 4 10 3 replace - 4 10 with -6. + -6 3-6 is an operand, add -6 and 3 together -3 is the result Problems 8 to 12. Evaluate the following prefix expressions. 8) / + 6 9 3 9) / + * - 5 3 8 6 2 10) * 4 + 3-6 8 11) + 10 / 20 + 4 * 3 2 12) * + 4 9-5 7 Page 3
To evaluate an expression in postfix notation, you scan the statement from left to right. As soon as you see two adjacent operands followed by an operator, you perform the operation specified and replace the operator and two operands with the result. Keep repeating until you have a result For example: 6 7 + 2 * scanning left to right we find the operands 6 and 7 and the operator right after them is + so we add them together and replace them with 13 13 2 * multiple 13 by 2 26 is the result Another example. 3 6 4 5 + * - 2 / scanning left to right the first pair of operands followed by an operator we find 4 5 + so we replace that with 9 3 6 9 * - 2 / replace 6 9 * with 54 3 54-2 / replace 3 54 - with -51-51 2 / -51 is an operand, divide -51 by 2-25.5 is the result Problems 13 to 17. Evaluate the following postfix expressions. 13) 7 2 4 + * 14) 7 2 + 4 * 15) 3 2 24 3 / + * 16) 9 2 * 3 5 * + 17) 12 6 3 / - 10 5 * * I ll leave it up to you to find out how to convert prefix and postfix expression into the corresponding infix expressions and vice versa. Problems 18 to 22. Rewrite each statement from infix form to prefix and postfix forms. YOU MUST KEEP THE OPERANDS IN THE SAME ORDER (sorry for shouting). Infix Prefix Postfix 18 4 + 6 * 5 19 4 * 6 + 5 20 8 + 5 * 2-7 21 (2 + 3)(4 5) 22 8 7 3(5 2) Page 4
Program. Complete the Eval class. Given a valid postfix expression, the evalpostfix method will return the value of that expression. The method should be able to handle multiplication, division, addition, and subtraction. You may assume that there is exactly one space between each operator/operand. public class Eval{ public static int evalpostfix( String s ){ Call the split method to create a String array that consists of the numbers and operands in the string. All spaces should be removed. Create an Integer stack. Iterate through the array. If the element is a number, push it onto a stack. If the element is an operator, pop the last two elements off the stack, evaluate the expression and push the result onto the stack. When you are finished iterating through the array, the size of the stack should be one. Pop that value off the stack and return it. Suggestion: Write a helper method that determines if a string is a number. This can be done by using the Character.isDigit method though remember that the number could be positive or negative. Or you could write a method that checks by using a try-catch thingee. Does this sound familiar? Maybe? (Voice getting higher each time.) Queues are linear collections in which elements can only be added to one end and you can only remove elements from the other end. Think of a line to buy tickets. When people arrive they go to the end of the line; the person at the head of the line is the next person to be served. This is called a first-in, first-out protocol (FIFO). Java has a Queue interface to support this abstract data type. Some Methods of the Queue Interface Method Description boolean add( E element ) Adds element to the rear of the queue and returns true if room is available or returns false otherwise. boolean isempty() Returns true if the queue is empty. E peek() Returns the object at the front of the queue or null if the queue is empty. E remove() Precondition: the queue is not empty. Removes and returns the object at the front of the queue. int size() Returns the number of objects in the queue. The LinkedList class implements the Queue interface. Page 5
By the way. The Queue interface defines some methods that do similar things, but one set of methods throws exceptions when things go bad, the other methods return special values. Type of Operation Throws Exception Returns special value Insert add(e) offer(e) Remove remove() poll() Examine element() peek() There are different queues and some use one set over the other. Here s very short program that uses a Queue. import java.util.*; public class Example { public static void main(string[] args) { Queue<String> q = new LinkedList<String>(); q.add( "A" ); q.add( "B" ); // prints A // prints B Program. Given a queue of strings, write a method that will print the contents of the queue without changing the order of the elements. Write a second method that remove elements of the queue that match another string, with changing the order of the remaining elements. This is program 3.03 on repl.it Program. Ok. Bear with me on this one. The idea is to model cars stopping at a traffic light. There is a Car class and in the main method cars are added, modified, and removed from a queue in response to various inputs/events. Everything is speeded up. For example, in one test run, I had the traffic light on for 4 seconds and off for 4 seconds and a new car show up every 2 seconds. After 60 seconds there were 10 cars backed up at the light. Car Class Instance Variables and Constructor final int RESPONSE_TIME How many seconds before the driver responds to the light going green. int timetogo How many seconds until the driver is awake and will drive. When the light goes green, these values are decremented every second the light is green. When the light goes red, these are reset to RESPONSE_TIME int spot This is where they are in line. 1 is in front. int speed This determines how many spots they may advance when the light goes green (given those spots are not occupied). Car( int distance) distance initializes spot. RESPONSE_TIME is random [1,3] timetogo is initialized to RESPONSE_TIME speed is random [1,3] Page 6
Car Class Methods Comments void moveforward( int x ) x is the next available spot. If the driver is awake, they will move as far as their speed lets them, but not past x void roll() The car moves forward one spot. The driver does not have be awake. The idea is this method is only called when (1) the spot in front of this car is empty and (2) the light is red. int getspot() return spot; void timepasses() Decrements timetogo by one. This is called when the light is green. timetogo may be negative. boolean readytogo() return timetogo <= 0; void resettimetogo() timetogo = RESPONSE_TIME; String tostring() return timetogo + "_" + spot; Please do not change the Car class. Here is a quick outline of the main method. The user says how long the light is on and off. Also, how often new cars are added to the queue. The simulation last 60 seconds. Not 60 actual seconds, 60 iterations where each iteration represents a second. The light is green at the start. In each iteration o add a car to the queue if it s time o change the light to change from red to green or green to red when appropriate. When it turns red, call the resettimetogo for every car in the queue o if it s green call the timepasses method for each car in the queue call the moveforward method for each car in the queue remove the car at the head of the queue if its spot is less than 1 o if it s red, call the roll method for each car in the queue when the spot in front is open (do that by checking what spot the car in front of it is in). o print out the time, whether the light is on or off, and call the tostring method for each car in the queue and print that o pause the program for 300 milliseconds. To the right is one possible result. The first column is the time. true means the light is on. Each number pair is a car. The first number is how more time until the driver wakes up. The second number is the car s spot in line. In the loop, a car is added and then may act and then data is printed. For instance, at end of time 0, 2_1 means that car will need 2 more seconds to wake up and they are at spot 1. At the end of time 2, the first has left the second driver is also very slow to respond and is still in spot 2. Page 7
Priority Queues are like queues in that items are added to the end of the queue and removed from the head of the queue. They are different in that more important elements go to the head of the line. For example, imagine an emergency room at a hospital. As people arrive they get in line and wait their turn. However, if someone comes in with a life-threatening problem, they go to the head of the line. Java has a PriorityQueue class that implements the Queue interface. The default constructor places objects in the queue according to their natural order which is defined by how they implement the Comparable interface (i.e. the compareto method). The item with the smallest value is removed first. For example, in the String class A is less than B so it will go to the head of the queue. import java.util.*; public class Example { public static void main(string[] args) { PriorityQueue<String> q = new PriorityQueue<String>(); q.add( "B" ); q.add( "A" ); q.add( "H" ); q.add( "C" ); // prints A // prints B // prints C // prints H Note. Suppose you have a class named Dog that does not implement Comparable. The following code will compile: PriorityQueue<Dog> q = new PriorityQueue<Dog>(); Dog d1 = new Dog( "hank" ); Dog d2 = new Dog( "bob" ); q.add( d1 ); q.add( d2 ); However, when you try to run it you will get the following runtime error: java.lang.classcastexception: Dog cannot be cast to java.lang.comparable Page 8
Queues and Priority Queues 24. What is displayed? Queue<Integer> q = new LinkedList<Integer>(); q.add( 14 ); q.add( 5 ); q.add( 12 ); 25. What is displayed? PriorityQueue<Integer> q = new PriorityQueue<Integer>(); q.add( 14 ); q.add( 5 ); q.add( 12 ); 26. What is displayed? Queue<String> q = new LinkedList<String>(); q.add( "M" ); q.add( "G" ); q.add( "K" ); while (! q.isempty() ) 27. What is displayed? PriorityQueue<String> q = new PriorityQueue<String>(); q.add( "M" ); q.add( "G" ); q.add( "K" ); while (! q.isempty() ) 28. What is displayed? PriorityQueue<String> q = new PriorityQueue<String>(); q.add( "apple" ); q.add( "a" ); q.add( "xray" ); q.add( "Adam" ); q.add( "ZOO!" ); while (! q.isempty() ) The ASCII code for A is 65. The ASCII code for a is 97. Program. This program models an emergency room and it has three classes. The Patient class obviously represents patients in a hospital. Each patient has a condition ranked from 1 (worst) to 10 (not too bad). The ERqueue class represents the ER room treating patients in order of worst to best condition. The main method creates an ERqueue objects and adds an array of Patients to the ERqueue object. Methods are called. Results are printed. Go to repl.it for more details. Page 9