Stacks
What is a Data Structure?
A data structure is a component or object that stores and provides access
to information. Arrays and linked lists are examples of rudimentary data
structures. Arrays store a fixed number of objects and can provide random
access to any of those objects. Linked lists store a dynamic number of
objects and provide access to only the first object in the list at any given
time.
Other examples of data structures include stacks, queues, and trees. Each
data structure differs with respect to how it provides access to information
and how efficient its operations are. All data structures enable the
programmer to insert and remove data. However, stacks only allow the
programmer to remove the last piece of data inserted. Queues allow the
programmer to remove the piece of data that has been in the queue the
longest.
Overview of Stacks
A stack is a last-in first-out data structure (LIFO). Conceptually, the
stack data structure behaves like a stack of books or a stack of plates. New
data is placed on the top of the stack, and when data is removed it is taken
from the top. Your browser's back button likely stores a set of URLs in a
stack.
The operations supported by a stack are as follows:
- void push(Object o) - place object o on the top of the stack
- Object pop() - remove and return the object on the top of the stack
- Object top() - return the object on the top of the stack without
removing it
- int size() - return the size of the stack
- boolean isEmpty() - return true if the stack contains no elements,
false otherwise
Stacks are typically depicted as follows:

The previous stack would be the result of the following operations:
push(1)
push(2)
push(3)
A pop on the stack above would return the object 3 and the resulting stack
would look as follows:

A top on the stack above would return the object 2 and the stack itself
would remain unchanged.
Implementation
A stack can be implemented using an array or a linked list. In essense,
the stack operations simply limit the way in which we access data stored in a
data structure such as an array. A stack can also be implemented using other
data structures, but we'll discuss that example later.
When choosing which rudimentary data structure to use for an
implementation, it is imperative that you consider efficiency. How many steps
will push and pop require?
To implement a stack, you will need to implement a Stack class that
provides the stack operations described above. You will also want to provide
appropriate error reporting. Therefore, it might make sense to have the pop
operation throw a StackEmptyException in the event that the programmer tries
to pop from a stack with no elements.
+Implementing a Stack Using an Array
To implement a stack using an array, your Stack class will require an array data member. The push method will place a new object in the appropriate location
in the array. The pop method will return the appropriate object from the array.
A stack with no elements will contain an array data member with no elements. When the first element is pushed onto the stack, where should the element be placed?
You can place the element anywhere in the array, but position 0 makes sense. The second element should be placed at position 1, and so on. After pushing elements
1, 2, and 3, the conceptual model and underlying implementation would look as follows:
The pseudocode for push and pop would look as follows:
push(o):
if top == elementarray.length
throw new StackFullException
elementarray[top++] = o
pop:
if top == 0
throw new StackEmptyException
return elementarray[--top]
The big-oh running time of both push and pop would be constant.
+Implementing a Stack Using a Linked List
To implement a stack using a linked list, your Stack class will require a linked list data member. The push method will place a new object in the
list and the pop method will remove and return the appropriate item from the list.
Rather than implementing a linked list from scratch, you should consider how you would use an existing linked list implementation. Your existing implementation
should provide insert/deleteHead methods and insert/deleteTail methods. How would you use those methods to efficiently implement the stack?
Recall that insert/deleteHead and insertTail are constant time operations if your linked list implementation maintains a tail reference. However, deleteTail is a
linear time operation and thus should be avoided.
Suppose you chose to implement push by inserting the new element at the tail of your linked list. In that case, push would be a constant time operation -- very
efficient. However, since pop removes the last item pushed, the pop method would need to invoke removeTail -- not efficient.
tail.
On the other hand, if you chose to implement push by inserting the new element at the head of your linked list, you could implement pop by invoking
removeHead. Since insertHead and removeHead are both constant time operations, your stack will be quite efficient.
The pseudocode for push and pop would look as follows:
push(o):
linkedlist.insertHead(o)
pop:
if linkedlist.getHead() == null
thow new StackEmptyException
o = linkedlist.removeHead()
return o
Sami Rollins
Date: 2007-10-10