Applications of Circular Arrays
Common Applications in Real-World Scenarios​
- Network Packet Buffers: Used in routers to handle packets with limited memory.
- Operating System Buffers: Useful for managing I/O data streams.
- Real-Time Data Logging: Used to store recent data while continuously overwriting the oldest data.
Here is a real-world example where a circular array can be practically applied:
Circular Buffer for Logging Events​
This documentation provides the implementations of a circular buffer in Java, C++, and Python. This data structure is commonly used in logging systems to maintain a fixed-size buffer of recent entries, where the oldest entries are overwritten when the buffer becomes full.
Java Code​
import java.util.Arrays;
public class CircularBuffer {
private String[] buffer;
private int front;
private int rear;
private int size;
private int capacity;
public CircularBuffer(int capacity) {
this.capacity = capacity;
buffer = new String[capacity];
front = -1;
rear = -1;
size = 0;
}
public boolean isEmpty() {
return size == 0;
}
public boolean isFull() {
return size == capacity;
}
public void logEvent(String event) {
if (isFull()) {
front = (front + 1) % capacity; // Move front forward if buffer is full
} else {
size++;
}
rear = (rear + 1) % capacity;
buffer[rear] = event;
System.out.println("Logged event: " + event);
}
public String[] getEvents() {
String[] events = new String[size];
int index = front == -1 ? 0 : (front + 1) % capacity;
for (int i = 0; i < size; i++) {
events[i] = buffer[index];
index = (index + 1) % capacity;
}
return events;
}
public static void main(String[] args) {
CircularBuffer logger = new CircularBuffer(5);
logger.logEvent("Event 1");
logger.logEvent("Event 2");
logger.logEvent("Event 3");
logger.logEvent("Event 4");
logger.logEvent("Event 5");
// Adding more events to show circular behavior
logger.logEvent("Event 6"); // Overwrites oldest
logger.logEvent("Event 7");
System.out.println("Logged Events: " + Arrays.toString(logger.getEvents()));
}
}
C++ Implementation​
#include <iostream>
#include <vector>
#include <string>
class CircularBuffer {
private:
std::vector<std::string> buffer;
int front, rear, size, capacity;
public:
CircularBuffer(int capacity) : capacity(capacity), front(-1), rear(-1), size(0) {
buffer.resize(capacity);
}
bool isEmpty() const {
return size == 0;
}
bool isFull() const {
return size == capacity;
}
void logEvent(const std::string& event) {
if (isFull()) {
front = (front + 1) % capacity; // Move front forward if buffer is full
} else {
size++;
}
rear = (rear + 1) % capacity;
buffer[rear] = event;
std::cout << "Logged event: " << event << std::endl;
}
void getEvents() const {
if (isEmpty()) {
std::cout << "No events logged." << std::endl;
return;
}
int index = front == -1 ? 0 : (front + 1) % capacity;
std::cout << "Logged Events: ";
for (int i = 0; i < size; i++) {
std::cout << buffer[index] << " ";
index = (index + 1) % capacity;
}
std::cout << std::endl;
}
};
int main() {
CircularBuffer logger(5);
logger.logEvent("Event 1");
logger.logEvent("Event 2");
logger.logEvent("Event 3");
logger.logEvent("Event 4");
logger.logEvent("Event 5");
// Adding more events to show circular behavior
logger.logEvent("Event 6"); // Overwrites oldest
logger.logEvent("Event 7");
logger.getEvents();
return 0;
}
Python Implementation​
class CircularBuffer:
def __init__(self, capacity):
self.capacity = capacity
self.buffer = [None] * capacity
self.front = -1
self.rear = -1
self.size = 0
def is_empty(self):
return self.size == 0
def is_full(self):
return self.size == self.capacity
def log_event(self, event):
if self.is_full():
self.front = (self.front + 1) % self.capacity # Move front forward if buffer is full
else:
self.size += 1
self.rear = (self.rear + 1) % self.capacity
self.buffer[self.rear] = event
print(f"Logged event: {event}")
def get_events(self):
events = []
index = 0 if self.front == -1 else (self.front + 1) % self.capacity
for _ in range(self.size):
events.append(self.buffer[index])
index = (index + 1) % self.capacity
return events
# Example usage
logger = CircularBuffer(5)
logger.log_event("Event 1")
logger.log_event("Event 2")
logger.log_event("Event 3")
logger.log_event("Event 4")
logger.log_event("Event 5")
# Adding more events to show circular behavior
logger.log_event("Event 6") # Overwrites oldest
logger.log_event("Event 7")
print("Logged Events:", logger.get_events())
Explanation​
These implementations of a circular buffer manage a fixed-size collection where the oldest entries are overwritten when the buffer becomes full. In each version (Java, C++, and Python), the circular buffer uses an array to store entries, along with variables to track the front
, rear
, and size
. When an event (or entry) is logged, the program checks if the buffer is full. If full, the front
pointer advances to discard the oldest entry, while the rear
pointer increments to store the new event in a "circular" manner, wrapping around to the start of the array when reaching the end. This approach maintains a constant buffer size, making it ideal for real-time applications like logging systems. Finally, a method retrieves all stored events in the correct order for review.
Conclusion​
Each implementation demonstrates how a circular buffer can manage a fixed-size buffer, retaining only the most recent entries by overwriting the oldest ones when the buffer is full.