Conversion from infix to postfix

In the previous lecture, we discussed the way to convert an infix notation into a postfix notation. During the process of conversion, we saw that there may be need of parenthesis in the infix especially at the times when we want to give a higher precedence to an operator of lower precedence. For example, if there is a + operator

data structures  Conversion from infix to postfix

a

b

around th operands rator. Su ere is t
wh t ve he
ex be ten
of sio at i
de rn es fo
fun t unde
co inf pressi
ho ithm s t
exo ca ut the prolumn sym

p

postfix column has the postfix string (expression) after each step and the stack is used to put the operators on it. The whole process of converting the infix notation into a postfix is given in the following table. This process of conversion is completed in eight steps. Each of the rows of the table depicts one step. Step No. Symbol Postfix Stack 1 ( ( 2 A A ( 3 + A (+ 4 B AB (+ 5 ) AB+ 6 * AB+ * 7 C AB+C * 8 AB+C*

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

c

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

e

before the multiplicat

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. 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 c

lana a templa

hen a programmer uses this ftion or class, the ge

, needed to be ud the template function or in the tem

ct othemplate class.

plat

be used in our program b

late class f

ate <class T>

{ public: Stack(); int empty(void); // 1=true, 0=false int push(T &); // 1=successful,0=stack overflow T pop(void);

~Stack();

int top; T* nodes; }; In the above code the line template <class T>

shows that we are going to write a template. Here T is a variable name for generic data type. We can use any other name but generally T is used (T evolves from template). A data type will replace this T wheneve

Then we declare member functions of the class. To begin with, there is a constructor of the class with the same name as that of the class i.e. Stack. It is follo

e

int push(T

We have been using the data (element) type int or some other data ty

fu

that the function takes a

use a proper data typ

replace T. There are

value which is of type T. The peek

(s

In the private sectio

point to the top of th

all

Ine definiti

stack class in the program, we will replace

Im

Now we will see how

co

#in

#

#include “Stack.h”

#define MAXSTACKSIZE

telate <class T>

Stack<T>::Sta

{

top = -1;

nodes = new T[MAXS

}

template <

Stack<T>::~Stack()

{

delete

}

tem

int Stack<T>::empty

{

return 0;

}

template <

int Stack<T>::push(T& x)

{

if(

{

nodes

cout << "stack overflow in push.\n"; return 0; }

te

T Stack<T>::pop(void)

{

T x; if( !empty() )

x = nodes[top--];

return x;

cout << “stack underflow in pop.\n”; return x; } In this code, we include different files in which one is Stack.h , written earlier to declare the template class Stack. We have defined a constant size of the stack to 50 by writing the line

#define MAXSTACKSIZE 50 Next is the definition of the constructor. Here before the signature of the constructor function, we have written template <class T>

Stack<T> :: Stack() ;

This means that we are writing a

written. As

with the class name before the access sp

class. Then the

value top and allocate m

MAXSASIZE of

pertin to

Similarly we define the destructor ~Stack, w

nodeshen there

pop(). We define all the m

m

type can be used. The function empty() returns a Boolean parameter. It returns 1 that means TRUE if the stack is empty i.e. if top is less than 0. Otherwise it returns zero i.e. FALSE if the stack is not empty. We define the push function as under int Stack<T>:

{ if( top < MAXSTACKSIZE ) {

return 1; } cout << “stack overflow in push.\n”; return 0;

This function takes an argument

sta

means there is space available in the stack. Then it puts the elem

retrns 1, indicating that pu

me

put on the stack.

Ne

type T. In the body of the function, we d

the stack is empty. If it is not empty, we pop the value from the top in varia

return it.

Now let’s see the use of this template stack. Here we write the main program in a

se

F

implementation of the stack.

#include “Stack.cpp” int main(int argc, char *argv[]) { Stack<int> intstack;

Stack<char> charsta

int x=10,

c c=’C', d=’D';

intstack.push(x); intstack.push(y); cout << “intstack: ” << intstack.pop() << “, ” << intstack.pop() << “\n”; charstack.push(c); charstack.push(d); cout << “charstack: ” << charstack.pop() << “, ” << charstack.pop() << “\n”; }

In the above code, consider the line Stack <int> intstack ; This line means that while creating an object intstack of Stack, the generic data type T should be replaced by the type int, In other words, it will be a stack for integers. The compiler will replace T with int wherever it exists in the code, providing a version of code with data type int. The compiler does this automatically. Similarly the next line

Stack <char> charstack ;

c

It shows that it

version of code

c

the template class. To demonstrate the implementation of Stack, we declare two variables of type int and two of type char. Then we push and pop these variables on and from the proper stack. We push the int values on the intstack (which we have created for int data type). The values of type other than int on the stack intstack can not be pushed as we have created it to store the int data type. And then we poop these values from the stack and show on the screen. Similarly we push the char values on the charstack (a stack to store char values) before displaying these values on the screen with the help of the pop method to get these values from the stack. Now we have the three files of our code i.e. stack.h, stack.cpp and main.cpp. Having these files in the same directory, we compile the main file (main.cpp) and execute it. Following is the output of the above program. intstack: 10, 20 charstack: C, D In the above example, we create two objects of Stack to use for two different data types. The compiler automatically provides us two versions of the template code, one for int and the other for char using the same code, written as template. So it is only due to the use of the template utility, provided by the C++ language only. No other language including C provides this utility of templates. If we write this program in C, the code of the functions of Stack has to be written repeatedly for each da

S

in templates, a programmer roduces the version of the co

p

stack by using array. It can also be implemented with the linked list. The use of array or linked list does not matter here. The implementation of the stack remains the same. The templates are so important that C++ provides a library in which a large number of common use functions are provided as templates. This library is a part of the official standard of C++. It is called STL i.e. Standard Template Library. As a library, it is a tested code base. We can use these templates and implement different concepts for our own data types. STL is an important code, pre-developed for us. It is available as a library. Different data structures like stack, queue etc is also there in STL. We can write programs by using them. But here in this course, our goal is t

data structures are, what is functioning and how can they be written? So we are writing and discussing the stack templates. You can use data structures from STL in the programming courses or in the professional life. You need not to write the stack or queue from the scratch you can simply use them in your programs from STL. Function Call Stack Let’s talk about another example of the stack. We know the functionality of the function calls. Whenever a programmer calls a function, he or she passes some arguments or parameters to the function. The function does work on these arguments and retu

re

lo

th re are variable
h . For thi
to ’s see ho
W compiler that actu
d
ill this funct on call. The co

th

fu

entries on the stack are the arguments of the function. The compiler pushes the last argument of the call list on the stack. Thus the last argument of the call list goes to the bottom of the stack after the return address. This is followed by the second last argument of the call list to be pushed on the stack. In this way, the first argument of the call list becomes the first element on the stack. This is shown in the following figure.

………

second argum

In

continues its execution form th

back here because when

addero thstack which it has push

conrooaat point in the program

function or program.

Cosi t fwingdf uniohat takes two integer argum

re

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. globl _i_avg _i_avg: movl 4(%esp), %eax

sarl $1, %eax

The first statement is globl_i_avg which shows that it’s 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), %

st

(i.e. top). The movl (move lon

4

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

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 t

S

a

fi

b

necessary to u

c

d

D

k

a

E

w

M

p

fo

of memory for their execution. Process 1 (browser)

data structures  Conversion from infix to postfix

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.

The following figure shows the internal memory organization of a process.

data structures  Conversion from infix to postfix

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.

VN:F [1.9.14_1148]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.14_1148]
Rating: 0 (from 0 votes)