Stack and Queue-class
-
Upload
rising-shinee -
Category
Documents
-
view
221 -
download
1
description
Transcript of Stack and Queue-class
STACK and QUEUE
Objectives
• Introduction– Define a stack– Define a queue
• Operations– Stack operations– Queue operations
• Java interfaces– PureStack interface– PureQueue interface
• Implementations• Array-based
implementations• Applications
– Stack applications– Queue applications
What is a stack?
• A stack is a finite sequence of elements in which the only element that can be removed is the element that was most recently inserted.
• A stack is a data structure that keeps objects in Last-In-First-Out (LIFO) order– Objects are added to the top of the stack– Only the top of the stack can be accessed
• Visualize this like a stack of paper (or plates)
Operations on a StackOperation Description
push Adds an element to the top of the stack
pop Removes an element from the top of the stack
peek Examines the element at the top of the stack
isEmpty Determines whether the stack is emkpty
size Determines the number of elements in the stack
• It is not legal to access any element other than the one that is the top of the stack!
Push and Pop
• Primary operations: Push and Pop• Push
– Add an element to the top of the stack• Pop
– Remove the element at the top of the stack
Atop
empty stack
top
top
top
push an element push another
A
B
pop
A
Stack Operations
1) push – add data onto the stack
2) Algorithm : - Increase top by 1 - Add new item into top location
Stack Operations
1) pop – remove data onto the stack
2) Algorithm : - Store the top data into a temporary storage - Decrease top by one
Stack Operations
1) stackEmpty – check whether the stack is empty or not
2) Algorithm : - Is top = -1 ? If yes, return true (stack is empty!)
Stack Operations
1) stackFull – check whether the stack is full or not
2) Algorithm : - Is top = stackSize -1 ? If yes, return true (stack is full!)
10
Stack Operations
Assume a simple stack for integers.Stack s = new Stack();s.push(12);s.push(4);s.push( s.top() + 2 );s.pop()s.push( s.top() );//what are contents of stack?
Stack Operations :
push operation pop operation
j
a
v
a
x
c
j a v a x c c x a v a j
OUTPUT
Print out contents of stack in reverse order.
Exercise
Show the output and the contents of stacks S and T(using diagrams)after each of the following sequence operations:
a. push(S,2);b. push(S,5);c. push(T,3);d. push(T,4);e. pop(topItem,S);f. System.out.println(topItem);g. getTop(topItem,T);h. System.out.println (topItem);i. push(S,topItem);j. push(S,5);k. pop(topItem,T);l. System.out.println (topItem);m. push(T,7);
Lab Exercise
Problem :Convert a decimal value to a binary form.
Instruction: Write a main() to accept a decimal value from the user. Convert the decimal value to its binary form. During the conversion, call the push() to push the binary value 1 or 0 on to the stack. Lastly call pop() repeatedly to pop the data out from the stack and display.
Interface
• A list of abstract methods and constants– must be public– constants must be declared as final static
• Abstract method is a method that does not have an implementation, i.e. it just consists of the header of the method:
return type method name (parameter list)
The PureStack Interface
public interface PureStack<E> { /** * Determines the number of elements in this * PureStack object. *
* @return the number of elements in this * PureStack object.
* */
int size();
/** * Determines if this PureStack object has no elements. * * @return true – if this PureStack object has no * elements; otherwise, return false. * */
boolean isEmpty(); /** * Inserts a specified element on the top of this * PureStack object. * * @param element – the element to be pushed. * */ void push (E element);
/** * Removes the top element from this PureStack object. * * @return – the element removed.
* @throws NoSuchElementException – if this PureStack * object is empty. */ E pop(); /** * Returns the top element on this PureStack object. * * @return – the element returned. * @throws NoSuchElementException – if this PureStack * object is empty. */ E peek(); } // interface PureStack
Generic Types
What is this <E> in the interface definition?• It represents a generic type
– For generality, we can define a class ( for interface) based on a generic type rather than as actual type
– Example: a Stack for object of type E• The actual type is known only when an application
program creates an object of that class• We can then create stacks of different types:
– stack<int> stackOfIntegers = new Stack<int>();– stack<String> stackOfString = new Stack<String>();
Implementing an Interface
One or more classes can implement an interface, perhaps differently
• A class implements the interface by providing the implementations (bodies) for each of the abstract methods
• Uses the reserved word implements followed by interface name
Stack implementation issues
• What do we need to implement a stack?
– A data structure (container) to hold the data elements
– Something to indicate the top of the stack
Implementation of Stacks
• Any list implementation could be used to implement a stack– Arrays (static: the size of stack is given initially)– Linked lists (dynamic: never become full)
• We will explore implementation based on array
Array Implementation of a Stack
• The container will be an array to hold the data elements– Data elements are kept contiguously at one end of the
array• The top of the stack will be indicated by its
position in the array (index)– Let’s assume that the bottom of the stack is at index 0– The top of the stack will be represented by an integer
variable that is the index on the next available slot in the array
Array Implementation of a Stack
s
4
……..
0 1 2 3 4 5 6
stack
top
A stack s with 4 elements
s
5
……..
0 1 2 3 4 5 6
stack
top
After pushing an element
Array Implementation of a StackAfter popping one element
s
4
……..
0 1 2 3 4 5 6
stack
top
After popping a second element
s
3
……..
0 1 2 3 4 5 6
stack
top
The ArrayPureStack Class
• The class ArrayPureStack implements the PureStack interface:
Public class ArrayPureStack <E> implements PureStack <E>
• Attributes (instance variables):
private E[] stack; //the container for the data private int size; // indicates the next open slot
The ArrayPureStack Class
• The array variable stack holds reference to objects– Their type is determined when the stack is
instantiated• The integer variable size represents the index of
the next available slot in the arrayExample: – initially size = 0, the first element is store at index 0– after the insertion, the size = 1, so the second element is
stored at index 1.
The ArrayPureStack ClassArrayPureStack Constructors:• Create an empty stack using default capacity
public ArrayPureStack(){ stack = (E[]) new Object[DEFAULT_CAPACITY]; size = 0; }
• Create an empty stack using the specified capacity public ArrayPureStack(){ stack = (E[]) new Object[initial_CAPACITY]; size = 0;}
Example of using Constructor to create a Stack of numbers
ArrayPureStack<Integer> s = new ArrayPureStack<Integer>(5);
s stack
size
? ? ? ? ?
0 1 2 3 4
Example: the same ArrayPureStack object after four items have been pushed on
s
4
stack
size
41 56 32 17 ?
0 1 2 3 4
s.push(41);s.push(56);s.push(32);s.push(17);
Example: the same ArrayPureStack object after two items have been pop out
s
2
stack
size
41 56 ? ? ?
0 1 2 3 4
s.pop();s.pop();
The ArrayPureStack Class
The push() operation• Adds the specified element to the top of the stack,
expanding the capacity of the stack array if necessary
public void push(E element){ if (size == stack.length) expandCapacity();
stack[size++]=element;}
Managing Capacity
• An array has a particular number of cell when it is created (its capacity), so array’s capacity is also the stack’s capacity
• What happens when we want to push a new element onto a stack that is full?– The push method could throw an exception– It could return status indicator (i.e. a boolean value true
or false, that indicates whether the push was successful or not)
– It could automatically expand the capacity of the array.
The ArrayPureStack Class
The expandCapacity() operation• To create a new array to store the contents of the
stack, with twice the capacity
public void expandCapacity(){ E[] larger = (E[]) new Object[stack.length * 2]; System.arraycopy(stack,0,larger,0,size); stack = larger;}
The ArrayPureStack Class
The pop() operation• Removes the element at the top of the stack and
returns a reference to it.
public E pop() { return data[--size];}
The ArrayPureStack Class
The size() operation• Returns the number of elements in the stack
public int size() { return size;}
The ArrayPureStack Class
The peek() operation• Returns a reference to the element at the top of the
stack, the element is not removed from the stack
public E peek() { return data[size-1];}
Stack Applications
Stack Applications
Used of stack in computing• Word Processors , editors
– To check expressions or string of text for matching parentheses / brackets
• i.e. if (a==b)
{ c=(d+e) * f; }– To implement undo operations
• Keeps track of the most recent operations
Stack Applications cont…
Used of stack in computing• Stack Calculators
– To convert an infix expression to postfix, to make evaluation easier
• i.e. Infix expression: a*b+c postfix expression: ab*c+
– To evaluate postfix expression
Stack Applications cont…
Used of stack in computing• Call stacks (Runtime stack)
– Used by runtime system when methods are invoked, for method call/return processing
• i.e. main method, calls method1 method1 call method2 method2 returns …
– Hold “call frame” which containing local variables, parameters, etc…
Stack Applications cont…
Used of stack in computing• Compilers
– To convert infix expressions to postfix, to make translation of a high-level language such as Java or C to a lower level language easier
– Focus more on this
Compilers
• Old compilers:Infix Machine language
– This gets messy because of parentheses.
• Newer compilers:Infix Postfix Machine language
Infix and Postfix notation
• In infix notation, an operator is placed between its operands.• In postfix notation, an operator is placed immediately after
its operands. Parentheses are not needed and not used, in postfix.
Infix Postfixa + b ab+a + b * c abc*+a * b + c ab*c+(a + b) * c ab+c*
Infix to Postfix Conversion The idea of converting infix to postfix using a stack:Example. Convert infix a + b * c to postfix abc*+.
We scan the input stream left to right, output each operand as they are scanned. The main idea is that when encountering an operator, it is pushed onto the stack if the stack is empty, or if it has a higher precedence than that of the stack top. Thus, the following chart demonstrates the snapshots of the input stream vs. the stack and the output during the conversion process:
next token stack output comments
(Initially) empty none a empty a always output operand+ + a push when stack emptyb + a b always output operand* + * a b push if higher precedencec + * a b c always output operand
(at end) empty a b c * + pop everything off stack
Another example: Convert infix a*(b + c)/d to postfix abc+*d/.next token stack output comments(Initially) empty none
a empty a output operand* * a push operator if stack empty( *( a always push (b *( ab output operand + *(+ ab push operator if stack top (c *(+ abc output operand ) * abc+ pop all operators until (/ / abc+* pop *, push /d / abc+*d output operand
(at end) empty abc+*d/ pop everything off stackNote that the token ( is pushed onto stack when scanned; once it is in the stack all operators are considered with a higher precedence against (. Also, we need to resolve operators with left or right-associative properties. For example, a+b+c means (a+b)+c but a^b^c means a^(b^c).
Infix to Postfix Conversion cont…
Infix to Postfix Conversion cont…We define the precedence levels of various operators including the parentheses, distinguishing whether the operators are currently inside the stack or they are incoming tokens.
operator tokens in-stack precedence in-coming precedence (ISP) (ICP)
) (N/A) (N/A) ^ 3 4*, / 2 2+, – 1 1( 0 4 $ –1 (N/A)
The idea is that when encountering an in-coming operator, pop all operators in the stack that have a higher or equal ISP than the ICP of the new operator, then push the new operator onto the stack. The initial stack is marked with a “bottom marker” $ with a –1 precedence, which serves as a control symbol.
Rules for converting the infix string: Starting from the left hand end, inspect each character of the string
1. if it’s an operand append it to the postfix string
2. if it’s a ‘(‘ push it on the stack
3. if it’s an operator if the stack is empty, push it on the stack else pop operators of greater or equal precedence and append them to the postfix string, stopping when a ‘(‘ is reached, an operator of lower precedence is reached, or the stack is empty; then push the operator on the stack
4. if it’s a ‘)’ pop operators off the stack, appending them to the postfix string, until a ‘(‘ is encountered and pop the ‘(‘ off the stack
5. when the end of the infix string is reached pop any remaining operators off the stack and append them to the postfix string
Infix to Postfix Conversion cont…
Infix to Postfix Conversion (continued)
An Example: 7-(2*3+5)*(8-4/2) 723*5+842/-*- Remaining Infix String char Stack Postfix String Rule Used
7-(2*3+5)*(8-4/2) empty null-(2*3+5)*(8-4/2) empty 7 1(2*3+5)*(8-4/2) - 7 32*3+5)*(8-4/2) -( 7 2*3+5)*(8-4/2) -( 72 13+5)*(8-4/2) -(* 72 3+5)*(8-4/2) -(* 723 35)*(8-4/2) -(+ 723* 3)*(8-4/2) -(+ 723*5 1*(8-4/2) - 723*5+ 4(8-4/2) -* 723*5+ 38-4/2) -*( 723*5+ 2-4/2) -*( 723*5+8 14/2) -*(- 723*5+8 3/2) -*(- 723*5+84 1
2) -*(-/ 723*5+84 3) -*(-/ 723*5+842 1null empty 723*5+842/-*- 4&5
create a stack and push the bottom-marker $ onto stack perform the following steps forever (until exit out of it)
set x = nextToken(E)if x = end-of-input
pop all operators off the stack and output (except the marker $)exit out of the loop
else if x = operand, output xelse if x = ‘)’
pop all operators off stack and output each until ‘(‘; pop ‘(‘ off but don’t output it
else pop all operators off stack as long as their ISP ICP(x)push x onto stack
Infix to Postfix Conversion Algorithm
Balanced Symbol Checking
• In processing programs and working with computer languages there are many instances when symbols must be balanced{ } , [ ] , ( )
A stack is useful for checking symbol balance. When a closing symbol is found it must match the most recent opening symbol of the same type.
Balancing Symbolsopeners [ ( { and closers ] ) }
public class A public static void main(String[ args System.out PRINTln( "Hello" ); for( int j = 0; j < 6 j++ ) j++ doub x = 0.0; inTeger j = 0; System.out.println( "Goodbye" ); }}
Java says 2 errors, but how many can you find?A.java:1: '{' expected.A.java:12: Unbalanced parentheses2 errors
Checks Balanced Symbols First
– Java's compiler apparently first checks to see if certain symbols are balanced [] {} ()
– It ignores others errors by making a run over the entire source code just looking for unbalanced symbols
– If it finds none, it will begin a new pass • starts reading character by character again
– Fix the unbalanced errors of the previous slide one by one to observe this behavior
• it probably uses a Stack and an algorithm like this
Algorithm for Balanced Symbol Checking
• Make an empty stack• read symbols until end of file
– if the symbol is an opening symbol push it onto the stack
– if it is a closing symbol do the following• if the stack is empty report an error• otherwise pop the stack. If the symbol popped does not
match the closing symbol report an error
• At the end of the file if the stack is not empty report an error
Example
Process these characters, which represent only the openers and closers in a short Java program: {{([])}}
As the first four characters are read — all openers —push each onto the stack
[ ( { {
Pop the first closerDo they match?
The next symbol read is a closer: ']'. Pop '[' and compare to ']'. Since they match, no error would be reported. The
stack would now look like this:
( { {
Still need to process ) } }
( matches )
Then ' )' is found, so pop the stack Since the top symbol '(' matches the closer ')', no
error needs to be reported. The stack now has two opening curly brakets
{ { Still need to process
} }
Pop last two. They match. All is okay
– The two remaining closing curly brakets would cause the two matching openers to be popped with no errors
– It is the last in first out nature of stacks that allows the first '{' to be associated with the last closer '}'.
When do errors occur?
¨ If a closer is found and the stack is empty, you could also report an error.- For example with}}, where the opening { was not
incorrectly typed, the stack has no openers.¨ If you process all symbols and the stack is not
empty, an error should be reported, - In the case of {{([])} there is a missing right curly
brace. Symbols are processed without error.- Except at the end, the stack should be empty. It is not
and an error gets reported.
Evaluating postfix expressions
– Stacks set up the evaluation of expressions.4 + 8 / 2 is different if evaluated left to right.
– Evaluating "infix" expressions is not easy.• So compilers convert what we write in infix into the
equivalent postfix expression.
– The expression 2 plus 2 in postfix 2 2 +– Postfix of 3-4-5*3 is 3 4 - 5 3 * -
Evaluation of Postfix Expressions• Easy to do with a stack• given a proper postfix expression:
– get the next token– if it is an operand push it onto the stack– else if it is an operator
• pop the stack for the right hand operand• pop the stack for the left hand operand• apply the operator to the two operands• push the result onto the stack
– when the expression has been exhausted the result is the top (and only element) of the stack
Evaluate 3 4 - 5 3 * -
s.push(3); s.push(4); right = s.pop(); // found operator - so popleft = s.pop();s.push(left - right); 3 - 4
– The stack now has one value -1 – The remainder of the expression: 5 3 * -
-1
3
4
Found operand so pushFound operand so pushFound operator so pop two values, apply operand, and push the result
Continue with 5 3 * -
s.push(5); s.push(3); right = s.pop(); left = s.pop();s.push(left * right); 5 * 3
– The Stack has 2 values– Only one token remains
15
5
3
-1
Found operand so pushFound operand so pushFound operator so pop two values, apply operand, and push the result
-1
Continue with -
left = s.pop(); // found operator -right = s.pop();s.push(left - right); -1 - 15
– The expression has been processed. – The value at the top of the stack is the value of the
expression is -16– Now evaluate 2 3 4 * 5 * -
15
-1
-16
Queue
Queue• A queue is a finite sequence of elements in which:
– Insertion occurs only at the back;– Deletion occurs only at the front.
• Queues provide First In First Out (FIFO) access to elements could also say Last In Last Out (LILO)
Can visualize a queue as a line of customers waiting for service
The next person to be served is the one who has waited the longest
New elements are placed at the end of the line
67
A Conceptual View of a Queue
Rear of Queue(or Tail)
Adding an Element Removing an Element
Front of Queue(or Head)
Queue Operations
1. Enqueue : Add an element to the tail of the queue
2. Dequeue : Remove the element at the head of the queue
3. Peek : Look at but do not remove the element at the head of the queue
Note: These are the standard queue operations. Java 1.5 has a queue interface which has operations with different names.
Enqueue and Dequeue
• Primary queue operations: Enqueue and Dequeue• Like check-out lines in a store, a queue has a front
and a back. • Enqueue
– Insert an element at the back of the queue• Dequeue
– Remove an element from the front of the queue
Insert (Enqueue)
Remove(Dequeue) rearfront
Enqueue and Dequeue
Enqueue “Matt”
Matt
Front Back
Enqueue “Andrew”
Matt
Front
Andrew
Back
Enqueue “Samira”
SamiraMatt
Front
Andrew
Back
Dequeue
Front
Andrew
Back
Samira
The PureQueue interface
public interface PureQueue<E> { // Returns the number of elements in this PureQueue
// object. int size( );
// Returns true if this PureQueue object has no // elements. boolean isEmpty( );
/** * Inserts a specified element at the back of this * PureQueue object. * * @param element – the element to be appended. */ void enqueue (E element);
/** * Removes the front element from this PureQueue * object. * * @return – the element removed. * @throws NoSuchElementException – if this * PureQueue object is empty. */ E dequeue();
/** * Returns the front element in this PureQueue * object. * * @return – the element returned. * * @throws NoSuchElementException – if * PureQueue object is empty. * */ E front(); } // interface PureQueue
75
Queue ExampleOperation Output Q enqueue(5) – (5)enqueue(3) – (5, 3)dequeue() 5 (3)enqueue(7) – (3, 7)dequeue() 3 (7)front() 7 (7)dequeue() 7 ()dequeue() “error” ()isEmpty() true ()enqueue(9) – (9)enqueue(7) – (9, 7)size() 2 (9, 7)enqueue(3) – (9, 7, 3)enqueue(5) – (9, 7, 3, 5)dequeue() 9 (7, 3, 5)
Implementation of Queue
There are many ways to implement a queue:1. Array2. Circular queue3. Linked List
Array implementation of queues cont…
• There are several different algorithms to implement Enqueue and Dequeue
• Naïve way– When enqueuing, the front index is always fixed
and the back index moves forward in the array.
front
back
Enqueue(3)
3
front
back
Enqueue(6)
3 6
front
back
Enqueue(9)
3 6 9
Array implementation of queues cont…
• Naïve way– When dequeuing, the element at the front of queue
is removed. Move or shift all the elements after it by one position. if size were 999, then 998 moves would be necessary (A bad algorithm for remove
Dequeue()
front
back
6 9
Dequeue() Dequeue()
front
back
9
back = -1
front
Array implementation of queues cont…
• Better way– When an item is enqueued, make the back index
move forward.
– When an item is dequeued, the front index moves by one element towards the back of the queue (thus removing the front item, so no copying to neighboring elements is needed).
Array implementation of queues
• A queue is a first in, first out (FIFO) data structure• This is accomplished by inserting at one end (the back)
and deleting from the other (the front)
• To insert: put new element in location 4, and set back to 4• To delete: take element from location 0, and set front to 1
17 23 97 44
0 1 2 3 4 5 6 7myQueue:
back = 3front = 0
Array implementation of queues cont…
• Notice how the array contents “crawl” to the right as elements are inserted and deleted
• This will be a problem after a while!
17 23 97 44 333After insertion:
23 97 44 333After deletion:
back = 4front = 1
17 23 97 44Initial queue:
back = 3front = 0
Circular arrays• We can treat the array holding the queue elements as
circular (joined at the ends)
44 55 11 22 33
0 1 2 3 4 5 6 7myQueue:
back = 1 front = 5
• Elements were added to this queue in the order 11, 22, 33, 44, 55, and will be removed in the same order
• Use: front = (front + 1) % myQueue.length;and: back = (back + 1) % myQueue.length;
Full and empty queues• If the queue were to become completely full, it would look
like this:
• If we were then to remove all eight elements, making the queue completely empty, it would look like this:
44 55 66 77 88 11 22 33
0 1 2 3 4 5 6 7myQueue:
rear = 4 front = 5
0 1 2 3 4 5 6 7myQueue:
rear = 4 front = 5
This is a problem! (same) –How to determine it is full or empty
Full and empty queues: solutions• Solution #1: Keep an additional variable
• Solution #2: Keep a gap between elements: consider the queue full when it has n-1 elements
44 55 66 77 88 11 22 33
0 1 2 3 4 5 6 7myQueue:
rear = 4 front = 5count = 8
44 55 66 77 11 22 33
0 1 2 3 4 5 6 7myQueue:
rear = 3 front = 5
85
Applications of Queues• Operating systems use queues to sequence tasks
waiting for a scarce resource– Printer queue– Tasks waiting for CPU
• Simulation of physical systems uses queues to simulate any ‘first-in first-out’ (FIFO) system– Supermarket checkouts– Tollbooths