Resizable Array Implementation for Standard Generic Object Queue
Posted By : Neeraj Kumar | 16-Apr-2018
For Array implementation of a Standard Queue Data Structure, there are some key points we should keep in mind:
1. Randomly upsizing the array whenever the required size got larger than the actual size of the underlying array while enqueueing and
2. Randomly downsizing the array whenever the actual size is much larger than the required size of the underlying array while de-queueing
Why are we doing these two required actions randomly and not regularly?
It's an obvious question one can ask and the answer is the performance optimization.
- Lets first take the scenario of upsizing the underlying array: if we are upsizing the array whenever it's full, the order of growth for inserting first N elements will be proportional to 1+2+3+ ..... + N ~ N^2 / 2 which is a quadratic order of growth and hence it's unacceptable. So now we have to somehow randomize this upsizing of the array to reduce the order of growth of insert operation.
The solution for this is repeated doubling, in which we double the size of the array when its full, which reduces the order of growth for inserting first N elements to N (not N^2). - Now the other problem from repeated doubling we have is that, whenever we remove the element from queue we also need to maintain the size of the queue, we do not want to keep on increasing this size however we have empty spaces in our queue. Now we need to randomize the downsizing.
Now you might be thinking why not to half the array just like we have doubled it for upsizing, but than if we half the array just when the size of queue is half of the size of array we will phase an order of growth N for enqueueing just the next element in queue and this will happen every time whenever an enqueue is performed just after the downsizing by dequeue, which is also bad. So to reduce this time complexity in downsizing by checking for the quarter size of the array to be equal to the size of the queue to half it at that point so we will not face the N order growth for enqueueing just the next element in the queue.
public class ResizableArrayQueueOfObjects<T> {
T[] s;
int first = 0, last = 0;
private int N = 0;
public boolean isEmpty(){
return N == 0;
}
public int size() {
return N;
}
@SuppressWarnings("unchecked")
public ResizableArrayQueueOfObjects() {
this.s = (T[]) new Object[1];
}
public void enqueue(T item) {
if(s.length == N) {
resize(first, last, 2 * s.length);
}
if(N != 0) {
last += 1;
}
s[last] = item; //post increment of N
N = (last -first) + 1;
}
//save us from thrashing
public T dequeue() throws Exception {
if(N > 0) {
T item = s[first];
N -= 1;
s[first] = null;
// Stoping first index from growing bigger than last index
if(first < last){
first += 1;
}
if(s.length / 4 == 0) {
if(N > 0 && N == s.length / 2) {
resize(first, last, s.length / 2);
}
}
if(N > 0 && N == s.length / 4) {
resize(first, last, s.length / 2);
}
return item;
} else {
throw new Exception("Queue already Empty!!");
}
}
@SuppressWarnings("unchecked")
private void resize(int first, int last, int capacity) {
int oldLength = s.length;
T[] copy = (T[]) new Object[capacity];
for(int i = 0, j = first; j <= last; i++, j++) {
copy[i] = s[j];
}
s = copy;
//only for the down sizing
if(s.length < oldLength) {
this.first = 0;
this.last = N-1;
}
}
@Override
public String toString() {
String ss;
ss = "[";
for(int i = 0, j = first; j <= last; i++, j++) {
ss = ss + s[j];
if(s[j] != null) {
if(((String) this.s[j]).length() != 0) {
ss = ss + ", ";
}
}
}
ss = ss + "]";
return ss;
}
}
Note: The initial size of the underlying array is 1 and now when ever an element is enqueued the size increased with repeated doubling.
The Main Class, calling the ResizableArrayQueueOfObjects ADT(abstract data type).
public class Main {
public static void main(String[] args) throws Exception {
ResizableArrayQueueOfObjects<String> resizableArrayImpleOfQueue = new ResizableArrayQueueOfObjects<>();
resizableArrayImpleOfQueue.enqueue("Hello World!");
System.out.println(resizableArrayImpleOfQueue.toString());
// repeadted doubling will occur to resize the array
resizableArrayImpleOfQueue.enqueue("input 1");
System.out.println(resizableArrayImpleOfQueue.toString());
System.out.println(resizableArrayImpleOfQueue.dequeue());
System.out.println(resizableArrayImpleOfQueue.toString());
resizableArrayImpleOfQueue.enqueue("input 2");
System.out.println(resizableArrayImpleOfQueue.toString());
resizableArrayImpleOfQueue.enqueue("input 3");
System.out.println(resizableArrayImpleOfQueue.toString());
resizableArrayImpleOfQueue.enqueue("input 4");
resizableArrayImpleOfQueue.enqueue("input 5");
resizableArrayImpleOfQueue.enqueue("input 6");
resizableArrayImpleOfQueue.enqueue("input 7");
resizableArrayImpleOfQueue.enqueue("input 8");
System.out.println(resizableArrayImpleOfQueue.toString());
// repeated doubling will occur at this point to resize the array
resizableArrayImpleOfQueue.enqueue("input 9");
System.out.println(resizableArrayImpleOfQueue.toString());
resizableArrayImpleOfQueue.enqueue("Hello yum!17");
resizableArrayImpleOfQueue.enqueue("Hello yum!18");
System.out.println(resizableArrayImpleOfQueue.dequeue());
System.out.println(resizableArrayImpleOfQueue.toString());
}
}
Cookies are important to the proper functioning of a site. To improve your experience, we use cookies to remember log-in details and provide secure log-in, collect statistics to optimize site functionality, and deliver content tailored to your interests. Click Agree and Proceed to accept cookies and go directly to the site or click on View Cookie Settings to see detailed descriptions of the types of cookies and choose whether to accept certain cookies while on the site.
About Author
Neeraj Kumar
Neeraj is a JAVA Developer who possesses skill set in: Data Structures, Core Java, Java Enterprise Edition (Servlets, JSP, Standard Java Beans), Spring (Spring-core, spring-MVC, spring-Data-Access, Spring-Data-JPA), Hibernate, JPA, HTML, CSS, JavaScri