Simple Queue Implementation [File]
Two of the more used data structures in programming are the Stack and the Queue. Each of which has important real-world (programming) applications which you use without knowing every day.
Stacks and queues are both data types used when working with a large number of objects, just like a List or a Set. The behaviour of the set is what sets them apart. Just like a set, you should not randomly access or change the elements of a stack or a queue. Instead you must follow a pre-determined access sequence defined by the data structure.
A stack behaves much in the same way as you would expect when you interact with a stack of paper in the real world:
In other words, stacks operate under a Last-In, First-Out, or LIFO operation policy. This means that a stack has a fairly standard set of methods that are used:
Traditionally, these are the only 4 methods needed for a stack data type. It is often, however, useful to check the top item of your stack without removing it. This is done through a peek method.
Note: In Java, a Stack is an already implemented class and inherits from the Vector class. A Vector is just a thread-safe ArrayList. This means a Java Stack<E> does not need to be implemented and the Stack object also has methods like elementAt(int index), insert(E e, int index), and remove(int index). These methods circumvent the purpose of the stack data type and should only be used sparingly.
Typically, we would maintain a variable, say n, which tells us how many items have been pushed (that have not been popped). We would also have some other data structure such as a list or array which would store all of the items on our stack.
As a consequence, the most recently added item would be at position n-1, and the least recently added item would be at position 0.
There are a lot of low-level situations where stacks are very useful. Three good examples are:
In addition, If you think about the back button on your web browser, this is very close to how a stack works, with one major exception. If you go back a few times you can still go forward to the pages you were just on, unless you go to a different page you had not originally visited. In this case all of your "forward" progress is lost and you create a new history.
public interface ISimpleStack<E> {
/**
* Places the object, item, on the top of the stack.
* @param item - the item to be pushed onto this stack.
*/
public void push(E item);
/**
* Removes the item on the top of the stack and returns
* it.
* @return the item from the top of the stack.
*/
public E pop();
/**
* Returns the item at the top of the stack without
* changing the stack contents.
* @return the item from the top of the stack.
*/
public E peek();
/**
* Tests if this stack is empty.
* @return true if and only if this stack contains no
* items; false otherwise
*/
public boolean isEmpty();
/**
* Returns the number of items in the stack.
* @return an integer representing the number of items
* currently in the stack.
*/
public int size();
}
1. a) What would be a reasonable response to attempting to pop an empty stack? Why?
b) What would happen if you pushed a null element onto a stack? Does that affect how you think of your response to question (a)?
2. Reverse a String using a stack.
3. Create a stack using an array whose size you control. The array must always be no more than twice the size of the number of items within it, except for a minimum size (say, 5). For example:
A queue behaves much like a line you would enter at an amusement park:
In other words, a queue operates under the First-In, First-Out or FIFO operation policy. Which allows us to have a fairly standard interface:
Traditionally, these are the only 4 methods needed for a queue data type. It is often, however, useful to check the front item of your queue without removing it. This is done through a peek method.
Though there are better underlying ways of creating a queue, you can create a queue using a primitive array. To do this you need to think of an array as more of a circular structure. So, instead of this:
Think of a Queue like this:
This change in thought allows us to avoid some very expensive reorganisation of elements when we dequeue an object.
In order to accomplish this, we must store two index values:
public interface ISimpleQueue<E> {
/**
* Add an item to the queue.
* @param item - The item being added to the queue
*/
public void enqueue(E item);
/**
* Returns the next item in the queue, removing it from
* the queue in the process.
* @return the item being removed from the queue
*/
public E dequeue();
/**
* Returns the item at the front of the queue without
* changing the queue contents.
* @return the item at the front of the queue.
*/
public E peek();
/**
* Tests is the queue is empty.
* @return true if and only if this queue contains no
* items; false otherwise.
*/
public boolean isEmpty();
/**
* Returns the number of items in the queue.
* @return the number of items currently stored in the
* queue
*/
public int size();
}
Queues are an essential part of internet communication: Requests made to retrieve a website from a server may be queued if there are many requests that happen simultaneously. Another example; tasks to be performed by a CPU/GPU are usually queued and performed by the first available processor. Queues can also used for:
1. What would be a reasonable response for calling dequeue() on an empty queue? Why? Would your answer change if calling enqueue() with a null element was allowed?
2. Simulate a checkout at a grocery store: