Print Job Simulator
Problem Statement
Write a Java program that simulates a printer queue using a queue implementation. The program should allow users to enqueue print jobs (represented as strings) and dequeue them in order, printing each job as it is processed in a first-in, first-out (FIFO) manner. Test the implementation with various sequences of enqueue and dequeue operations, including edge cases like empty queues and null print jobs. You can visualize this as a printer handling a queue of documents, where each document is printed in the order it was submitted, and the printer processes one job at a time.
Input: A sequence of operations, where each operation is either:
- Enqueue: Add a print job (string) to the queue (e.g.,
"Document1"). - Dequeue: Remove and process the next print job, printing its details. Output: For each operation, print the action performed (enqueue or dequeue) and, for dequeue, the processed job or a message if the queue is empty. Constraints:
- Queue size is between 0 and 10^5.
- Print jobs are non-empty strings containing printable ASCII characters, or null (handled gracefully).
- The queue may be empty when dequeue is called. Example:
- Input: Operations = [enqueue("Doc1"), enqueue("Doc2"), dequeue, enqueue("Doc3"), dequeue]
- Output:
Enqueued Doc1 Enqueued Doc2 Dequeued and processed: Doc1 Enqueued Doc3 Dequeued and processed: Doc2 - Explanation: Jobs are enqueued in order and dequeued in FIFO order, printing each job as processed.
- Input: Operations = [dequeue on empty queue]
- Output:
Queue empty, cannot dequeue
Pseudocode
CLASS StringQueue
SET array to new string array of size 1000
SET front to 0
SET rear to -1
SET size to 0
FUNCTION enqueue(job)
IF size equals array length THEN
RETURN false (queue full)
ENDIF
INCREMENT rear
SET array[rear] to job
INCREMENT size
RETURN true
ENDFUNCTION
FUNCTION dequeue()
IF size equals 0 THEN
RETURN null (queue empty)
ENDIF
SET job to array[front]
INCREMENT front
DECREMENT size
RETURN job
ENDFUNCTION
FUNCTION isEmpty()
RETURN size equals 0
ENDFUNCTION
ENDCLASS
FUNCTION simulatePrinter(operations)
CREATE queue as new StringQueue
FOR each operation in operations
IF operation.type equals "enqueue" THEN
CALL queue.enqueue(operation.job)
PRINT enqueued job
ELSE IF operation.type equals "dequeue" THEN
SET job to queue.dequeue()
IF job is null THEN
PRINT queue empty message
ELSE
PRINT dequeued and processed job
ENDIF
ENDIF
ENDFOR
ENDFUNCTION
FUNCTION main()
SET testCases to array of operation sequences
FOR each testCase in testCases
PRINT test case details
CALL simulatePrinter(testCase)
ENDFOR
ENDFUNCTION
Algorithm Steps
- Define a
StringQueueclass with: a. An array to store print jobs (strings), withfront,rear, andsizeto track queue state. b. Methods:enqueue(add job to rear),dequeue(remove job from front),isEmpty(check if empty). - In the
simulatePrintermethod: a. Create a newStringQueue. b. For each operation:- If "enqueue", add the job to the queue and print the action.
- If "dequeue", remove the next job, print it as processed, or print "Queue empty" if empty.
- In the
mainmethod, test with sequences of enqueue and dequeue operations, including empty queues, single jobs, and null jobs.
Java Implementation
import java.util.*;
public class PrintJobSimulator {
// Custom queue implementation for strings
static class StringQueue {
private String[] array;
private int front;
private int rear;
private int size;
private static final int DEFAULT_SIZE = 1000;
public StringQueue() {
array = new String[DEFAULT_SIZE];
front = 0;
rear = -1;
size = 0;
}
public boolean enqueue(String job) {
if (size == array.length) {
return false; // Queue full
}
array[++rear] = job;
size++;
return true;
}
public String dequeue() {
if (size == 0) {
return null; // Queue empty
}
String job = array[front++];
size--;
return job;
}
public boolean isEmpty() {
return size == 0;
}
}
// Helper class for operations
static class Operation {
String type;
String job; // For enqueue operations
Operation(String type, String job) {
this.type = type;
this.job = job;
}
}
// Simulates printer queue functionality
public void simulatePrinter(List<Operation> operations) {
StringQueue queue = new StringQueue();
for (Operation op : operations) {
if (op.type.equals("enqueue")) {
boolean success = queue.enqueue(op.job);
if (success) {
System.out.println("Enqueued " + (op.job != null ? op.job : "null"));
} else {
System.out.println("Enqueue " + (op.job != null ? op.job : "null") + " failed: Queue full");
}
} else if (op.type.equals("dequeue")) {
String job = queue.dequeue();
if (job == null) {
System.out.println("Queue empty, cannot dequeue");
} else {
System.out.println("Dequeued and processed: " + job);
}
}
}
}
// Main method to test printer queue simulation
public static void main(String[] args) {
PrintJobSimulator simulator = new PrintJobSimulator();
// Test cases
List<List<Operation>> testCases = new ArrayList<>();
// Test case 1: Normal sequence
List<Operation> case1 = Arrays.asList(
new Operation("enqueue", "Document1"),
new Operation("enqueue", "Document2"),
new Operation("dequeue", null),
new Operation("enqueue", "Document3"),
new Operation("dequeue", null)
);
testCases.add(case1);
// Test case 2: Empty queue
List<Operation> case2 = Arrays.asList(
new Operation("dequeue", null)
);
testCases.add(case2);
// Test case 3: Single job
List<Operation> case3 = Arrays.asList(
new Operation("enqueue", "SingleDoc"),
new Operation("dequeue", null)
);
testCases.add(case3);
// Test case 4: Multiple enqueues
List<Operation> case4 = Arrays.asList(
new Operation("enqueue", "Job1"),
new Operation("enqueue", "Job2"),
new Operation("enqueue", "Job3"),
new Operation("dequeue", null),
new Operation("dequeue", null)
);
testCases.add(case4);
// Test case 5: Null job
List<Operation> case5 = Arrays.asList(
new Operation("enqueue", null),
new Operation("dequeue", null)
);
testCases.add(case5);
// Run test cases
for (int i = 0; i < testCases.size(); i++) {
System.out.println("Test case " + (i + 1) + ":");
simulator.simulatePrinter(testCases.get(i));
System.out.println();
}
}
}
Output
Running the main method produces:
Test case 1:
Enqueued Document1
Enqueued Document2
Dequeued and processed: Document1
Enqueued Document3
Dequeued and processed: Document2
Test case 2:
Queue empty, cannot dequeue
Test case 3:
Enqueued SingleDoc
Dequeued and processed: SingleDoc
Test case 4:
Enqueued Job1
Enqueued Job2
Enqueued Job3
Dequeued and processed: Job1
Dequeued and processed: Job2
Test case 5:
Enqueued null
Dequeued and processed: null
Explanation:
- Test case 1: Enqueues "Document1", "Document2", dequeues "Document1", enqueues "Document3", dequeues "Document2".
- Test case 2: Dequeue on empty queue returns "Queue empty".
- Test case 3: Enqueues single job, dequeues it.
- Test case 4: Enqueues three jobs, dequeues two in FIFO order.
- Test case 5: Enqueues null job, dequeues it.
How It Works
- StringQueue:
- Uses an array with
frontandrearindices to track the queue’s state, andsizeto track the number of jobs. enqueue: Adds a job to the rear if the queue isn’t full.dequeue: Removes and returns the front job if not empty.isEmpty: Checks if the queue is empty.
- Uses an array with
- simulatePrinter:
- Enqueues jobs, printing each action.
- Dequeues jobs, printing the processed job or "Queue empty".
- Example Trace (Test case 1):
- Enqueue "Document1": queue = ["Document1"], front=0, rear=0.
- Enqueue "Document2": queue = ["Document1", "Document2"], front=0, rear=1.
- Dequeue: Returns "Document1", queue = ["Document2"], front=1, rear=1.
- Enqueue "Document3": queue = ["Document2", "Document3"], front=1, rear=2.
- Dequeue: Returns "Document2", queue = ["Document3"], front=2, rear=2.
- Main Method: Tests normal sequences, empty queue, single job, multiple enqueues, and null job.
Complexity Analysis Table
| Operation | Time Complexity | Space Complexity |
|---|---|---|
| Enqueue/Dequeue | O(1) | O(1) |
| Full Algorithm | O(n) | O(n) |
Note:
- n is the number of operations.
- Time complexity: O(1) for each enqueue or dequeue; O(n) for processing n operations.
- Space complexity: O(n) for the queue storing up to n jobs.
- Worst case: O(n) time and O(n) space for many enqueue operations.
✅ Tip: Use a queue to simulate a printer’s job processing, as its FIFO nature ensures jobs are processed in submission order. Test with sequences that mix enqueue and dequeue operations to verify correctness.
⚠ Warning: Handle null jobs and empty queue cases to avoid unexpected behavior. Ensure the queue size is sufficient to accommodate the input sequence.