Title: Stacks
1Stacks Queues
- ECE573 Data Structures and Algorithms
- Electrical and Computer Engineering Dept.
- Rutgers University
- http//www.cs.rutgers.edu/vchinni/dsa/
2ReviewCollection Data Structure Implementations
- Implementation of collection can be substituted
for arrays with linked list or vice versa with no
change to clients program - Exception Linked list implementation can add any
number of items - Linked list implementation
- Exchange flexibility for efficiency
- Most systems, system call to allocate memory is
relatively expensive - Pre-allocation in the array-based implementation
is generally more efficient - Also linked lists consume more memory space (less
mem efficient) - Study of data structures and algorithms will
enable you to make the implementation decision
which most closely matches your users specs
3PA1
Pre-and post-condition specifications cover it
/ Array implementation of a Collection / struct
t_Collection int item_cnt int max_items /
Not strictly necessary / int size / Needed by
FindInCollection / void items
Array of items which happen to be pointers We are
trying to hide this from users Some will write
void items
4PA1
assert calls have been added for the
pre-conditions
Collection ConsCollection(int max_items, int
item_size ) Collection c assert( max_items
gt 0 ) assert( item_size gt 0 ) c
(Collection)calloc( 1, sizeof(struct
t_Collection) ) c-gtitems (void
)calloc(max_items,sizeof(void )) c-gtsize
item_size c-gtmax_items max_items return
c
Calloc is used to dynamically allocate
memory One to allocate space for header
structure, other for array of item pointers
No error handling what if no mem available on
the heap for calloc? There is no treatment of
errors Need consistent strategy for detecting,
reporting and recovering from errors
5PA1
Compare blocks of memory byte by byte
void FindInCollection( Collection c, void key
) int i assert( c ! NULL ) assert( key
! NULL ) for(i0iltc-gtitem_cnti) if
(memcmp(ItemKey(c-gtitemsi),key,c-gtsize)0) r
eturn c-gtitemsi return NULL
6Stacks
- Stacks are a special form of collectionwith LIFO
semantics - Stack is a linear list in which insertions and
deletions take place at the same end (this end is
called the top, the other end of the list is
bottom)
pop pop pop
top
E D C B A
D C B A
B A
push E
bottom
7Stacks
- Two methods
- int push( Stack s, void item ) - add item to
the top of the stack - void pop( Stack s ) - remove an item from the
top of the stack - Like a plate stacker
- Other methods
- int IsEmpty( Stack s )/ Return TRUE if empty
/ - void Top( Stack s )/ Return the item at the
top, without deleting it /
8Stacks - Relevance
- Stacks appear in computer programs
- Perhaps most frequently used data structures
(along with Queues) - Key to call / return in functions procedures
- Stack frame allows recursive calls
- Call push stack frame
- Return pop stack frame
- Stack frame
- Function arguments
- Return address
- Local variables
9Stack Frames - Functions in HLL
function f( int x, int y) int a if (
term_cond ) return a . return g( a
) function g( int z ) int p, q p
. q . return f(p,q)
Context for execution of f
10Stacks - Implementation
- Arrays
- Provide a stack capacity to the constructor
- Flexibility limited but matches many real uses
- Capacity limited by some constraint
- Memory in your computer
- Size of the plate stacker, etc
- push, pop methods
- Variants of AddToC, DeleteFromC
- Linked list also possible
- Ex linked list - Need to add and delete from
head of the list only - Less used due to space constraints!
- Stack
- basically a Collection with special semantics!
11Formal Spec for Stack Class
- typedef struct t_stack stack
- stack ConsStack( int max_items, int item_size )
- / Construct a new stack
- Pre-condition (max_items gt 0) (item_size gt 0)
- Post-condition returns a pointer to an empty
stack - /
- void Push( stack s, void item )
- / Push an item onto a stack
- Pre-condition (s is a stack created by a call to
ConsStack) (existing item count lt max_items)
(item ! NULL) - Post-condition item has been added to the top of
s - /
- void Pop( stack s )
- / Pop an item of a stack
- Pre-condition (s is a stack created by a call to
ConsStack) (existing item count gt 1) - Post-condition top item has been removed from s
- /
12Derived Classes Inheritance
Ex class B public A B inherits all of the
members public, protected, and private of the
base class A All data members functions of A
are associated with every object of type B Ex2
class B public A, private C (derive from two
classes)
Private accessible to members of the class, but
not by the instances
Virtual?
13Stacks Derived Classes
- Are we ready to do C implementations?
14Recursion Stacks Enable It
- Very useful technique
- Definition of mathematical functions
- Definition of data structures
- Recursive structures are naturally processed by
recursive functions!
Recursively defined functions factorial Fibonacci
GCD (Greatest common denominator) by Euclids
algorithm Fourier Transform Games Towers of
Hanoi Chess
15Recursion Example
factorial( n ) if ( n 0 ) then 1 else n
factorial( n-1 )
Pseudo-code
C
function fact( int n ) if ( n 0 ) return
1 else return nfact(n-1)
Simple, elegant solution!
Important Termination condition Before reaching
term condition push n stack-frames on to stack
16Recursion - Example
fib( n ) if ( n 0 ) then 1
else if ( n 1 ) then 1 else
fib(n-1) fib(n-2)
Pseudo-code
C
int fib( n ) if ( n lt 2 ) return 1 else
return fib(n-1) fib(n-2)
Simple, elegant solution!
17Recursion - Example
int fib( n ) if ( n lt 2 ) return 1 else
return fib(n-1) fib(n-2)
C
But, in the Fibonacci case, a run-time
disaster!!!!
However, many recursive functions, eg binary
search, are simple, elegant and efficient!
18Queues
- Queues are dynamic collections which have some
concept of order - LIFO or FIFO queues.
FIFO Queue
rear
front
delete
add D
B C D
A B C
B C
19Queues from Linked Lists
- Can build with linked lists
- add-to-head implementation gives LIFO behavior
- Minor modification add tail pointer and adjust
the addition method will produce FIFO queue - Add and delete an item time needed is
independent of the number of items in the queue ?
O(1) - Can we improve it further?
head
tail
Well, look at (the machine os language ?
look at compiler, run-time system, machine speed
etc.) not much can be done at algorithm level ?
20Queues from Arrays
FIFO
rear
front
delete
add D
A
B
C
B
C
B
C
D
0 1 2
0 1
0 1 2
Addition O(1) Deletion Q(n)
21Queues from Arrays
FIFO
front
rear
front
rear
front
rear
delete
add D
A
B
C
B
C
B
C
D
0 1 2
0 1 2
0 1 2
Addition O(1) Deletion Q(1) worst case
Q(n)
- We can do circular arrays to get O(1) for both
addition and deletion - Need to pay attention to queue EMPTY and FULL
conditions - Can only use Maxsize-1 elements in most
implementations
22Priority Queues
- The items added to a queue have a priority
associated with them - This priority determines the order in which they
exit the queue - Example priority messages in an automated
factory, real time systems, life critical systems
etc.
23Priority Queues using Linear Lists
- Unordered linear list
- Insertion time Insert at the beginning of the
list ? Q(1) - Deletion time search for the element with
largest priority ?O(n) - Ordered linear list
- The elements are in nonincreasing order
- Insertion time Insert at the appropriate
location of the list ? O(n) - Deletion time delete at the beginning of the
list ?Q(1)
We need balanced approach Tree structure
generally provides O(log n) performance for both
insertion and deletion If the tree becomes
unbalanced, the performance degrades to O(n) Not
acceptable Structure to provide guaranteed O(log
n) performance for both insertion and deletion ?
heap
24Heaps
- Heaps or based on the notion of a complete tree
- A complete tree is filled from the left
- All the leaver are on the same level or two
adjacent ones - All nodes at the lowest level are as far to the
left as possible - A binary tree is completely full ?? 2h1-1 nodes
(h is height) - A binary tree is complete iff
- It is empty or
- Its left subtree is complete of height h-1 and
its right subtree is completely full of height
h-2 or - Its left subtree is completely full of height h-1
and its right subtree is complete of height h-1
25Heaps
- A binary tree has the heap property iff
- It is empty or
- The key in the root is larger than that in either
child and both subtrees have the heap property - Heap can be used as a priority queue
- Highest priority item is at the root and is
trivially extracted - If root is deleted, we are left with two
sub-trees and we must recreate a single tree with
heap property - We can both extract the highest priority item and
insert a new item in O(log n) time.
26Deletion from a Heap
T
S
P
G
R
O
N
A
M
C
I
A
E
5. Tree is now a heap again We need to make at
most h interchanges of a root of a subtree with
one of its children to restore the heap
property. Thus deletion from a heap is O(h) or
O(log n).
27Addition to a Heap
Follow the reverse procedure Place it in the next
leaf position and move it up
T
S
P
G
R
O
N
A
M
C
I
A
E
We need O(h) or O(log n) exchanges
28Storage of complete trees
- Use n sequential locations in an array
- Number the nodes from 1 at the root
- and place
- The left child of node k is at 2k
- The right child of node k is at 2k1
1
2
3
4
5
6
7
11
13
10
12
8
9
Viewed as an array, we can see that the nth node
is always in index position n
Delete extract the root, swap the last item to
its place, and call MoveDown recursively Insertion
similar and use MoveUp recursively
More Later on the data structures and program
representation of heaps In between think how to
implement them?
29Next Time
30Memory Mapping
31How Do We Write Programs Now?
public class foo static private int yv
0 static private int nv 0 public
static void main() foo foo_obj new
foo foo_obj-gtcheat() public cheat()
int tyv yv yv yv 1 if (tyv lt 10)
cheat()
- How to map a program like this to a Von Neuman
machine? - Where to keep yv, nv?
- What about foo_obj and tyv?
- How to do foo-gtcheat()?
32Global Variables
- Dealing with global variables like yv and nv is
easy - Lets just allocate some space in memory for them
- This is done by the compiler at compile time
- A reference to yv is then just an access to yvs
location in memory - Suppose yv is stored at location 2000
- Then, yv yv 1 might be compiled to something
like - loadi 2000, R1 load R1, R2 add R2, 1,
R2 store R1, R2
33Local Variables
- What about foo_obj defined in main() and tyv
defined in cheat()? - 1st option you might think of is just to allocate
some space in memory for these variables as well
(as shown to the right) - What is the problem with this approach?
- How can we deal with this problem?
yv
2000
nv
2004
2008
foo_obj
tyv
34Local Variable
yv
globals
foo-gtcheat() tyv yv foo-gtcheat() tyv
yv
tyv
stack
tyv
tyv
- Allocate a new memory location to tyv every time
cheat() is called at run-time - Convention is to allocate storage in a stack
(often called the control stack) - Pop stack when returning from a method storage
is no longer needed - Code for allocating/deallocating space on the
stack is generated by compiler at compile time
35What About new Objects?
- foo foo_obj new foo
- foo_obj is really a pointer to a foo object
- As just explained, a memory location is allocated
for foo_obj from the stack whenever main() is
invoked - Where does the object created by the new foo
actually live? - Is the stack an appropriate place to keep this
object? - Why not?
36Memory Image
- Suppose we have executed the following
- yv 0nv 0main()foo_obj new
foofoo-gtcheat()tyv yvyv yv
1foo-gtcheat()tyv yvyv yv
1foo-gtcheat()tyv yvyv yv 1
yv
globals
foo_obj
tyv
stack
tyv
tyv
heap
37Data Access
- How to find data allocated dynamically on stack?
- By convention, designate one register as the
stack pointer - Stack pointer always point at current activation
record - Stack pointer is set at entry to a method
- Code for setting stack pointer is generated by
compiler - Local variables and parameters are referenced as
offsets from sp
PC
activation record for cheat_yes()
tyv
SP
CPU
38Data Access
- The statement
- tyv tyv 1
- Would then translate into something like
- addi 0, sp, R1 tyv is the only variable so
offset is 0 - load R1, R2
- addi 1, R2
- store R1, R2
39Activation Record
- We have only talked about allocation of local
variables on the stack - The activation record is also used to store
- Parameters
- The beginning of the previous activation record
- The return address
-
Other stuff
Local variables
40Run Time Storage Organization
- Each variable must be assigned a storage class
- Global (static) variables
- Allocated in globals region at compile-time
- Method local variables and parameters
- Allocate dynamically on stack
- Dynamically created objects (using new)
- Allocate from heap
- Objects live beyond invocation of a method
- Garbage collected when no longer live
Code
Globals
Stack
Heap
Memory