Uploaded by Mustafa Magdy

Lecture 5 stack

advertisement
Data Structures via C++
Lecture 7:
Stacks
Dr. Shaker El-Sappagh
Benha University
Faculty of Computers and Informatics
Department of Information Systems
2017
What is a stack?
- A container is an ADT that can hold multiple objects and
structure them in a different way.
- Stack is a container that stores items in LIFO order.
- Items are added and removed from the same end (head).
- Stack reverses the order of items.
- Stack has these operations:
1. The push operation adds elements to the stack,
2. the pop operation retrieve elements,
3. the isEmpty operation to check if the stack is empty,
4. the top return the top element without modifying the
stack.
Implementing the stack by array
- Stack stores elements of the same type (homogeneous), so array
data structure is suitable.
- The two ways of pushing:
1. Fixing one position (index 0) as the top of the stack.
What is the problem? What is the cost for push and pop? O(n)
0
1
2
3
4
5
?
?
?
?
?
?
push (‘a’)
0
1
2
3
4
5
a
?
?
?
?
?
push (‘b’)
0
1
2
3
4
5
b
a
?
?
?
?
Implementing the stack by array
2. Let the top of the stack flow up and down by pushing at the end
of the stack.
Set the top as an integer. Set top= -1 for empty stack. For each push,
top++. For each pop, top--.
0
1
2
3
4
5
top = -1
?
?
push (‘a’)
?
?
?
?
top = 0
0 a
1 ?
2 ?
3 ?
4 ?
5 ?
push (‘b’)
0
1
2
3
4
5
top = 1
a
b
?
?
?
?
Implementing the stack by array
C++ implementation of the stack:
- The stackArray is an array to store maxStackSize elements.
- The topIndex stores the top of stack. Initially, topIndex = -1.
- In push operation: topIndex ++, stackArray [topIndex]= new item.
- As a start, items are of type char.
- In pop operation: return stackArray [topIndex], topIndex --.
- The isEmpty operation check if topIndex = -1.
- The isFull operation check if topIndex = maxStackSize - 1
Array based stack
const int maxStackSize = 1000;
typedef char StackElementType;
class Stack {
public:
Stack();
void push(StackElementType item);
StackElementType pop();
StackElementType top();
bool isEmpty();
private:
StackElementType stackArray[maxStackSize];
int topIndex;
};
Array based stack
Stack::Stack()
{
topIndex = -1;
}
void Stack::push(StackElementType item)
{
++topIndex;
// ensure array bounds not exceeded
assert(topIndex < maxStackSize);
stackArray[topIndex] = item;
}
StackElementType Stack::pop()
{
// ensure array bounds not exceeded
assert(topIndex >= 0);
int returnIndex(topIndex);
--topIndex;
return stackArray[returnIndex];
}
Array based stack
StackElementType Stack::top()
{
// ensure array bounds not exceeded
assert(topIndex >= 0);
return stackArray[topIndex];
}
bool Stack::isEmpty()
{
return bool(topIndex == -1);
}
Creating generic classes with templates
- Generic classes can be defined by typedef and template.
- In a templated class, the type stored by the class becomes a
parameter to the class.
- How to define a template class?
template <class …(your type)…..>
class …(class name)…
{
}
Example:
template <class stackElementType>
class stack
{
}
Creating generic classes with templates
- How to define a template constructor?
template < class …(your type)….. > className <(your type)> :: classname
{
}
Example:
template <class stackElementType> stack < stackElementType> :: stack
{
}
Creating generic classes with templates
- How to define a template function?
template < class …(your type)….. > return type className <(your
function_name (parameter list)
type)>
::
{
…
}
Example:
template <class stackElementType> void stack < stackElementType> :: push
(stackElementType item)
{
…
}
Creating generic classes with templates
- Template class defines a family of classes.
- From template of stack class, we can define a stack of int,
char, string, etc. These are instances of the stack template.
- The definition is in the main function or when we define
objects.
- Example: stack < int > stack_Object; or stack<int> stack_Object
- Compilation of template class create a problem with linker
because it is impossible for compiler to create the object file
form template class because it does not know how much
space for the generic variable (as in typedef). Platform
dependent.
- All of stack C++ operations are implemented regularly.
const int maxStackSize = 1000;
template < class StackElementType >
class Stack {
public:
Stack();
void push(StackElementType item);
StackElementType pop();
StackElementType top();
bool isEmpty();
bool isFull();
private:
StackElementType stackArray[maxStackSize];
int topIndex;
};
Code template
Code template
template < class StackElementType > Stack < StackElementType >
::Stack()
{
topIndex = -1;
}
template < class StackElementType > void Stack < StackElementType>
::push(StackElementType item)
{
++topIndex;
// ensure array bounds not exceeded
assert(topIndex < maxStackSize);
stackArray[topIndex] = item;
}
Code template
template < class StackElementType > StackElementType Stack < StackElementType >
::pop()
{
// ensure array bounds not exceeded
assert(topIndex >= 0);
int returnIndex(topIndex);
--topIndex;
return stackArray[returnIndex];
}
template < class StackElementType > StackElementType Stack < StackElementType >
::top()
{
assert(topIndex >= 0);
return stackArray[topIndex];
}
Code template
template < class StackElementType > bool Stack < StackElementType>
::isEmpty()
{
return bool(topIndex == -1);
}
template < class StackElementType > bool Stack < StackElementType >
::isFull()
{
return topIndex == maxStackSize - 1;
}
Implemented the stack: Dynamic linked list
- Array based implementation of stack has the same linear
array drawbacks.
- Linked list based implementation can solve these
problems.
- In the linked list, the functions’ interfaces are the same as
in regular array, but the private part is different.
- The LIFO nature of stack makes all push and pop done at
the head of the linked list, so one pointed is required.
template < class StackElementType >
class Stack {
public:
Stack();
void push(StackElementType e);
StackElementType pop();
StackElementType top();
bool isEmpty();
private:
struct Node;
typedef Node * Link;
struct Node {
StackElementType data;
Link next;
};
Link head;
};
Code linked list
Code linked list
template < class StackElementType> Stack < StackElementType >
::Stack()
{
head = 0;
}
template < class StackElementType > void Stack < StackElementType >
::push(StackElementType e)
{
Link addedNode = new Node;
assert(addedNode);
addedNode->data = e;
addedNode->next = head;
head = addedNode;
}
Code linked list
template < class StackElementType > StackElementType Stack < StackElementType >
::pop()
{
assert(head);
StackElementType result;
Link delNode;
delnode= head;
result = head->data;
head = head->next;
delete delnode;
return result;
}
Code linked list
template < class StackElementType > StackElementType Stack < StackElementType >
::top()
{
assert(head);
return head->data;
}
template < class StackElementType > bool Stack < StackElementType >
::isempty()
{
return head==0;
}
Example: Calculator
- Mathematical expressions can be written using prefix, infix, and postfix (Reverse
Polish Notation).
- The infix form of writing arithmetic operation is ambiguous as in 3-4-5*3.
- Solution is to use parentheses and precedence rules.
1. Parentheses first
2. Inside parentheses Multiply and division first then addition and subtraction
3. For a sequence of operators of equal precedence from left to right.
- Reverse Polish Notation (RPN) is easier to implement because it has no Rules.
- How to convert the infix form into postfix form?
- The evaluation of postfix format can be done by stack data structure:
Each time an operand is encountered, it is pushed into the stack; upon reaching an operator, the
last two operands are popped off the stack, and the operation is applied.
The top of the stack is the right hand operand and the second item is the left hand operand.
Evaluation of an RPN expression using a stack
expression:
stack:
34-53*-
3
34-53*-
34-53*-
3 - 4 = -1
4
3
expression:
stack:
34-53*-
5
-1
34-53*-
3
5
34-53*-
5*3=
15
-1
-1
expression:
stack:
34-53*-
-1 -15 = -16
Final result on top of stack
Example: Calculator
- To evaluate RPN expressions, we need a way to break the input string into operands and
operators.
- The input “3 4 – 5 3 * -” has (operand) 3, (operand) 4, (operator) -, (operand) 5, (operand) 3,
(operator) *, (operator) -.
- Each input is called a token.
- We can have
enum tokenType {operandToken, operatorToken, eolToken, eofToken, badToken}
enum operatorType {none, add, subtract, multiply, divide}
- The process of breaking up the string is called lexical analysis or tokenization.
- These all tokenization operations can be collected in Token class. (Homework)
class Token {
Public:
tokenType nextToken (); // get next token stream
operatorType getOperator (); // return operator
double getOperand (); // return operand
Assignment
Using a Stack, trace the evaluation of the following RPN expressions:
7 3 15 * +
12 10 5 / 12 3 - * +
111111+-*/+
Assignment
Write a program that uses a stack to test for balanced bracket pairs. The input strings,
all consisting of a single line less than 80 characters long, will include 4 types of
brackets:
{}, [], <>, ()
In order for an expression to be parenthesized properly, each lef bracket must be
matched with a right bracket of the same type. For example, the expression:
{A [B <C> <D> (E) F] (G)}
is correct, but
{A[B}]
is not, because the ‘}’ after ‘B’ pairs with a ‘[‘, which is not allowed.
Your program will read strings and determine whether or not they are properly
parenthesized, until it gets a string starting with a period (‘.’) at which point it
will terminate. You will need to instantiate a Stack of char.
Thanks
Download