Stacks

Introduction

The primary characteristic of a stack is that the last thing out is the first thing in. This is called LIFO. In real life, this is the way that cafeteria trays that are stacked on a spring work. The topmost one is the one that will be taken next. Its definition is independent of the way it is implemented as are all the data structures more complex than an array. There are four operations used on a stack; push pop isEmpty and isFull . There is also a pointer to a location on the stack. This is the top of stack (TOS) pointer and it indicates the place where the next item will be added or removed. Only the item at the top of the stack can be referred to. Any reference to the underlying data structure is illegal By always using the routines described above, the LIFO characteristic of the stack is preserved. The routines below use the STL list container but it is vital that you not confuse stacks and lists. Stacks can be implemented using lists but that is not the only way.
template 
class stack
{
	public:
		void push(TYPE x) { stk.push_front(x);}
		TYPE pop() { TYPE x = stk.front(); stk.pop_front(); return x;}
		int size() { return stk.size();}
		bool isEmpty() { return stk.empty();}
		friend ostream & operator<<(ostream & os, stack & s)
		{
			list::iterator ptr = s.stk.begin();
			while(ptr != s.stk.end())
				os << *ptr++ << ' ';
			os << endl;
			return os;
		}

	private:
		list stk;
};
There is no implementation of the isFull() method as we are using the STL list class and the only way for the stack to be full is if the program is out og memory. We should handle this using exceptions. The stack pointer is hidden as the list pointer in the stk object.

Here is a simple main that uses the template above to make a stack of integers.

int main(int argc, char* argv[])
{
	stack S;
	int i;

	if(S.isEmpty()) 
		cout << "Stack is initially empty" << endl;
	else
		cout << "Stack is initially NOT empty" << endl;

	for(i=0; i< 10; i++)
		S.push(i);

	if(S.isEmpty()) 
		cout << "Stack is empty after push loop" << endl;
	else
		cout << "Stack is NOT empty after push loop" << endl;

	cout << "stack contents using operator<<()" << endl;
	cout << S << endl;

	cout << "Size of stack before pop loop is " << S.size() << endl;
	
	cout << "stack contents using pop()" << endl;
	while(! S.isEmpty()) {
		cout << S.pop() << ' ';
	} // while
	cout << endl;

	cout << "Size of stack after pop loop is " << S.size() << endl;
	return 0;
}
The output looks like
Stack is initially empty
Stack is NOT empty after push loop
stack contents using operator<<()
9 8 7 6 5 4 3 2 1 0

Size of stack before pop loop is 10
stack contents using pop()
9 8 7 6 5 4 3 2 1 0
Size of stack after pop loop is 0
Press any key to continue

Uses For Stacks

The most common use is for maintaining parameters and return addresses for subroutine calls. They are also used for temporary storage of information and reversing things. Think of how an undo command works. It undoes in the opposite order that things were done. A stack is a natural for this.