Beruflich Dokumente
Kultur Dokumente
Lecture No. 08
___________________________________________________________________
Data Structures
Lecture No. 08
Reading Material
Data Structures and Algorithm Analysis in C++
Chapter. 3
3.3.3
Summary
Page 1 of 12
Symbol
(
A
+
B
)
*
C
Postfix
A
A
AB
AB+
AB+
AB+C
AB+C*
Stack
(
(
(+
(+
*
*
First of all, there is the input symbol ((i.e. opening parenthesis). As this is not an
operand, it may be put on the stack. The next input symbol is A. Being an operand it
goes to the postfix string and the stack remains unchanged. Then there is + operator of
binary type. Moreover, there is one operand in the postfix string. We push this +
operator on the stack and it has to wait for its second operand. Now in the input
symbol, there is an operand B. We put his operand in the postfix string. Then after
this, there is the closing parenthesis ) in the input symbol. We know that the
presence of a closing parenthesis in the input means that an expression (within the
parentheses) has been completed. All of its operands and operators are present with in
the parentheses. As studied in the algorithm, we discard a closing parenthesis when it
comes in the input. Then the operators from the stack are popped up and put in the
postfix string. We also pop the opening parenthesis and discard it as we have no need
of opening as well as closing parenthesis in the postfix notation of an expression. This
process is carried out in the 5th row of the table. The + operator is put in the postfix
string. We also discard the opening parenthesis, as it is not needed in the postfix.
Now the next input symbol is *. We put this operator on the stack. There is one
operand for the * operator i.e. AB+. The * operator being a binary operator, has to
wait for the second operand. C is the Next input symbol that is an operand. We put it
in the postfix string. After this, the input string (expression) ends so we come out of
the loop. We check if there is any thing on the stack now? There is * operator in the
stack. We pop the operator and put it into the postfix string. This way, we get the
postfix form of the given infix expression that becomes AB+C*. In this postfix
expression, the + operator is before the * operator. So addition operation is done
before the multiplication. This is mainly due to the fact that in the infix expression,
we have put parentheses to give + operator the precedence higher than the * operator.
Note that there are no parentheses in the postfix form of the given infix expression.
Now we apply the evaluation algorithm on this postfix expression (i.e. AB+C*). The
two operands A and B, will go to the stack. Then operator + will pop these operands
from the stack, will add them and push the result back on the stack. This result
becomes an operand. Next C will go to the stack and after this * operator will pop
these two operands (result of addition and C). Their multiplication will lead to the
final result. The postfix notation is simple to evaluate as compared to the infix one. In
postfix, we need not to worry about what operation will be carried first. The operators
in this notation are in the order of evaluation. However, in the infix notation, we have
to force the precedence according to our requirement by putting parentheses in the
expression. With the help of a stack data structure, we can do the conversion and
evaluation of expressions easily.
Page 2 of 12
C++ Templates
We can use C++ templates for stack and other data structures. We have seen that stack
is used to store the operands while evaluating an expression. These operands may be
integers, floating points and even variables. We push and pop the operands to and
from the stack. In the conversion of an expression, a programmer uses the stack for
storing the operators like +, *, -, and / etc which are single characters. In both cases,
the functionality is the same. We push and pop things on and from the stack. At times,
we check if the stack is empty or not. Thus identical methods are employed while
using stack in evaluating and converting the expressions. However, there may be a
difference in the type of the elements (data) used in these cases. We may define a
stack, which can store different types of data but for the time being we are restricting
ourselves to the stack that can store elements of only one type. In C++ programming,
we will have to create two classes FloatStack and CharStack for operands and
operators respectively. These classes of stack have the same implementation. Thus, we
write the same code twice only with the difference of data type. Is there any method to
write the code for the stack once and then use it for different types of data? This
means is there any way that we can make a stack for storing integers, floating points,
characters or even objects with the same code written once. The language C++
provides us the facility of writing templates. A template can be understood with the
example of a factory that bakes biscuits. The factory may use flour, corn or starch as
ingredients of the product. But the process of baking biscuits is the same whatever
ingredients it uses. There is no difference in the machinery for producing biscuits with
different ingredients. So we call the factory as the template for the biscuits. Similarly
in C++ language, a template is a function or class that is written with a generic data
type. When a programmer uses this function or class, the generic data type is replaced
with the data type, needed to be used in the template function or in the template class.
We only give the data type of our choice while calling a template function or creating
an object of the template class. The compiler automatically creates a version of that
function or class with that specified data type. Thus if we write a template class for
stack, then later on we can use it for creating a stack for integers, floating points or
characters etc. So instead of writing code for different stacks of different data types,
we write one code as a template and reuse it for creating different stacks. We declare
the template class in a separate file in addition to the main program file. This file can
be used in our program by including it in that file. Following is the code of the
template class for stack. This is written in the file Stack.h.
template <class T>
class Stack
{
public:
Stack();
int empty(void);
// 1=true, 0=false
int push(T &);
// 1=successful,0=stack overflow
T pop(void);
T peek(void);
~Stack();
private:
int top;
T* nodes;
};
Page 3 of 12
Implementation
Now we will see how to implement this stack class in our program. Following is the
code of the program. We save this code in the file named Stack.cpp.
#include <iostream.h>
#include <stdlib.h>
#include "Stack.h"
#define MAXSTACKSIZE 50
template <class T>
Stack<T>::Stack()
{
top = -1;
nodes = new T[MAXSTACKSIZE];
}
template <class T>
Stack<T>::~Stack()
{
delete nodes;
}
Page 4 of 12
second argument
first argument
top ------> return address
In the calling function, after the execution of the function called, the program
continues its execution form the next line after the function call. The control comes
back here because when the execution of the function ends the compiler pops the
address from the stack which it has pushed when the function call was made. Thus the
control goes at that point in the program and the execution continues in the calling
function or program.
Consider the following code of a function that takes two integer arguments a, b and
returns the average of these numbers.
int i_avg (int a, int b)
{
return (a + b) / 2;
}
To understand the use of stack, look at the assembly language code of the above
function that is written as under.
Page 8 of 12
The first statement is globl_i_avg which shows that its a global function that can be
called by other functions or programs. After it, there is a label, written as _i_avg:
The next statement is movl 4(%esp), %eax. Here in this statement, there is the use of
stack. Here esp is a register in assembly language that is now a stack pointer for us
(i.e. top). The movl (move long) takes offset 4 from top (4 is number of bytes, we use
4 bytes as in C++ an integer is of 4 bytes.) that means after 4 bytes from the top in the
stack it gets the value and put it in the eax register. We know that the compiler pushes
the arguments of the function in reverse order on the stack. And pushes return address
at the end. Thus the order of stack will be that on the top will be the return address
and immediately after it will be the first argument. Here in the assembly code
generated by the compiler, the compiler pops first argument from offset 4 and puts it
in eax register. The next statement is
addl 8(%esp), %eax
The addl takes offset 8 from the stack pointer that is second argument and adds it to
eax. Thus in the previous two statements, the compiler got the first argument i.e. a
from the stack and the second argument b from the stack, added them before putting
the result in eax. The next statement
sarl $1, %eax
is the division statement of assembly language. This statement divides the value in
eax by 2 and thus eax has the resultant value. The last statement i.e. ret, returns the
value on the top of the stack to the caller function.
So we have seen the use of stack in the execution of a function and how the arguments
are passed to the function, how the functions return its return value and finally how
the control goes back to the caller function .All this process is executed by using a
stack. All the things about the functionality of the function calls are necessary to
understand as these will be needed while going to write our own compilers. We will
read this in the compilers course. The whole process we have discussed about the use
of stack in function calling is known as run time environment.
Different data structures are also used in run time environment of the computer. We
know that an executable program while in run, is loaded in the memory and becomes
a process. This process is given a block of memory which it uses during its execution.
Even the operating system, in which we are working, itself takes memory. Suppose
we are running many programs simultaneously, which for example include browser,
MS Word, Excel and dev-C++. We can also run programs written by us. Every
program which we run takes a block of memory and becomes a process. The
following figure shows a part of memory in which different programs occupy a block
of memory for their execution.
Page 9 of 12
Process 1
(browser)
Process 3
(Word)
Process 4
(Excel)
Process 2
(Dev-C++)
Windows Os
We can also see the details of all the programs running at a specific time. If we press
the key combination Ctrl-Alt-Del, there appears a window task manager on the
screen. Following is the figure of the task manager. In the figure, there are many
columns i.e. PID (process ID), CPU, CPU time, Memory usage, page faults, I/O
Reads, I/O Writes, I/O Read Bytes. These all things we will read in the course of
Operating Systems in detail.
Page 10 of 12
Here the thing of our interest is the first, second and fifth column. These columns are
Image Name, PID and Mem Usage (i.e. memory usage). Now look at the row where
explorer.exe is written in the first column. The process ID (PID) of it is 888 and
memory usage is 4696K. This means that the process size of explorer.exe in the
memory is 4696 Kilo Bytes (KB). All the processes in the first column of the task
manager are present in the memory of the computer at that time. The column Image
name has the names of the processes being executed. These have extension .exe but
there may be other executable programs that have extension other than .exe.
Page 11 of 12
Process 1
(browser)
Code
Process 3
(Word)
Static data
Process 4
(Excel)
Stack
Process 2
(Dev-C++)
Windows Os
Heap
This shows that the first part of the memory of the process is for the code. This is the
code generated by the compiler of C++, JAVA or VB etc with respect to the language
in which the actual code was written. Then the static data of the program occupies the
memory. This holds the global variables and different variables of objects. Then in the
memory of the process, there is stack. After it there is heap. The stack and heap are
used in function calls. We have discussed the use of stack in function calls. When we
allocate memory dynamically in our programs, it is allocated from the heap. The use
of heap is a topic related to some programming course or to the operating system
course.
Page 12 of 12