Skip to content

Commit bd335d0

Browse files
Merge branch 'master' into LIFOCache
2 parents 8c3f312 + 2dfad7e commit bd335d0

File tree

5 files changed

+290
-64
lines changed

5 files changed

+290
-64
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package com.thealgorithms.matrix;
2+
3+
/**
4+
* This class provides a method to perform matrix multiplication.
5+
*
6+
* <p>Matrix multiplication takes two 2D arrays (matrices) as input and
7+
* produces their product, following the mathematical definition of
8+
* matrix multiplication.
9+
*
10+
* <p>For more details:
11+
* https://www.geeksforgeeks.org/java/java-program-to-multiply-two-matrices-of-any-size/
12+
* https://en.wikipedia.org/wiki/Matrix_multiplication
13+
*
14+
* <p>Time Complexity: O(n^3) – where n is the dimension of the matrices
15+
* (assuming square matrices for simplicity).
16+
*
17+
* <p>Space Complexity: O(n^2) – for storing the result matrix.
18+
*
19+
*
20+
* @author Nishitha Wihala Pitigala
21+
*
22+
*/
23+
24+
public final class MatrixMultiplication {
25+
private MatrixMultiplication() {
26+
}
27+
28+
/**
29+
* Multiplies two matrices.
30+
*
31+
* @param matrixA the first matrix rowsA x colsA
32+
* @param matrixB the second matrix rowsB x colsB
33+
* @return the product of the two matrices rowsA x colsB
34+
* @throws IllegalArgumentException if the matrices cannot be multiplied
35+
*/
36+
public static double[][] multiply(double[][] matrixA, double[][] matrixB) {
37+
// Check the input matrices are not null
38+
if (matrixA == null || matrixB == null) {
39+
throw new IllegalArgumentException("Input matrices cannot be null");
40+
}
41+
42+
// Check for empty matrices
43+
if (matrixA.length == 0 || matrixB.length == 0 || matrixA[0].length == 0 || matrixB[0].length == 0) {
44+
throw new IllegalArgumentException("Input matrices must not be empty");
45+
}
46+
47+
// Validate the matrix dimensions
48+
if (matrixA[0].length != matrixB.length) {
49+
throw new IllegalArgumentException("Matrices cannot be multiplied: incompatible dimensions.");
50+
}
51+
52+
int rowsA = matrixA.length;
53+
int colsA = matrixA[0].length;
54+
int colsB = matrixB[0].length;
55+
56+
// Initialize the result matrix with zeros
57+
double[][] result = new double[rowsA][colsB];
58+
59+
// Perform matrix multiplication
60+
for (int i = 0; i < rowsA; i++) {
61+
for (int j = 0; j < colsB; j++) {
62+
for (int k = 0; k < colsA; k++) {
63+
result[i][j] += matrixA[i][k] * matrixB[k][j];
64+
}
65+
}
66+
}
67+
return result;
68+
}
69+
}
Lines changed: 62 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,110 +1,115 @@
11
package com.thealgorithms.datastructures.lists;
22

3-
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
43
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertFalse;
55
import static org.junit.jupiter.api.Assertions.assertTrue;
66

77
import java.util.Arrays;
88
import java.util.stream.IntStream;
9+
import org.junit.jupiter.api.BeforeEach;
10+
import org.junit.jupiter.api.DisplayName;
911
import org.junit.jupiter.api.Test;
1012

1113
class SkipListTest {
1214

15+
private SkipList<String> skipList;
16+
17+
@BeforeEach
18+
void setUp() {
19+
skipList = new SkipList<>();
20+
}
21+
1322
@Test
14-
void add() {
15-
SkipList<String> skipList = new SkipList<>();
23+
@DisplayName("Add element and verify size and retrieval")
24+
void testAdd() {
1625
assertEquals(0, skipList.size());
1726

1827
skipList.add("value");
1928

20-
print(skipList);
2129
assertEquals(1, skipList.size());
30+
assertEquals("value", skipList.get(0));
2231
}
2332

2433
@Test
25-
void get() {
26-
SkipList<String> skipList = new SkipList<>();
34+
@DisplayName("Get retrieves correct element by index")
35+
void testGet() {
2736
skipList.add("value");
28-
29-
String actualValue = skipList.get(0);
30-
31-
print(skipList);
32-
assertEquals("value", actualValue);
37+
assertEquals("value", skipList.get(0));
3338
}
3439

3540
@Test
36-
void contains() {
37-
SkipList<String> skipList = createSkipList();
38-
print(skipList);
39-
40-
boolean contains = skipList.contains("b");
41-
42-
assertTrue(contains);
41+
@DisplayName("Contains returns true if element exists")
42+
void testContains() {
43+
skipList = createSkipList();
44+
assertTrue(skipList.contains("b"));
45+
assertTrue(skipList.contains("a"));
46+
assertFalse(skipList.contains("z")); // negative test
4347
}
4448

4549
@Test
46-
void removeFromHead() {
47-
SkipList<String> skipList = createSkipList();
48-
String mostLeftElement = skipList.get(0);
50+
@DisplayName("Remove element from head and check size and order")
51+
void testRemoveFromHead() {
52+
skipList = createSkipList();
53+
String first = skipList.get(0);
4954
int initialSize = skipList.size();
50-
print(skipList);
5155

52-
skipList.remove(mostLeftElement);
56+
skipList.remove(first);
5357

54-
print(skipList);
5558
assertEquals(initialSize - 1, skipList.size());
59+
assertFalse(skipList.contains(first));
5660
}
5761

5862
@Test
59-
void removeFromTail() {
60-
SkipList<String> skipList = createSkipList();
61-
String mostRightValue = skipList.get(skipList.size() - 1);
63+
@DisplayName("Remove element from tail and check size and order")
64+
void testRemoveFromTail() {
65+
skipList = createSkipList();
66+
String last = skipList.get(skipList.size() - 1);
6267
int initialSize = skipList.size();
63-
print(skipList);
6468

65-
skipList.remove(mostRightValue);
69+
skipList.remove(last);
6670

67-
print(skipList);
6871
assertEquals(initialSize - 1, skipList.size());
72+
assertFalse(skipList.contains(last));
6973
}
7074

7175
@Test
72-
void checkSortedOnLowestLayer() {
73-
SkipList<String> skipList = new SkipList<>();
76+
@DisplayName("Elements should be sorted at base level")
77+
void testSortedOrderOnBaseLevel() {
7478
String[] values = {"d", "b", "a", "c"};
7579
Arrays.stream(values).forEach(skipList::add);
76-
print(skipList);
7780

7881
String[] actualOrder = IntStream.range(0, values.length).mapToObj(skipList::get).toArray(String[] ::new);
7982

80-
assertArrayEquals(new String[] {"a", "b", "c", "d"}, actualOrder);
83+
org.junit.jupiter.api.Assertions.assertArrayEquals(new String[] {"a", "b", "c", "d"}, actualOrder);
8184
}
8285

83-
private SkipList<String> createSkipList() {
84-
SkipList<String> skipList = new SkipList<>();
85-
String[] values = {
86-
"a",
87-
"b",
88-
"c",
89-
"d",
90-
"e",
91-
"f",
92-
"g",
93-
"h",
94-
"i",
95-
"j",
96-
"k",
97-
};
86+
@Test
87+
@DisplayName("Duplicate elements can be added and count correctly")
88+
void testAddDuplicates() {
89+
skipList.add("x");
90+
skipList.add("x");
91+
assertEquals(2, skipList.size());
92+
assertEquals("x", skipList.get(0));
93+
assertEquals("x", skipList.get(1));
94+
}
95+
96+
@Test
97+
@DisplayName("Add multiple and remove all")
98+
void testClearViaRemovals() {
99+
String[] values = {"a", "b", "c"};
98100
Arrays.stream(values).forEach(skipList::add);
99-
return skipList;
101+
102+
for (String v : values) {
103+
skipList.remove(v);
104+
}
105+
106+
assertEquals(0, skipList.size());
100107
}
101108

102-
/**
103-
* Print Skip List representation to console.
104-
* Optional method not involved in testing process. Used only for visualisation purposes.
105-
* @param skipList to print
106-
*/
107-
private void print(SkipList<?> skipList) {
108-
System.out.println(skipList);
109+
private SkipList<String> createSkipList() {
110+
SkipList<String> s = new SkipList<>();
111+
String[] values = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"};
112+
Arrays.stream(values).forEach(s::add);
113+
return s;
109114
}
110115
}

src/test/java/com/thealgorithms/datastructures/queues/DequeTest.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,38 @@ void testToString() {
8787
deque.addFirst(5);
8888
assertEquals("Head -> 5 <-> 10 <-> 20 <- Tail", deque.toString());
8989
}
90+
91+
@Test
92+
void testAlternatingAddRemove() {
93+
Deque<Integer> deque = new Deque<>();
94+
deque.addFirst(1);
95+
deque.addLast(2);
96+
deque.addFirst(0);
97+
assertEquals(0, deque.pollFirst());
98+
assertEquals(2, deque.pollLast());
99+
assertEquals(1, deque.pollFirst());
100+
org.junit.jupiter.api.Assertions.assertTrue(deque.isEmpty());
101+
}
102+
103+
@Test
104+
void testSizeAfterOperations() {
105+
Deque<Integer> deque = new Deque<>();
106+
assertEquals(0, deque.size());
107+
deque.addFirst(1);
108+
deque.addLast(2);
109+
deque.addFirst(3);
110+
assertEquals(3, deque.size());
111+
deque.pollFirst();
112+
deque.pollLast();
113+
assertEquals(1, deque.size());
114+
}
115+
116+
@Test
117+
void testNullValues() {
118+
Deque<String> deque = new Deque<>();
119+
deque.addFirst(null);
120+
assertNull(deque.peekFirst());
121+
assertNull(deque.pollFirst());
122+
org.junit.jupiter.api.Assertions.assertTrue(deque.isEmpty());
123+
}
90124
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package com.thealgorithms.matrix;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertThrows;
5+
import static org.junit.jupiter.api.Assertions.assertTrue;
6+
7+
import org.junit.jupiter.api.Test;
8+
9+
public class MatrixMultiplicationTest {
10+
11+
private static final double EPSILON = 1e-9; // for floating point comparison
12+
13+
@Test
14+
void testMultiply1by1() {
15+
double[][] matrixA = {{1.0}};
16+
double[][] matrixB = {{2.0}};
17+
double[][] expected = {{2.0}};
18+
19+
double[][] result = MatrixMultiplication.multiply(matrixA, matrixB);
20+
assertMatrixEquals(expected, result);
21+
}
22+
23+
@Test
24+
void testMultiply2by2() {
25+
double[][] matrixA = {{1.0, 2.0}, {3.0, 4.0}};
26+
double[][] matrixB = {{5.0, 6.0}, {7.0, 8.0}};
27+
double[][] expected = {{19.0, 22.0}, {43.0, 50.0}};
28+
29+
double[][] result = MatrixMultiplication.multiply(matrixA, matrixB);
30+
assertMatrixEquals(expected, result); // Use custom method due to floating point issues
31+
}
32+
33+
@Test
34+
void testMultiply3by2and2by1() {
35+
double[][] matrixA = {{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}};
36+
double[][] matrixB = {{7.0}, {8.0}};
37+
double[][] expected = {{23.0}, {53.0}, {83.0}};
38+
39+
double[][] result = MatrixMultiplication.multiply(matrixA, matrixB);
40+
assertMatrixEquals(expected, result);
41+
}
42+
43+
@Test
44+
void testMultiplyNonRectangularMatrices() {
45+
double[][] matrixA = {{1.0, 2.0, 3.0}, {4.0, 5.0, 6.0}};
46+
double[][] matrixB = {{7.0, 8.0}, {9.0, 10.0}, {11.0, 12.0}};
47+
double[][] expected = {{58.0, 64.0}, {139.0, 154.0}};
48+
49+
double[][] result = MatrixMultiplication.multiply(matrixA, matrixB);
50+
assertMatrixEquals(expected, result);
51+
}
52+
53+
@Test
54+
void testNullMatrixA() {
55+
double[][] b = {{1, 2}, {3, 4}};
56+
assertThrows(IllegalArgumentException.class, () -> MatrixMultiplication.multiply(null, b));
57+
}
58+
59+
@Test
60+
void testNullMatrixB() {
61+
double[][] a = {{1, 2}, {3, 4}};
62+
assertThrows(IllegalArgumentException.class, () -> MatrixMultiplication.multiply(a, null));
63+
}
64+
65+
@Test
66+
void testMultiplyNull() {
67+
double[][] matrixA = {{1.0, 2.0}, {3.0, 4.0}};
68+
double[][] matrixB = null;
69+
70+
Exception exception = assertThrows(IllegalArgumentException.class, () -> MatrixMultiplication.multiply(matrixA, matrixB));
71+
72+
String expectedMessage = "Input matrices cannot be null";
73+
String actualMessage = exception.getMessage();
74+
75+
assertTrue(actualMessage.contains(expectedMessage));
76+
}
77+
78+
@Test
79+
void testIncompatibleDimensions() {
80+
double[][] a = {{1.0, 2.0}};
81+
double[][] b = {{1.0, 2.0}};
82+
assertThrows(IllegalArgumentException.class, () -> MatrixMultiplication.multiply(a, b));
83+
}
84+
85+
@Test
86+
void testEmptyMatrices() {
87+
double[][] a = new double[0][0];
88+
double[][] b = new double[0][0];
89+
assertThrows(IllegalArgumentException.class, () -> MatrixMultiplication.multiply(a, b));
90+
}
91+
92+
private void assertMatrixEquals(double[][] expected, double[][] actual) {
93+
assertEquals(expected.length, actual.length, "Row count mismatch");
94+
for (int i = 0; i < expected.length; i++) {
95+
assertEquals(expected[i].length, actual[i].length, "Column count mismatch at row " + i);
96+
for (int j = 0; j < expected[i].length; j++) {
97+
assertEquals(expected[i][j], actual[i][j], EPSILON, "Mismatch at (" + i + "," + j + ")");
98+
}
99+
}
100+
}
101+
}

0 commit comments

Comments
 (0)