Sei sulla pagina 1di 15

1 Stacks 1

1 Stacks

A stack is an ordered collection of items into which new items may be inserted and
from which old items may be deleted at one end, called the top of the stack. The
most important attribute of a stack is, that the last element inserted into a stack
is the 󰅬irst element deleted. For this reason a stack is sometimes called a last-in,
󰅬irst-out (or LIFO) list.
The two operations which can be made to a stack are given special names. When an
item is added to a stack, it is pushed onto the stack, and when an item is removed, it
is popped from the stack. Given a stack s, and an item i, performing the push(s,i)
operation adds the item i to the top of the stack s. Similarly, the operation pop(s)
removes the top elements and returns it as a function value.

1.1 Representing stacks in C

A stack in C may therefore be declared as a structure containing two objects: an


array to hold the elements of the stack, and an integer to indicate the position of
the current stack top within the array.
# ifndef STACK_H
# define STACK_H

const int stacksize = 100;

struct stack {
int top;
int items[ stacksize ];
};

void push(stack& s, int x);


int pop(stack& s);
int is_empty (stack& s);
int stacktop (stack& s);
void init_stack (stack& s);

# endif // ! STACK_H
Listing 1: Stack.h

The implementation of the various functions are written in Stack.cpp.


# include " Stack .h"
# include <iostream >

void push(stack& s, int x)


1 Stacks 2

{
if (s.top == stacksize - 1)
{
std :: cout << "\ nStack overflow ";
return ;
}

s.items [++s.top] = x;
}

int pop(stack& s)
{
if ( is_empty (s))
{
std :: cout << "\ nStack underflow ";
return 0;
}

return s.items[s.top --];


}

int is_empty (stack& s)


{
if (s.top == -1)
return true;
else
return false ;
}

int stacktop (stack& s)


{
if ( is_empty (s))
{
std :: cout << "\ nStack empty .";
return 0;
}

return s.items[s.top ];
}

void init_stack (stack& s)


{
s.top = -1;
for (int i = 0; i < stacksize ; i++)
s.items[i] = 0;
}
1 Stacks 3

Listing 2: Stack.cpp

The routine to test the functionality of stack is as follows.


# include <iostream >
# include " Stack .h"

int main ()
{
stack s;
init_stack (s);
int i;

push(s, 1);
push(s, 2);
push(s, 3);
push(s, 4);
push(s, 5);
push(s, 6);
push(s, 7);
push(s, 8);
push(s, 9);
push(s, 10);

i = pop(s); std :: cout << "\npop(s) = " << i;


i = pop(s); std :: cout << "\npop(s) = " << i;
i = pop(s); std :: cout << "\npop(s) = " << i;
i = pop(s); std :: cout << "\npop(s) = " << i;
i = pop(s); std :: cout << "\npop(s) = " << i;

push(s, 11);
i = pop(s); std :: cout << "\npop(s) = " << i;
i = pop(s); std :: cout << "\npop(s) = " << i;
i = pop(s); std :: cout << "\npop(s) = " << i;
i = pop(s); std :: cout << "\npop(s) = " << i;
i = pop(s); std :: cout << "\npop(s) = " << i;
i = pop(s); std :: cout << "\npop(s) = " << i;
i = pop(s); std :: cout << "\npop(s) = " << i;

push(s, 12);
push(s, 13);
i = stacktop (s); std :: cout << "\ nstacktop (s) = " << i;

std :: cin.clear ();


std :: cin.get ();
1 Stacks 4

return 0;
}
Listing 3: TestStack.cpp

Problem 1. Write an algorithm to determine if an input character string is of the


form
Problem.
x2y

where x is a string consisting of the binary digits 0 and 1, and where y is the reverse
of x(that is, if x=010110, y must equal 011010). At each point you may read only
the next character of the string.

Solution.
We read the input string character-by-character and push each character onto the
stack until a ’2’ is encountered, at which point we begin popping the elements off
the stack. If the element popped matches the next character read, the process con-
tinues until the end of string, else the string is marked invalid. If the stack is empty
at any time, before the end of the string, the string is marked invalid.
Additionally, I have modi󰅬ied the push() and pop() routines to include overflow
and underflow 󰅬lags.
# ifndef STACK_H
# define STACK_H

const int stacksize = 100;

struct stack {
int top;
char items[ stacksize ];
};

void push(stack& s, char x, int& overflow );


char pop(stack& s, int& underflow );
int is_empty (stack& s);
char stacktop (stack& s, int& underflow );
void init_stack (stack& s);

# endif // ! STACK_H
Listing 4: Stack.h

The function de󰅬initions are as follows -


1 Stacks 5

# include " Stack .h"


# include <iostream >

void push(stack& s, char x, int& overflow )


{
overflow = 0;

if (s.top == stacksize - 1)
{
std :: cout << "\ nStack overflow ";
overflow = 1;
return ;
}

s.items [++s.top] = x;
}

char pop(stack& s, int& underflow )


{
underflow = 0;
if ( is_empty (s))
{
std :: cout << "\ nStack underflow ";
underflow = 1;
return 0;
}

return s.items[s.top --];


}

int is_empty (stack& s)


{
if (s.top == -1)
return true;
else
return false ;
}

char stacktop (stack& s,int& underflow )


{
underflow = 0;
if ( is_empty (s))
{
std :: cout << "\ nStack empty .";
underflow = 1;
1 Stacks 6

return 0;
}

return s.items[s.top ];
}

void init_stack (stack& s)


{
s.top = -1;
for (int i = 0; i < stacksize -1; i++)
s.items[i] = ' ';
s.items[ stacksize - 1] = '\0';
}
Listing 5: Stack.cpp

I have tested four different strings.


# include <iostream >
# include " Stack .h"
# include <cstring >

int is_valid (char* str , int len);

int main ()
{
stack s;
init_stack (s);
int i, len = 0, valid = 0;

char s1[] = " 0101102011010 ";


char s2[] = " 01010121010 ";
char s3[] = " 01012101010 ";
char s4[] = " 0000011111 ";

len = strlen (s1);


valid = is_valid (s1 , len);

std :: cout << "\ns1: " << s1 << " is " << valid;

len = strlen (s2);


valid = is_valid (s2 , len);

std :: cout << "\ns2: " << s2 << " is " << valid;

len = strlen (s3);


valid = is_valid (s3 , len);
1 Stacks 7

std :: cout << "\ns3: " << s3 << " is " << valid;

len = strlen (s4);


valid = is_valid (s4 , len);

std :: cout << "\ns4: " << s4 << " is " << valid;

std :: cin.clear ();


std :: cin.get ();
return 0;
}

int is_valid (char* str , int len)


{
stack s;
int overflow = 0, underflow = 0;
init_stack (s);

bool mid_of_string_flag = false ;


int valid = 1;
char x;

for (int i = 0; i < len && valid; i++)


{

if ( mid_of_string_flag )
{
x = pop(s, underflow );
if (x != str[i] || underflow )
valid = 0;
}
else
{
if (str[i] == '2')
{
mid_of_string_flag = true;
continue ;
}
else
{
x = str[i];
push(s, x, overflow );

if ( overflow ) { break ; valid = 0; }


1 Stacks 8

}
}
}

if (! is_empty (s))
valid = 0;

return valid;
}
Listing 6: TestValidString1.cpp

Problem 2. Write an algorithm to determine if an input character string is of the


form

a 3 b 3 c 3...3 z

where each string a, b, . . . , z is of the form of the string de󰅬ined in problem (1).
Thus, a string is in the proper form, if it consists of any number of such strings
separated by the character ’3’. At each point you may read only the next character
of the string.

Solution.
The above solution is modi󰅬ied as follows. Each time the character ’3’ is read, the
stack must be empty. If the stack is not empty, the entire string is marked invalid.
int is_valid (char* str , int len)
{
stack s;
int overflow = 0, underflow = 0;
init_stack (s);

bool mid_of_string_flag = false ;


int valid = 1;
char x;

for (int i = 0; i < len && valid; i++)


{
if (str[i] == '3')
{
if (! is_empty (s))
{
valid = 0;
1 Stacks 9

break ;
}
mid_of_string_flag = false ;
overflow = 0; underflow = 0;
continue ;
}

if ( mid_of_string_flag )
{
x = pop(s, underflow );
if (x != str[i] || underflow )
valid = 0;
}
else
{
if (str[i] == '2')
{
mid_of_string_flag = true;
continue ;
}
else
{
x = str[i];
push(s, x, overflow );

if ( overflow ) { break ; valid = 0; }

}
}
}

if (! is_empty (s))
valid = 0;

return valid;
}
Listing 7: TestValidString2.cpp

Problem 3. Design an algorithm that checks for a valid algebraic expression such
as {x + (y − [a + b]) ∗ c − [(d + e)]}/(h − (j − k − [l − n]))). If one or more scopes
that have been opened have not been closed, the string is invalid.

Solution.
A stack may be used to keep track of the types of scope encountered. Whenever a
scope is opened, it is pushed onto the stack. When a closing bracket is encountered,
1 Stacks 10

we pop the stack and check whether the popped item corresponds to the scope
ender. If a match occurs, we continue. If it does not, the string is invalid. When
the end of the string is reached, the stack must be empty; otherwise one or more
scopes have been opened which have not been closed, and the string is invalid.
# include <iostream >
# include " Stack .h"
# include <cstring >

int is_valid (char* str , int len);

int main ()
{

int i, len = 0, valid = 0;


char s1[] = "{x+(y-[a+b])*c -[(d+e)]}/(h -(j -(k -[l-n])))"
;
char s2[] = "(a+b]";

len = strlen (s1);


valid = is_valid (s1 , len);

std :: cout << "\ nstring s1: " << s1 << "is " << valid;

len = strlen (s2);


valid = is_valid (s2 , len);

std :: cout << "\ nstring s2: " << s2 << "is " << valid;

std :: cin.clear ();


std :: cin.get ();
return 0;
}

int is_valid (char* str , int len)


{
stack s;
init_stack (s);
int overflow = 0, underflow = 0, valid =1;
int i = 0; char x;

while (i < len)


{
if (str[i] == '[' || str[i] == '{' || str[i] == '(')
{
x = str[i];
1 Stacks 11

push(s, x, overflow );
if ( overflow ) { valid = 0; break ; }
}

if (str[i] == ']' || str[i] == '}' || str[i] == ')')


{
x = pop(s, underflow );
if ( underflow ) { valid = 0; break ; }

if ((x == '[' && str[i] == ']') ||


(x == '{' && str[i] == '}') ||
(x == '(' && str[i] == ')'))
{
valid = 1;
}
else
{
valid = 0;
break ;
}
}
i++;
}

if (! is_empty (s))
valid = 0;

return valid;
}
Listing 8: TestValidString3.cpp

Problem 4. Design an algorithm that computes the result of a post󰅬ix expression.

Solution.
Each operator in a post󰅬ix string refers to the previous two operands in the string.
(Of course, one of these two operands may itself be the result of applying a previous
operator.) Suppose that each time we read an operand we push it onto a stack.
When we reach an operator, its operands will be the top two elements on the stack.
We can then pop these two elements, perform the indicated operation on them,
and push the result on the stack, so that it will be available for use as an operand
of the next operator.
double evaluate_postfix (char* str , int len)
{
stack operand_stack ;
1 Stacks 12

init_stack ( operand_stack );
int overflow = 0, underflow = 0, valid =1;
int i = 0; char symbol ;
double operand1 = 0, operand2 = 0, result =0;

while (i<len)
{
/*1. Read the next symbol from the postfix expression
.*/
symbol = str[i];

/*2a. If the character is operand , push it on the


stack */
if ( is_digit ( symbol ))
{
push( operand_stack , to_num ( symbol ),overflow );
}

/*2b. If the character is an operator , pop two


operands off
the stack , compute the expression , and push the
result on
the stack .*/
if ( symbol == '+' ||
symbol == '-' ||
symbol == '*' ||
symbol == '/' ||
symbol == '$')
{
operand2 = pop( operand_stack , underflow );
if( underflow ) { std :: cout << "Stack underflow
exception "; exit (1); }

operand1 = pop( operand_stack , underflow );


if ( underflow ) { std :: cout << " Stack underflow
exception "; exit (1); }

result = compute (symbol , operand1 , operand2 );

push( operand_stack , result , overflow );


}
i++;
}

result = pop( operand_stack , underflow );


return result ;
1 Stacks 13

int is_digit (char symbol )


{
return ( symbol >= '0' && symbol <= '9');
}

double compute (int op , double operand1 , double operand2 )


{
switch (op)
{
case '+': return ( operand1 + operand2 );
case '-': return ( operand1 - operand2 );
case '*': return ( operand1 * operand2 );
case '/': return ( operand1 / operand2 );
case '$': return (pow(operand1 , operand2 ));
default : std :: cout << " Illegal operation ";
exit (1);
}
}

double to_num (char x)


{
return (x - '0');
}
Listing 9: TestPostFix.cpp

Problem 5. Design an algorithm that converts an in󰅬ix expression(without paren-


thesis) to a post󰅬ix expression.

Here is an outline of the algorithm to convert an in󰅬ix string without parentheses


into a post󰅬ix string.
void to_postfix ( const char* infix_expr , char*
postfix_expr , int len)
{
stack operator_stack ;
init_stack ( operator_stack );
char operator1 , operator2 ;

int i = 0, j = 0, underflow = 0, overflow = 0;


char symbol ;

while (i < len)


{
1 Stacks 14

/*1. Read the next symbol from


the infix string .*/
symbol = infix_expr [i];

/*2a. If the symbol is an operand ,


output it to the postfix expression */
if ( is_digit ( symbol ))
postfix_expr [j++] = symbol ;

/*If the symbol is an operator ,


compare it to the top of the stack */
if ( symbol == '+' || symbol == '-' ||
symbol == '*' || symbol == '/' ||
symbol == '$')
{
operator2 = symbol ;

while (! is_empty ( operator_stack ) &&


precedes ( stacktop ( operator_stack , underflow ),
operator2 ))
{
operator1 = pop( operator_stack , underflow );
postfix_expr [j++] = operator1 ;
}

push( operator_stack , operator2 , overflow );


}
i++;
}

while (! is_empty ( operator_stack ))


{
postfix_expr [j++] = pop( operator_stack , underflow );
}

postfix_expr [j] = '\0';


}

int precedes (char operator1 , char operator2 )


{
int prcd , priority1 =0, priority2 =0;
if ( operator1 == '+' || operator1 == '-')
priority1 = 1;

if ( operator1 == '*' || operator1 == '/')


priority1 = 2;
1 Stacks 15

if ( operator1 == '$')
priority1 = 3;

if ( operator2 == '+' || operator2 == '-')


priority2 = 1;

if ( operator2 == '*' || operator2 == '/')


priority2 = 2;

if ( operator2 == '$')
priority2 = 3;

prcd = priority1 - priority2 ;

if ( operator1 == '$' && operator2 == '$')


prcd = -1;

if (prcd >= 0)
return true;
else
return false ;
}
Listing 10: ToPostFix.cpp

Note that at each point of the simulation, an operator on the stack has a lower
precedence than all the operators above it. This is because, the initially empty
stack trivially satis󰅬ies this condition, and an operator is pushed onto the stack
only if the operator currently on top of the stack has a lower precendence than
the incoming operator. Intuitively, the highest precedence operator in an in󰅬ix ex-
pression must 󰅬irst be converted to post󰅬ix, so that they can be treated as single
operands.
What modi󰅬ication must be made to this algorithm to accomodate parentheses?
The answer is surprisingly little.

Potrebbero piacerti anche