Repository: TheAlgorithms/Java (java)

Issue:
[FEATURE REQUEST] Make `MedianOfRunningArray` generic
### What would you like to Propose?

I find it a bit odd that the [`MedianOfRunningArray`](https://github.com/TheAlgorithms/Java/blob/fbe348b105a06258a81538023698117e2bb116cb/src/main/java/com/thealgorithms/misc/MedianOfRunningArray.java) only works with integers and returns double as the median. I suggest to make `MedianOfRunningArray` generic accepting any [`Number`](https://docs.oracle.com/javase/8/docs/api/java/lang/Number.html) class.

### Issue details

I suggest to define `MedianOfRunningArray` as

```java
public class MedianOfRunningArray<T extends Number> {
    //...
}
```

and to change the method `insert` to accept objects of `T` and `median` to return `T`.

### Additional Information

Please make sure to include the following test (_rounding down to the integer_):

```Java
var stream = new MedianOfRunningArray<Integer>();
stream.insert(1);
stream.insert(2);
assertEquals(1, stream.median());
```

Pull request:
Make `MedianOfRunningArray` Generic
Closes #4390

Patch:
diff --git a/src/main/java/com/thealgorithms/misc/MedianOfRunningArray.java b/src/main/java/com/thealgorithms/misc/MedianOfRunningArray.java
index 61fbfa82..62013ee3 100644
--- a/src/main/java/com/thealgorithms/misc/MedianOfRunningArray.java
+++ b/src/main/java/com/thealgorithms/misc/MedianOfRunningArray.java
@@ -6,10 +6,10 @@ import java.util.PriorityQueue;
 /**
  * @author shrutisheoran
  */
-public class MedianOfRunningArray {
+public abstract class MedianOfRunningArray<T extends Number & Comparable<T>> {
 
-    private PriorityQueue<Integer> maxHeap;
-    private PriorityQueue<Integer> minHeap;
+    private PriorityQueue<T> maxHeap;
+    private PriorityQueue<T> minHeap;
 
     // Constructor
     public MedianOfRunningArray() {
@@ -21,8 +21,8 @@ public class MedianOfRunningArray {
       Inserting lower half of array to max Heap
       and upper half to min heap
      */
-    public void insert(Integer e) {
-        if (!minHeap.isEmpty() && e < minHeap.peek()) {
+    public void insert(final T e) {
+        if (!minHeap.isEmpty() && e.compareTo(minHeap.peek()) < 0) {
             maxHeap.offer(e);
             if (maxHeap.size() > minHeap.size() + 1) {
                 minHeap.offer(maxHeap.poll());
@@ -38,14 +38,16 @@ public class MedianOfRunningArray {
     /*
       Returns median at any given point
      */
-    public double median() {
+    public T median() {
         if (maxHeap.isEmpty() && minHeap.isEmpty()) {
             throw new IllegalArgumentException("Enter at least 1 element, Median of empty list is not defined!");
+        } else if (maxHeap.size() == minHeap.size()) {
+            T maxHeapTop = maxHeap.peek();
+            T minHeapTop = minHeap.peek();
+            return calculateAverage(maxHeapTop, minHeapTop);
         }
-
-        if (maxHeap.size() == minHeap.size()) {
-            return (maxHeap.peek() + minHeap.peek()) / 2.0;
-        }
-        return maxHeap.size() > minHeap.size() ? maxHeap.peek() * 1.0 : minHeap.peek() * 1.0;
+        return maxHeap.size() > minHeap.size() ? maxHeap.peek() : minHeap.peek();
     }
+
+    public abstract T calculateAverage(T a, T b);
 }
diff --git a/src/main/java/com/thealgorithms/misc/MedianOfRunningArrayByte.java b/src/main/java/com/thealgorithms/misc/MedianOfRunningArrayByte.java
new file mode 100644
index 00000000..668f651e
--- /dev/null
+++ b/src/main/java/com/thealgorithms/misc/MedianOfRunningArrayByte.java
@@ -0,0 +1,8 @@
+package com.thealgorithms.misc;
+
+public final class MedianOfRunningArrayByte extends MedianOfRunningArray<Byte> {
+    @Override
+    public Byte calculateAverage(final Byte a, final Byte b) {
+        return (byte) ((a + b) / 2);
+    }
+}
diff --git a/src/main/java/com/thealgorithms/misc/MedianOfRunningArrayDouble.java b/src/main/java/com/thealgorithms/misc/MedianOfRunningArrayDouble.java
new file mode 100644
index 00000000..9d743de5
--- /dev/null
+++ b/src/main/java/com/thealgorithms/misc/MedianOfRunningArrayDouble.java
@@ -0,0 +1,8 @@
+package com.thealgorithms.misc;
+
+public final class MedianOfRunningArrayDouble extends MedianOfRunningArray<Double> {
+    @Override
+    public Double calculateAverage(final Double a, final Double b) {
+        return (a + b) / 2.0d;
+    }
+}
diff --git a/src/main/java/com/thealgorithms/misc/MedianOfRunningArrayFloat.java b/src/main/java/com/thealgorithms/misc/MedianOfRunningArrayFloat.java
new file mode 100644
index 00000000..a667abf6
--- /dev/null
+++ b/src/main/java/com/thealgorithms/misc/MedianOfRunningArrayFloat.java
@@ -0,0 +1,8 @@
+package com.thealgorithms.misc;
+
+public final class MedianOfRunningArrayFloat extends MedianOfRunningArray<Float> {
+    @Override
+    public Float calculateAverage(final Float a, final Float b) {
+        return (a + b) / 2.0f;
+    }
+}
diff --git a/src/main/java/com/thealgorithms/misc/MedianOfRunningArrayInteger.java b/src/main/java/com/thealgorithms/misc/MedianOfRunningArrayInteger.java
new file mode 100644
index 00000000..7154ba07
--- /dev/null
+++ b/src/main/java/com/thealgorithms/misc/MedianOfRunningArrayInteger.java
@@ -0,0 +1,8 @@
+package com.thealgorithms.misc;
+
+public final class MedianOfRunningArrayInteger extends MedianOfRunningArray<Integer> {
+    @Override
+    public Integer calculateAverage(final Integer a, final Integer b) {
+        return (a + b) / 2;
+    }
+}
diff --git a/src/main/java/com/thealgorithms/misc/MedianOfRunningArrayLong.java b/src/main/java/com/thealgorithms/misc/MedianOfRunningArrayLong.java
new file mode 100644
index 00000000..1f138c63
--- /dev/null
+++ b/src/main/java/com/thealgorithms/misc/MedianOfRunningArrayLong.java
@@ -0,0 +1,8 @@
+package com.thealgorithms.misc;
+
+public final class MedianOfRunningArrayLong extends MedianOfRunningArray<Long> {
+    @Override
+    public Long calculateAverage(final Long a, final Long b) {
+        return (a + b) / 2L;
+    }
+}


Test patch:
diff --git a/src/test/java/com/thealgorithms/misc/MedianOfRunningArrayTest.java b/src/test/java/com/thealgorithms/misc/MedianOfRunningArrayTest.java
index 96cdc77e..90910d51 100644
--- a/src/test/java/com/thealgorithms/misc/MedianOfRunningArrayTest.java
+++ b/src/test/java/com/thealgorithms/misc/MedianOfRunningArrayTest.java
@@ -1,15 +1,13 @@
 package com.thealgorithms.misc;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
-import org.apache.commons.lang3.tuple.Pair;
 import org.junit.jupiter.api.Test;
 
 /**
- * Test case for Two sum Problem.
- * @author Bama Charan Chhandogi (https://github.com/BamaCharanChhandogi)
+ * Test case for Median Of Running Array Problem.
+ * @author Ansh Shah (https://github.com/govardhanshah456)
  */
 
 public class MedianOfRunningArrayTest {
@@ -17,71 +15,71 @@ public class MedianOfRunningArrayTest {
 
     @Test
     public void testWhenInvalidInoutProvidedShouldThrowException() {
-        MedianOfRunningArray stream = new MedianOfRunningArray();
+        var stream = new MedianOfRunningArrayInteger();
         IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> stream.median());
         assertEquals(exception.getMessage(), EXCEPTION_MESSAGE);
     }
 
     @Test
     public void testWithNegativeValues() {
-        MedianOfRunningArray stream = new MedianOfRunningArray();
+        var stream = new MedianOfRunningArrayInteger();
         stream.insert(-1);
         assertEquals(-1, stream.median());
         stream.insert(-2);
-        assertEquals(-1.5, stream.median());
+        assertEquals(-1, stream.median());
         stream.insert(-3);
         assertEquals(-2, stream.median());
     }
 
     @Test
     public void testWithSingleValues() {
-        MedianOfRunningArray stream = new MedianOfRunningArray();
+        var stream = new MedianOfRunningArrayInteger();
         stream.insert(-1);
         assertEquals(-1, stream.median());
     }
 
     @Test
     public void testWithRandomValues() {
-        MedianOfRunningArray stream = new MedianOfRunningArray();
+        var stream = new MedianOfRunningArrayInteger();
         stream.insert(10);
-        assertEquals(10.0, stream.median());
+        assertEquals(10, stream.median());
 
         stream.insert(5);
-        assertEquals(7.5, stream.median());
+        assertEquals(7, stream.median());
 
         stream.insert(20);
-        assertEquals(10.0, stream.median());
+        assertEquals(10, stream.median());
 
         stream.insert(15);
-        assertEquals(12.5, stream.median());
+        assertEquals(12, stream.median());
 
         stream.insert(25);
-        assertEquals(15.0, stream.median());
+        assertEquals(15, stream.median());
 
         stream.insert(30);
-        assertEquals(17.5, stream.median());
+        assertEquals(17, stream.median());
 
         stream.insert(35);
-        assertEquals(20.0, stream.median());
+        assertEquals(20, stream.median());
 
         stream.insert(1);
-        assertEquals(17.5, stream.median());
+        assertEquals(17, stream.median());
     }
 
     @Test
     public void testWithNegativeAndPositiveValues() {
-        MedianOfRunningArray stream = new MedianOfRunningArray();
+        var stream = new MedianOfRunningArrayInteger();
         stream.insert(-1);
         assertEquals(-1, stream.median());
         stream.insert(2);
-        assertEquals(0.5, stream.median());
+        assertEquals(0, stream.median());
         stream.insert(-3);
         assertEquals(-1, stream.median());
     }
 
     @Test
     public void testWithDuplicateValues() {
-        MedianOfRunningArray stream = new MedianOfRunningArray();
+        var stream = new MedianOfRunningArrayInteger();
         stream.insert(-1);
         assertEquals(-1, stream.median());
         stream.insert(-1);
@@ -92,7 +90,7 @@ public class MedianOfRunningArrayTest {
 
     @Test
     public void testWithDuplicateValuesB() {
-        MedianOfRunningArray stream = new MedianOfRunningArray();
+        var stream = new MedianOfRunningArrayInteger();
         stream.insert(10);
         stream.insert(20);
         stream.insert(10);
@@ -105,7 +103,7 @@ public class MedianOfRunningArrayTest {
 
     @Test
     public void testWithLargeValues() {
-        MedianOfRunningArray stream = new MedianOfRunningArray();
+        var stream = new MedianOfRunningArrayInteger();
         stream.insert(1000000);
         assertEquals(1000000, stream.median());
         stream.insert(12000);
@@ -113,49 +111,89 @@ public class MedianOfRunningArrayTest {
         stream.insert(15000000);
         assertEquals(1000000, stream.median());
         stream.insert(2300000);
-        assertEquals(1650000.00, stream.median());
+        assertEquals(1650000, stream.median());
     }
 
     @Test
     public void testWithLargeCountOfValues() {
-        MedianOfRunningArray stream = new MedianOfRunningArray();
+        var stream = new MedianOfRunningArrayInteger();
         for (int i = 1; i <= 1000; i++) stream.insert(i);
-        assertEquals(500.5, stream.median());
+        assertEquals(500, stream.median());
     }
 
     @Test
     public void testWithThreeValuesInDescendingOrder() {
-        MedianOfRunningArray stream = new MedianOfRunningArray();
+        var stream = new MedianOfRunningArrayInteger();
         stream.insert(30);
         stream.insert(20);
         stream.insert(10);
-        assertEquals(20.0, stream.median());
+        assertEquals(20, stream.median());
     }
 
     @Test
     public void testWithThreeValuesInOrder() {
-        MedianOfRunningArray stream = new MedianOfRunningArray();
+        var stream = new MedianOfRunningArrayInteger();
         stream.insert(10);
         stream.insert(20);
         stream.insert(30);
-        assertEquals(20.0, stream.median());
+        assertEquals(20, stream.median());
     }
 
     @Test
     public void testWithThreeValuesNotInOrderA() {
-        MedianOfRunningArray stream = new MedianOfRunningArray();
+        var stream = new MedianOfRunningArrayInteger();
         stream.insert(30);
         stream.insert(10);
         stream.insert(20);
-        assertEquals(20.0, stream.median());
+        assertEquals(20, stream.median());
     }
 
     @Test
     public void testWithThreeValuesNotInOrderB() {
-        MedianOfRunningArray stream = new MedianOfRunningArray();
+        var stream = new MedianOfRunningArrayInteger();
         stream.insert(20);
         stream.insert(10);
         stream.insert(30);
-        assertEquals(20.0, stream.median());
+        assertEquals(20, stream.median());
+    }
+
+    @Test
+    public void testWithFloatValues() {
+        var stream = new MedianOfRunningArrayFloat();
+        stream.insert(20.0f);
+        assertEquals(20.0f, stream.median());
+        stream.insert(10.5f);
+        assertEquals(15.25f, stream.median());
+        stream.insert(30.0f);
+        assertEquals(20.0f, stream.median());
+    }
+
+    @Test
+    public void testWithByteValues() {
+        var stream = new MedianOfRunningArrayByte();
+        stream.insert((byte) 120);
+        assertEquals((byte) 120, stream.median());
+        stream.insert((byte) -120);
+        assertEquals((byte) 0, stream.median());
+        stream.insert((byte) 127);
+        assertEquals((byte) 120, stream.median());
+    }
+
+    @Test
+    public void testWithLongValues() {
+        var stream = new MedianOfRunningArrayLong();
+        stream.insert(120000000L);
+        assertEquals(120000000L, stream.median());
+        stream.insert(92233720368547757L);
+        assertEquals(46116860244273878L, stream.median());
+    }
+
+    @Test
+    public void testWithDoubleValues() {
+        var stream = new MedianOfRunningArrayDouble();
+        stream.insert(12345.67891);
+        assertEquals(12345.67891, stream.median());
+        stream.insert(23456789.98);
+        assertEquals(Double.valueOf(11734567.83), stream.median(), .01);
     }
 }