Data Structures Chapter 4
Array Unbounded Queue Class
Create a new larger array when needed and copy the queue into the new array. Since enlarging the array is conceptually a seperate operation from enqueueing, we implement it as a separate enlarge method. This method Instantiates an array with a size equal to the current capacity plus the original capacity We change the isFull method so that it always returns false, since an unbounded queue is never full. The dequeue and isEmpty methods are unchanged.
Link - Based Queue Implementations
For nodes we use the same LLNode class we used for the linked implementation of stacks. After discussing the link based approaches we compare all of our queue implementation approaches.
The Queue Interface
Like a stack, a queue is implemented with tools. We define overflow exceptions for both queue overflow and underflow. Our queues are generic Create a queueinterface containing abstract methods as a first step
Concurrency
Several interacting code sequences are executing simultaneously - through interleaving of statements of a single processor - through execution on several processors
Synchronized Queue
Similarly the synchronized keyword can be used to control access to an entire or selected parts of a data structure.
Array Based Implementation -
Two array based implementations of the Queue ADT, a bounded queue version and an unbounded queue version. Some figures are simplified by using a capital letter to represent an elements information.
Application: Average Waiting Time
We create a program that simulates a series of customers arriving for a service, entering a queue, waiting, being served, and finally leaving the queue. It tracks the time customeres spend waiting in queues and outputs the average waiting time.
Floating Front Design is much more effective and efficient than Fixed Front Design. It can also be used to wrap an added value around to the other side of the array if the last indexes are full
With Floating Front Design, when you perform the enqueue operation values are placed in the front of the array. When you perform the dequeue, it removes the first element from the array, and instead of moving the entire array, it moves the front to change index 1 from index 0
LinkedQueue Class
import support.LLNode; public class LinkedQueue<T> implements QueueInterface<T> { protected LLNode<T> front; // reference to the front of q protected LLNode<T> rear; // reference to the rear of q protected int numElements = 0; // num of elements in q public LinkedQueue() { front = null; rear = null; }
The Enlarge Operation
private void enlarge() { //create the larger array T[] larger = (T[]) new Object[elements.length + origCap]; //copy the contents from the smaller array into the larger int currSmaller = front; for (int currLarger = 0; currLarger < numElements; currLarger++) { larger[currLarger] = elements[currSmaller]; currSmaller = (currSmaller + 1) % elements.length; } // update instance variables elements = larger; front = 0; rear = numElements - 1; }
Code for Dequeue Operation Link Based Queue Implementations
public T dequeue() { if (isEmpty()) throw new QueueUnderflowException("Dequeue attempted on empty queue."); else { T element; element = front.getInfo(); front = front.getLink(); if (front == null) rear = null; numElements--; return element; } }
The Dequeue Operation
public T dequeue() { if (isEmpty()) throw new QueueUnderflowException("Dequeue attempted on empty queue."); else { T toReturn = elements[front]; elements[front] = null; front = (front + 1) % elements.length; numElements = numElements - 1; return toReturn; } }
The Queue Interface Code
public interface QueueInterface<T> { void enqueue(T element) throws QueueOverflowException; //Throws QueueOverflowException if queue is full; //Otherwise, adds element to the rear of this queue. T dequeue() throws QueueUnderflowException; //Throws QueueUnderflowException; //otherwise, removes front element from this queue and returns it. boolean isFull(); // returns true if this queue is full; //otherwise, returns false. boolean isEmpty(); //returns true if this queue is empty; //otherwise, returns false. int size(); // returns the number of elements in this queue. }
ArrayUnbounded Enqueue Operation
public void enqueue(T element) //adds element to rear of this queue { if (numElements == elements.length) enlarge(); rear = (rear + 1) % elements.length; elements[rear] = element; numElements = numElements + 1; }
Code For Enqueue Operation Link Based Queue Implementations
public void enqueue(T element) //adds element to the rear of this queue { LLNode<T> newNode = new LLNode<T>(element); if (rear == null) front = newNode; else rear.setLink(newNode); rear = newNode; numElements++; }
How to find the rear of the array
rear =(rear+1)% arr.len
Enqueue Operation
{ If (isFull()) Throw new QueueOverflowException("Enqueue attempted on a full queue"); Else { rear = (rear + 1) % elements.length; elements[rear] = element; numElements = numElements + 1; } }
Difference between .size and .length
.size measures total empty or full spaces in array .length measures only the spaces in the array that contain a value of some kind
Enqueue Operation Link Based Queue Implementations
1. Create a node for the new element 2. Add the new node at the rear of the queue 3. Update the reference to the rear of the queue 4. Increment the number of elements
The Enqueue Operation For Link Based Queue Implementations
1. Create a node for the new element 2. Add the new node at the rear of the queue 3. Update the reference to the rear of the queue 4. Increment the number of elements
The Dequeue Operation for Link Based Queue Implementations
1. Set element to the information in the front node 2. Remove the front node from the queue 3. If the queue is empty set the rear to null 4. Decrement the number of elements\ 5. Return element
Dequeue Operation Link Based Queue Implementations
1. Set element to the information in the front node 2. Remove the front node from the queue 3. if the queue is empty set the rear to null 4. Decrement the number of elements 5. Return element
Bounded Queue
A queue with a limited or bounded capacity for processes.
Queue
A structure in which elements are added to the rear and removed from the front. Has several constructors and transformers
Two operations for Enqueing
Add, that throws an exception if invoked on a full queue, and offer, that returns a boolean value of false if invoked on a full queue.
Queue Operator - Enqueue
Adds an element to the end of the queue(transformer)
Fixed Front Design
After four Calls to enqueue with arguments A, B, C, D: [A][B][C][D][ ] Dequeue the front element: [ ] [B] [C] [D] [ ] Move every element in the queue up one slot [B] [C] [D] [ ] [ ] This dequeue operation is inefficient, so we do not use this approach.
Four library classes that implement the Dequeue interface
ArrayDequeue, ConcurrentLinkedDequeue, LinkedBlockingDequeue, and linkedList
Test for palindrome (String Candidate)
Create a new stack Create a new queue For each character in candidate if the character is a letter change letter to lowercase push to the character onto the stack enqueue the character onto the queue Set stillPalindrome to true While(there are still more characters in the structures && stillPalindrome) Pop fromStack from the stack Dequeue fromQueue from the queue If(fromStack != fromQueue) Set stillPalindrome to false Return(stillPalindrome)
Queue Operator - New
Creates an empty queue (Constructor)
When to throw exceptions in queue
If queue is full and enqueue attempted, throw overflow exception. If queue is empty and dequeue is attempted, throw underflow exception.
Inheritance of Interfaces
Java supports inheritance of interfaces, in fact the language supports mulitple inheritance of interfaces - A single interface can extend any number of other interfaces. Suppose that interface A extends interface B. Then a class that implements interface B must provide concrete methods to extend all of the abstract methods listed in both interface B and interface A.
Queue Methods :
Moves in from rear and out from front. isEmpty(); isFull(); size(); enqueue(); dequeue();
Using Queues
Operating Systems often maintain a queue of processes that are ready to execute or that are waiting for a particular event to occur. Another important application of the queue data structure is to help us simulate and analyze such real worlds queues.
Exceptional Situations
Our queues throw exceptions in the case of underflow or overflow. Another approach to prevent the over/underflow from occuring by nullifying the operation, and returning a value that indicates failure. Boolean enqueue (T element) adds element to the rear of this queue, returns true if successfully added, returns false otherwise. T dequeue() returns null if the queue is empty, otherwise removes the front element from this queue and returns it.
Unbounded Queue
Queue that does not have a limited capacity
Front and Rear
References of the index's of the array that are the first and last
Queue Operator - Dequeue
Removes and returns the front element of the queue
Comparing Queue Implementations
Storage Size Array Based: Takes the same amount of memory, no matter how many array slots are actually used, proportional to current capacity. Link Based: Takes space proportional to actual size of the queue(but each element requires more space with array approach) Operation Efficiency All operations, for each approach, are O(1) Except for the constructors: Array Based - O(N) Link Based - O(1) Special Case - For the ArrayUnboundedQueue the size penalty can be minimized but the enlarge method is O(N)
Elements are always removed from which direction of a queue
The Front
The Test Method
The test method creates both a stack and a queue. It then repeatedly pushes each input letter onto the stack, and also enqueues the letter onto the queue. It discards any non letter characters. To simplify the comparision later, we push and enqueue only lowercase versions of the characters After the characters of the candidate string have been processed, test repeatedly pops a letter from the stack and dequeues a letter from the queue. As long as these letters match each other throughout the process, it is a palindrome.
The Palindrome Class
To help us identify strings, we create a class called palindrome, with a single export static method test. Test takes a candidate string argument and returns a boolean Value indicating whether the string is a palindrome. Since test is static we invoke it using the name of the class rather than instantiating an object of the class. The test method uses both the queue and stack data structures.