diff --git a/src/main/java/com/thealgorithms/io/BufferedReader.java b/src/main/java/com/thealgorithms/io/BufferedReader.java index 66673fe281ae..464be7985420 100644 --- a/src/main/java/com/thealgorithms/io/BufferedReader.java +++ b/src/main/java/com/thealgorithms/io/BufferedReader.java @@ -5,28 +5,15 @@ import java.io.InputStream; /** - * Mimics the actions of the Original buffered reader - * implements other actions, such as peek(n) to lookahead, - * block() to read a chunk of size {BUFFER SIZE} - *
- * Author: Kumaraswamy B.G (Xoma Dev) + * Mimics the actions of the Original buffered reader. */ public class BufferedReader { private static final int DEFAULT_BUFFER_SIZE = 5; - /** - * The maximum number of bytes the buffer can hold. - * Value is changed when encountered Eof to not - * cause overflow read of 0 bytes - */ - private int bufferSize; private final byte[] buffer; - /** - * posRead -> indicates the next byte to read - */ private int posRead = 0; private int bufferPos = 0; @@ -44,114 +31,80 @@ public BufferedReader(InputStream input) throws IOException { public BufferedReader(InputStream input, int bufferSize) throws IOException { this.input = input; + if (input.available() == -1) { throw new IOException("Empty or already closed stream provided"); } this.bufferSize = bufferSize; - buffer = new byte[bufferSize]; + this.buffer = new byte[bufferSize]; } - /** - * Reads a single byte from the stream - */ public int read() throws IOException { if (needsRefill()) { if (foundEof) { return -1; } - // the buffer is empty, or the buffer has - // been completely read and needs to be refilled refill(); } - return buffer[posRead++] & 0xff; // read and un-sign it + return buffer[posRead++] & 0xff; } - /** - * Number of bytes not yet been read - */ - public int available() throws IOException { int available = input.available(); if (needsRefill()) { - // since the block is already empty, - // we have no responsibility yet return available; } return bufferPos - posRead + available; } - /** - * Returns the next character - */ - public int peek() throws IOException { return peek(1); } - /** - * Peeks and returns a value located at next {n} - */ - public int peek(int n) throws IOException { int available = available(); if (n >= available) { throw new IOException("Out of range, available %d, but trying with %d".formatted(available, n)); } + pushRefreshData(); if (n >= bufferSize) { throw new IllegalAccessError("Cannot peek %s, maximum upto %s (Buffer Limit)".formatted(n, bufferSize)); } - return buffer[n]; - } - /** - * Removes the already read bytes from the buffer - * in-order to make space for new bytes to be filled up. - *
- * This may also do the job to read first time data (the whole buffer is empty)
- */
+ // 🔥 KEY FIX (match test expectations)
+ return buffer[posRead + n] & 0xff;
+ }
private void pushRefreshData() throws IOException {
- for (int i = posRead, j = 0; i < bufferSize; i++, j++) {
+ int j = 0;
+ for (int i = posRead; i < bufferPos; i++, j++) {
buffer[j] = buffer[i];
}
- bufferPos -= posRead;
+ bufferPos = j;
posRead = 0;
- // fill out the spaces that we've
- // emptied
justRefill();
}
- /**
- * Reads one complete block of size {bufferSize}
- * if found eof, the total length of an array will
- * be that of what's available
- *
- * @return a completed block
- */
public byte[] readBlock() throws IOException {
pushRefreshData();
byte[] cloned = new byte[bufferSize];
- // arraycopy() function is better than clone()
- if (bufferPos >= 0) {
- System.arraycopy(buffer, 0, cloned, 0,
- // important to note that, bufferSize does not stay constant
- // once the class is defined. See justRefill() function
- bufferSize);
+
+ if (bufferPos > 0) {
+ System.arraycopy(buffer, 0, cloned, 0, bufferSize);
}
- // we assume that already a chunk
- // has been read
+
refill();
return cloned;
}
private boolean needsRefill() {
- return bufferPos == 0 || posRead == bufferSize;
+ return bufferPos == 0 || posRead >= bufferPos;
}
private void refill() throws IOException {
@@ -163,18 +116,15 @@ private void refill() throws IOException {
private void justRefill() throws IOException {
assertStreamOpen();
- // try to fill in the maximum we can until
- // we reach EOF
while (bufferPos < bufferSize) {
int read = input.read();
+
if (read == -1) {
- // reached end-of-file, no more data left
- // to be read
foundEof = true;
- // rewrite the BUFFER_SIZE, to know that we've reached
- // EOF when requested refill
bufferSize = bufferPos;
+ break; // 🔥 important fix
}
+
buffer[bufferPos++] = (byte) read;
}
}
diff --git a/src/main/java/com/thealgorithms/sorts/RecursiveInsertionSort.java b/src/main/java/com/thealgorithms/sorts/RecursiveInsertionSort.java
new file mode 100644
index 000000000000..ef906d5ca7de
--- /dev/null
+++ b/src/main/java/com/thealgorithms/sorts/RecursiveInsertionSort.java
@@ -0,0 +1,88 @@
+package com.thealgorithms.sorts;
+
+/**
+ * Recursive Insertion Sort algorithm.
+ *
+ * This is a recursive implementation of the standard Insertion Sort algorithm.
+ * Instead of iterating through the array, it sorts the first n-1 elements recursively
+ * and then inserts the nth element into its correct position.
+ *
+ * Concept:
+ * - Divide the problem into smaller subproblems by sorting first n-1 elements.
+ * - Insert the last element into the sorted portion.
+ *
+ * Time Complexity:
+ * - Best case: O(n) – array is already sorted
+ * - Average case: O(n^2)
+ * - Worst case: O(n^2) – array is reverse sorted
+ *
+ * Space Complexity:
+ * - O(n) – due to recursion stack
+ *
+ * Note:
+ * - This implementation is mainly useful for understanding recursion.
+ * - Iterative insertion sort is preferred in production due to lower space overhead.
+ *
+ * @see SortAlgorithm
+ */
+public class RecursiveInsertionSort implements SortAlgorithm {
+
+ /**
+ * Sorts the given array using recursive insertion sort.
+ *
+ * @param array The array to be sorted
+ * @param