Queue using Array - Simple Implementation
A queue is a linear data structure that follows the FIFO (First In, First Out) principle. The first element inserted is the first one to be removed.
Declaration of Queue Using Array:
A queue can be implemented using an array, and there are two main ways:
- Infinite (or Dynamically Growable) Array Queue
- Fixed-Size Array Queue
Infinite (or Dynamically Growable) Array Queue:
We can implement a queue using a conceptually infinite array by maintaining only a front pointer. The front pointer tracks the first valid element.
- Enqueue: Insert at the next available position at the end. No rear pointer is required.
- Dequeue: Remove the element at front and increment the front pointer.
The space before front is never reused, and unlike basic array implementations, we do not shift elements after each dequeue. This ensures both enqueue and dequeue operations run in O(1) time with a simple design.
Limitations:
- Wasted space: The elements before the front pointer are never reused, so memory can be wasted if many elements are dequeued.
- Infinite array assumption: We assume the array is conceptually infinite. In practice, memory is finite, so very large queues can cause memory issues.
Fixed-Size Array Queue
In this article, we will mainly discuss the queue implementation using a fixed-size array. In such an array-based queue, we maintain:
- A fixed-size array arr[] to store the elements.
- A variable size to track the current number of elements in the queue.
- A variable capacity to represent the maximum number of elements the queue can hold.
#include <iostream>
using namespace std;
class myQueue {
// Array to store queue elements.
int* arr;
//Maximum number of elements the queue can hold.
int capacity;
// Current number of elements in the queue.
int size;
public:
myQueue(int c) {
capacity = c;
arr = new int[capacity];
size = 0;
}
}
struct Queue {
int *arr;
int capacity;
int size;
};
// Create queue
struct myQueue* createQueue(int capacity) {
struct Queue* q = (struct Queue*)malloc(sizeof(struct Queue));
//Maximum number of elements the queue can hold.
q->capacity = capacity;
q->size = 0;
// Array to store queue elements.
q->arr = (int*)malloc(capacity * sizeof(int));
return q;
}
class myQueue {
private int[] arr;
private int capacity;
private int size;
// Constructor
public myQueue(int capacity) {
//Maximum number of elements the queue can hold.
this.capacity = capacity;
// Array to store queue elements.
arr = new int[capacity];
// Current number of elements in the queue.
size = 0;
}
}
class myQueue:
def __init__(self, capacity):
# Maximum number of elements the queue can hold.
self.capacity = capacity
# Array to store queue elements.
self.arr = [0] * capacity
# Current number of elements in the queue.
self.size = 0
class myQueue {
private int[] arr;
private int capacity;
private int size;
public myQueue(int capacity) {
//Maximum number of elements the queue can hold.
this.capacity = capacity;
// Array to store queue elements.
arr = new int[capacity];
// Current number of elements in the queue.
size = 0;
}
}
class myQueue {
constructor(capacity) {
//Maximum number of elements the queue can hold.
this.capacity = capacity;
// Array to store queue elements.
this.arr = new Array(capacity);
// Current number of elements in the queue.
this.size = 0;
}
}
Operations on Queue
Enqueue (Insert):
- Add element at the end of the queue if space is available; otherwise, it results in an Overflow condition.
- Time: O(1) , Space: O(1)
void enqueue(int x) {
if (size == capacity) {
cout << "Queue Overflow" << endl;
return;
}
arr[size++] = x;
}
void enqueue(int x) {
if (*size == capacity) {
printf("Queue Overflow");
return;
}
arr[*size] = x;
(*size)++;
}
void enqueue(int x) {
if (size == capacity) {
System.out.println("Queue Overflow");
return;
}
arr[size++] = x;
}
def enqueue(self, x):
if self.size == self.capacity:
print("Queue Overflow")
return
self.arr[self.size] = x
self.size += 1
public void enqueue(int x) {
if (size == capacity) {
Console.WriteLine("Queue Overflow");
return;
}
arr[size++] = x;
}
enqueue(x) {
if (this.size === this.capacity) {
console.log("Queue Overflow");
return;
}
this.arr[this.size++] = x;
}
Dequeue:
- Remove element from the front of the queue; if the queue is empty, it results in an Underflow condition.
- Time: O(n) (because of shifting) , Space : O(1)
void dequeue() {
if (size == 0) {
cout << "Queue Underflow" << endl;
return;
}
for (int i = 1; i < size; i++) {
arr[i-1] = arr[i];
}
size--;
}
void dequeue() {
if (*size == 0) {
printf("Queue Underflow");
return;
}
for (int i = 1; i < *size; i++) {
arr[i-1] = arr[i];
}
(*size)--;
}
void dequeue() {
if (size == 0) {
System.out.println("Queue Underflow");
return;
}
for (int i = 1; i < size; i++) {
arr[i-1] = arr[i];
}
size--;
}
def dequeue(self):
if self.size == 0:
print("Queue Underflow")
return
for i in range(1, self.size):
self.arr[i-1] = self.arr[i]
self.size -= 1
public void dequeue() {
if (size == 0) {
Console.WriteLine("Queue Underflow");
return;
}
for (int i = 1; i < size; i++) {
arr[i-1] = arr[i];
}
size--;
}
dequeue() {
if (this.size === 0) {
console.log("Queue Underflow");
return;
}
for (let i = 1; i < this.size; i++) {
this.arr[i-1] = this.arr[i];
}
this.size--;
}
getFront (Peek):
- Return first element if not empty, else -1.
- Time: O(1) , Space: O(1)
int getFront() {
if (size == 0) {
cout << "Queue is empty" << endl;
return -1;
}
return arr[0];
}
int getFront() {
if (size == 0) {
printf("Queue is empty\n");
return -1;
}
return arr[0];
}
int getFront() {
if (size == 0) {
System.out.println("Queue is empty");
return -1;
}
return arr[0];
}
def getFront(self):
if self.size == 0:
print("Queue is empty")
return -1
return self.arr[0]
public int getFront() {
if (size == 0) {
Console.WriteLine("Queue is empty");
return -1;
}
return arr[0];
}
function getFront() {
if (this.size === 0) {
console.log("Queue is empty");
return -1;
}
return this.arr[0];
}
getRear():
- Return last element if not empty, else -1.
- Time: O(1) , Space: O(1)
int getRear() {
if (isEmpty()) {
cout << "Queue is empty!" << endl;
return -1;
}
return arr[size - 1];
}
int getRear(Queue* q) {
if (isEmpty(q)) {
printf("Queue is empty!\n");
return -1;
}
return q->arr[q->size - 1];
}
public int getRear() {
if (isEmpty()) {
System.out.println("Queue is empty!");
return -1;
}
return arr[size - 1];
}
def getRear(self):
if self.isEmpty():
print("Queue is empty!")
return -1
return self.arr[self.size - 1]
public int getRear() {
if (isEmpty()) {
Console.WriteLine("Queue is empty!");
return -1;
}
return arr[size - 1];
}
function getRear() {
if (this.isEmpty()) {
console.log("Queue is empty!");
return -1;
}
return this.arr[this.size - 1];
}
isEmpty():
- Checks whether the queue has any elements or not.
- Returns true if the queue is empty, otherwise false.
- Time: O(1) , Space: O(1)
bool isEmpty() {
return size == 0;
}
int isEmpty(struct Queue* q) {
return q->size == 0;
}
public boolean isEmpty() {
return size == 0;
}
def isEmpty(self):
return self.size == 0
public bool isEmpty() {
return size == 0;
}
function isEmpty() {
return this.size === 0;
}
isFull():
- Checks whether the queue has reached its maximum capacity.
- Returns true if the queue is full, otherwise false.
- Time: O(1) , Space: O(1)
bool isFull() {
return size == capacity;
}
int isFull(struct Queue* q) {
return q->size == q->capacity;
}
public boolean isFull() {
return size == capacity;
}
def isFull(self):
return self.size == self.capacity
public bool isFull() {
return size == capacity;
}
function isFull() {
return this.size === this.capacity;
}
Full Implementations of Queue using Array
#include <iostream>
using namespace std;
class myQueue {
// Array to store queue elements.
int *arr;
// Maximum number of elements the queue can hold.
int capacity;
// Current number of elements in the queue.
int size;
public:
myQueue(int c) {
capacity = c;
arr = new int[capacity];
size = 0;
}
bool isEmpty()
{
return size == 0;
}
bool isFull()
{
return size == capacity;
}
// Adds an element x at the rear of the queue.
void enqueue(int x)
{
if (isFull())
{
cout << "Queue is full!\n";
return;
}
arr[size] = x;
size++;
}
// Removes the front element of the queue.
void dequeue()
{
if (isEmpty())
{
cout << "Queue is empty!\n";
return;
}
for (int i = 1; i < size; i++)
{
arr[i - 1] = arr[i];
}
size--;
}
// Returns the front element of the queue.
int getFront()
{
if (isEmpty())
{
cout << "Queue is empty!\n";
return -1;
}
return arr[0];
}
// Return the last element of queue
int getRear()
{
if (isEmpty())
{
cout << "Queue is empty!" << endl;
return -1;
}
return arr[size - 1];
}
};
int main()
{
myQueue q(3);
q.enqueue(10);
q.enqueue(20);
q.enqueue(30);
cout << "Front: " << q.getFront() << endl;
q.dequeue();
cout << "Front: " << q.getFront() << endl;
cout << "Rear: " << q.getRear() << endl;
q.enqueue(40);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
struct myQueue {
// Array to store queue elements
int *arr;
// Maximum number of elements the queue can hold
int capacity;
// Current number of elements in the queue
int size;
};
// Create queue
struct myQueue* createQueue(int capacity) {
struct myQueue* q = (struct myQueue*)malloc(sizeof(struct myQueue));
q->capacity = capacity;
q->size = 0;
q->arr = (int*)malloc(capacity * sizeof(int));
return q;
}
int isEmpty(struct myQueue* q) {
return q->size == 0;
}
int isFull(struct myQueue* q) {
return q->size == q->capacity;
}
// Adds an element x at the rear of the queue
void enqueue(struct myQueue* q, int x) {
if (isFull(q)) {
printf("Queue is full!\n");
return;
}
q->arr[q->size] = x;
q->size++;
}
// Removes the front element of the queue
void dequeue(struct myQueue* q) {
if (isEmpty(q)) {
printf("Queue is empty!\n");
return;
}
for (int i = 1; i < q->size; i++) {
q->arr[i - 1] = q->arr[i];
}
q->size--;
}
// Returns the front element of the queue
int getFront(struct myQueue* q) {
if (isEmpty(q)) {
printf("Queue is empty!\n");
return -1;
}
return q->arr[0];
}
// Returns the last element of the queue
int getRear(struct myQueue* q) {
if (isEmpty(q)) {
printf("Queue is empty!\n");
return -1;
}
return q->arr[q->size - 1];
}
int main() {
struct myQueue* q = createQueue(3);
enqueue(q, 10);
enqueue(q, 20);
enqueue(q, 30);
printf("Front: %d\n", getFront(q));
dequeue(q);
printf("Front: %d\n", getFront(q));
printf("Rear: %d\n", getRear(q));
enqueue(q, 40);
return 0;
}
class myQueue {
private int[] arr;
private int capacity;
private int size;
// Constructor
public myQueue(int capacity) {
//Maximum number of elements the queue can hold.
this.capacity = capacity;
// Array to store queue elements.
arr = new int[capacity];
// Current number of elements in the queue.
size = 0;
}
// Check if queue is empty
public boolean isEmpty() {
return size == 0;
}
// Check if queue is full
public boolean isFull() {
return size == capacity;
}
// Enqueue
public void enqueue(int x) {
if (isFull()) {
System.out.println("Queue is full!");
return;
}
arr[size] = x;
size++;
}
// Dequeue
public void dequeue() {
if (isEmpty()) {
System.out.println("Queue is empty!");
return;
}
for (int i = 1; i < size; i++) {
arr[i - 1] = arr[i];
}
size--;
}
// Get front element
public int getFront() {
if (isEmpty()) {
System.out.println("Queue is empty!");
return -1;
}
return arr[0];
}
//Get last element
public int getRear() {
if (isEmpty()) {
System.out.println("Queue is empty!");
return -1;
}
return arr[size - 1];
}
}
public class Main {
public static void main(String[] args) {
myQueue q = new myQueue(3);
q.enqueue(10);
q.enqueue(20);
q.enqueue(30);
System.out.println("Front: " + q.getFront());
q.dequeue();
System.out.println("Front: " + q.getFront());
System.out.println("Rear: " + q.getRear());
q.enqueue(40);
}
}
class myQueue:
def __init__(self, capacity):
#Maximum number of elements the queue can hold.
self.capacity = capacity
# Array to store queue elements.
self.arr = [0] * capacity
# Current number of elements in the queue.
self.size = 0
# Check if queue is empty
def isEmpty(self):
return self.size == 0
# Check if queue is full
def isFull(self):
return self.size == self.capacity
# Enqueue
def enqueue(self, x):
if self.isFull():
print("Queue is full!")
return
self.arr[self.size] = x
self.size += 1
# Dequeue
def dequeue(self):
if self.isEmpty():
print("Queue is empty!")
return
for i in range(1, self.size):
self.arr[i - 1] = self.arr[i]
self.size -= 1
# Get front element
def getFront(self):
if self.isEmpty():
print("Queue is empty!")
return -1
return self.arr[0]
def getRear(self):
if self.isEmpty():
print("Queue is empty!")
return -1
return self.arr[self.size - 1]
# Driver code
if __name__ == '__main__':
q = myQueue(3)
q.enqueue(10)
q.enqueue(20)
q.enqueue(30)
print("Front:", q.getFront())
q.dequeue()
print("Front:", q.getFront())
print("Rear:", q.getRear())
q.enqueue(40)
using System;
class myQueue {
private int[] arr;
private int capacity;
private int size;
public myQueue(int capacity)
{
// Maximum number of elements the queue can hold.
this.capacity = capacity;
// Array to store queue elements.
arr = new int[capacity];
// Current number of elements in the queue.
size = 0;
}
// Check if queue is empty
public bool isEmpty() { return size == 0; }
// Check if queue is full
public bool isFull() { return size == capacity; }
// Enqueue
public void enqueue(int x)
{
if (isFull()) {
Console.WriteLine("Queue is full!");
return;
}
arr[size] = x;
size++;
}
// Dequeue
public void dequeue()
{
if (isEmpty()) {
Console.WriteLine("Queue is empty!");
return;
}
for (int i = 1; i < size; i++) {
arr[i - 1] = arr[i];
}
size--;
}
// Get front element
public int getFront()
{
if (isEmpty()) {
Console.WriteLine("Queue is empty!");
return -1;
}
return arr[0];
}
// get last element
public int getRear()
{
if (isEmpty()) {
Console.WriteLine("Queue is empty!");
return -1;
}
return arr[size - 1];
}
}
class GfG {
static void Main()
{
myQueue q = new myQueue(3);
q.enqueue(10);
q.enqueue(20);
q.enqueue(30);
Console.WriteLine("Front: " + q.getFront());
q.dequeue();
Console.WriteLine("Front: " + q.getFront());
Console.WriteLine("Rear: " + q.getRear());
q.enqueue(40);
}
}
class myQueue {
constructor(capacity) {
//Maximum number of elements the queue can hold.
this.capacity = capacity;
// Array to store queue elements.
this.arr = new Array(capacity);
// Current number of elements in the queue.
this.size = 0;
}
//Maximum number of elements the queue can hold.
isEmpty() {
return this.size === 0;
}
// Check if full
isFull() {
return this.size === this.capacity;
}
// Enqueue
enqueue(x) {
if (this.isFull()) {
console.log("Queue is full!");
return;
}
this.arr[this.size] = x;
this.size++;
}
// Dequeue
dequeue() {
if (this.isEmpty()) {
console.log("Queue is empty!");
return;
}
for (let i = 1; i < this.size; i++) {
this.arr[i - 1] = this.arr[i];
}
this.size--;
}
// Get front element
getFront() {
if (this.isEmpty()) {
console.log("Queue is empty!");
return -1;
}
return this.arr[0];
}
// Get rear element
getRear() {
if (this.isEmpty()) {
console.log("Queue is empty!");
return -1;
}
return this.arr[this.size - 1];
}
}
//Driver Code
let q = new myQueue(3);
q.enqueue(10);
q.enqueue(20);
q.enqueue(30);
console.log("Front:", q.getFront());
q.dequeue();
console.log("Front:", q.getFront());
console.log("Rear:", q.getRear());
q.enqueue(40);
Output
Front: 10 Front: 20 Rear: 30
We can notice that the Dequeue operation is O(n) which is not acceptable. The enqueue and dequeue both operations should have O(1) time complexity. That is why if we wish to implement a queue using array (because of array advantages like cache friendliness and random access), we do circular array implementation of queue.