0% found this document useful (0 votes)
2 views

Abstract Data Type

Uploaded by

Pranav
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views

Abstract Data Type

Uploaded by

Pranav
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 10

NOTES -2 on STACK Data Structure for Mid Term test 2

PVR Murthy

Contents:
i.Abstract Data Type for STACK
ii.About implementing STACK using Python List
iii. Function call and Return Mechanism using Stack
#ABSTRACTION:
# The notion of abstraction is to distill a complicated system down to its
#most fundamental parts.
#Describing the parts of a system involves naming them and explaining their
#functionality.

#Applying the abstraction paradigm to the design of data structures gives


#rise to abstract data types(ADTs). An ADT is a mathematical model of a data
structure
#that specifies the type of data stored, the operations supported on them
# and the types of parameters of the operations.

#An ADT specifies what each operation does , but not how it does it.

#We will refer to the collective set of behaviours supported by an ADT as its
#public interface.

#Stack Abstract Data Type


#
# A STACK is an ABSTRACT DATA TYPE (ADT) such that an instance S supports
# the following two methods:

# S.push(e): Add element e to the top of stack S.


# S.pop(): Remove and return the top element from Stack S;
# an error occurs, if the stack is empty

What is the purpose of Class ArrayStack?


Class ArrayStack provides an implementation of the above mentioned Abstract
Data Type for data structure Stack. Recall that Stack is a Last In First Out data
structure.
Member names or identifiers of class ArrayStack:
_data
Note that _data is the name of a class member name and its data type is
Python list which is used to implement Stack data structure. Thus we have
Abstract data type for Stack and the ADT for Stack is realized or implemented
using _data which has list data type. ADT for Stack S specifies the operations
or methods S.Push( e ) and S.pop(e) as public interface and these methods or
operations are implemented using the methods
def push(self, e) and
def pop(self)
In the definitions of the methods of class ArrayStack, self is always provided as
a parameter and it represents object instance.
For example, (refer to Class ArrayStack below to understand the example
given below)
>> myStack=ArrayStack() # calls constructor of ArrayStack __init__(self)
which initializes stack to an empty stack (in the method __init__, this is
achieved by assigning empty list [] to _data ). myStack is an object instance of
class ArrayStack that is just created and initialized. Note that the statement
myStack = ArrayStack() is viewed as instantiation of class ArrayStack that
results in an instance of class ArrayStack being created. myStack is a reference
to the object.
myStack Has one slot for Empty List []
reference to _data of list
(reference) type

(Figure1: Object which is an instance of class ArrayStack)

The above diagram shows the result of the interpretation of the statement:
myStack = ArrayStack() .
An orbject instance of class Stack is created by the statement:
myStack = ArrayStack()
Python interpreter allocates space for an object instance of class ArrayStack
and initializes member names or identifiers or attributes of class ArrayStack.

>> myStack.push(“Ram”) # note that in the call to push(self,e) method


defined in class ArrayStack below, the actual argument corresponding to self is
not passed explicitly. The call is
myStack.push(“Ram”)
myStack corresponds to self , this object instance. The actual argument “Ram”
corresponds to the formal argument e.

myStack Has one slot for [“Ram”]


reference to _data of list
(reference) type

(Figure2:Diagram showing result of interpretation of the statement


myStack.push(“Ram” )
Definition push(self,e):
(Refer to class ArrayStack: below ).
def push(self,e):
self._data.append(e)
When the call myStack.push(self,e) is made, element e is appended to
myStack._data (e is appended to the list representation of Stack,
myStack._data ).

In the definition of push(self,e) in class ArrayStack below, the abstract


operation push(self,e) is achieved by appending element e to the _data of list
type which is used as the concrete representation of ADT Stack. Refer to
Python documentation (for example, python.org) to read details of append( e )
method on list. The built-in function _data.append(e) appends element e to
the list _data . For example,
Current state of _data is empty [].
Following execution of the statement _data.append(“Ram”),
new state of _data is [“Ram”].
Now consider the call
>> myStack.push(“Lakshman”).
Old state of stack : [“Ram”].
New State of stack: [“Ram”, “Lakshman”]

myStack Has one slot for [“Ram”, “Lakshman”]


reference to _data of list
(reference) type

(Figure 3)
Explicit parameter: self
Note that in the definition of class ArrayStack: , push(self,e) is the signature of
the method push; what this means is that self (current object instance) is
explicitly passed as a parameter. Note that self represents a reference to
current instance(object instantiated from the class).
Implicit parameter in call to push: myStack.push(“Ram”)
Note that in the call to push(self,e) method , only e is passed explicitly as in
myStack.push(“Ram”). A reference to the string “Ram” is passed as an
argument. Actual argument corresponding to formal parameter(argument) self
is not passed explicitly in the call. However, it may be noted that the call to
push is qualified by reference to the object ( myStack). Thus, push method is
executed on the instance(object) referred to by myStack.
Different Object instances and states of objects:
Multiple object instances may be created in a program:
myStack1 = ArrayStack()
myStack2 = ArrayStack()
The object referred to by reference myStack1 and the object referred to by
reference myStack2 have their own instance variables (_data in this case) and
their own respective states based on the calls through push(self,e) and pop().
(Question1: trace through the interpretation of the call to myStack.top() ;
definition of top() method can be found below in class ArrayQueue: use the
above diagram as a reference ; draw the diagram following the call to
myStack.top().
Question 2: Now trace through the call to myStack.pop() and draw the
diagram of the object).
The above discussion and questions indicate to us that an instance (object) of
class ArrayStack: is created to start with the interpretation of the statement
myStack = ArrayStack() which initializes myStack as hown in Figure 1 using the
method myStack.__init__(). The initial state of the object referred to by
myStack is shown in Figure 1. Subsequently, Figure 2 shows the state of the
object referred to by myStack, following the call to myStack.push(“Ram”).
Figure 3 shows the state of the object following the call to
myStack.push(“Lakshman”). Thus an instance (object) usually undergoes state
changes with each method call made. The object exists until the statement
myStack = None is interpreted by Python interpreter and subsequently,
Garbage Collector reclaims the memory occupied by the object to which
myStack no longer refers to (or points to).

STACK Data Structure:


A stack is a LIFO(Last In First Out) Data Structure.
Usually stacks are drawn as shown below:

Empty Stack: (TopOfStack may be initialized to an appropriate value to


indicate an empty stack , it may be -1, if Python list based implementation is
used as first element is stored at index 0; Whatever is the initial value choice,
push(self,e) and pop() methods need to deal with TopOfIndex consistently.
Note that class ArrayStack is not maintain TopOfStack in its object’s state).

Stack with One element:


(Basically, following a push operation; myStack.push(“Ram”)).
TopOfStack (not a member of class ArrayStack, though)

“Ram”

Stack with Two elements:


(Basically, following two push operations;
myStack.push(“Ram”) ; myStack.push(“Lakshman”) ).

TopOfStack

“Lakshman”

“Ram”

Question:
Indicate a sequence of operations on the above stack which transform the
stack with two elements present in it to an empty stack. How many such
sequences are possible?
NOTE:
What is just shown above is the way a stack is usually drawn and an accepted
way of showing stacks or illustrating stacks. However, in the notes, and the
text book, a stack may be shown in the form [“Ram”, “Lakshman”] but the
above is the preferred way.

class Empty(Exception):
pass
class ArrayStack:
# LIFO Stack implementation using Python List namely _data
def __init__(self):
#__init__ method serves as the constructor of the class(see page 71 of text
# book)

self._data = [] # initializing stack to empty state using concrete Python


#list

def __len__self(self):
#return number of elements in stack
return len(self._data)

def is_empty(self):
#boolean function that returns True, if stack is empty, else, False
return len(self._data)==0

def push(self,e):
#Push element e onto the top of the stack
self._data.append(e)

def top(self):
#return top element without removing it
# note the special feature of Python Lists, -1 index being used for
# last element; also note the condition on which an exception is raised
if self.is_empty():
raise Empty('Stack is empty')
return self._data[-1]
def pop(self):
#retrun top element , removing it from stack
# note that in both top and pop() methods, Python list related
# built-in functions are used (lists support pop() function, refer
# to python.org and raed documentation of list’s pop() function
if self.is_empty():
raise Empty('Stack is empty')
return self._data.pop()

Runtime stack maintained by Programming Language systems:


Main program unit :

call f(1)
… # Rm return address in main program unit
Function f(x):

Call g(5)
… # Rf return address in function f

return(some expression) # return statement in f

Function g(y):


return(some other expression)

Stack State: Stack Operations

[Rm] push(Rm)
[Rm , Rf ] push(Rf)
[Rm] pop()
[] pop()

You might also like