Skip to content

Commit 83c634e

Browse files
Merge branch 'master' into workflow/close-failed-prs
2 parents 427a065 + 100462d commit 83c634e

12 files changed

Lines changed: 818 additions & 2 deletions

File tree

DIRECTORY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@
173173
- 📄 [FordFulkerson](src/main/java/com/thealgorithms/datastructures/graphs/FordFulkerson.java)
174174
- 📄 [Graphs](src/main/java/com/thealgorithms/datastructures/graphs/Graphs.java)
175175
- 📄 [HamiltonianCycle](src/main/java/com/thealgorithms/datastructures/graphs/HamiltonianCycle.java)
176+
- 📄 [HierholzerAlgorithm](src/main/java/com/thealgorithms/graph/HierholzerAlgorithm.java)
176177
- 📄 [JohnsonsAlgorithm](src/main/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithm.java)
177178
- 📄 [KahnsAlgorithm](src/main/java/com/thealgorithms/datastructures/graphs/KahnsAlgorithm.java)
178179
- 📄 [Kosaraju](src/main/java/com/thealgorithms/datastructures/graphs/Kosaraju.java)

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
<dependency>
2121
<groupId>org.junit</groupId>
2222
<artifactId>junit-bom</artifactId>
23-
<version>6.0.0</version>
23+
<version>6.0.1</version>
2424
<type>pom</type>
2525
<scope>import</scope>
2626
</dependency>
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package com.thealgorithms.bitmanipulation;
2+
3+
/**
4+
* Utility class for performing circular bit rotations on 32-bit integers.
5+
* Bit rotation is a circular shift operation where bits shifted out on one end
6+
* are reinserted on the opposite end.
7+
*
8+
* <p>This class provides methods for both left and right circular rotations,
9+
* supporting only 32-bit integer operations with proper shift normalization
10+
* and error handling.</p>
11+
*
12+
* @see <a href="https://en.wikipedia.org/wiki/Bit_rotation">Bit Rotation</a>
13+
*/
14+
public final class BitRotate {
15+
16+
/**
17+
* Private constructor to prevent instantiation.
18+
* This is a utility class with only static methods.
19+
*/
20+
private BitRotate() {
21+
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
22+
}
23+
24+
/**
25+
* Performs a circular left rotation (left shift) on a 32-bit integer.
26+
* Bits shifted out from the left side are inserted on the right side.
27+
*
28+
* @param value the 32-bit integer value to rotate
29+
* @param shift the number of positions to rotate left (must be non-negative)
30+
* @return the result of left rotating the value by the specified shift amount
31+
* @throws IllegalArgumentException if shift is negative
32+
*
33+
* @example
34+
* // Binary: 10000000 00000000 00000000 00000001
35+
* rotateLeft(0x80000001, 1)
36+
* // Returns: 3 (binary: 00000000 00000000 00000000 00000011)
37+
*/
38+
public static int rotateLeft(int value, int shift) {
39+
if (shift < 0) {
40+
throw new IllegalArgumentException("Shift amount cannot be negative: " + shift);
41+
}
42+
43+
// Normalize shift to the range [0, 31] using modulo 32
44+
shift = shift % 32;
45+
46+
if (shift == 0) {
47+
return value;
48+
}
49+
50+
// Left rotation: (value << shift) | (value >>> (32 - shift))
51+
return (value << shift) | (value >>> (32 - shift));
52+
}
53+
54+
/**
55+
* Performs a circular right rotation (right shift) on a 32-bit integer.
56+
* Bits shifted out from the right side are inserted on the left side.
57+
*
58+
* @param value the 32-bit integer value to rotate
59+
* @param shift the number of positions to rotate right (must be non-negative)
60+
* @return the result of right rotating the value by the specified shift amount
61+
* @throws IllegalArgumentException if shift is negative
62+
*
63+
* @example
64+
* // Binary: 00000000 00000000 00000000 00000011
65+
* rotateRight(3, 1)
66+
* // Returns: -2147483647 (binary: 10000000 00000000 00000000 00000001)
67+
*/
68+
public static int rotateRight(int value, int shift) {
69+
if (shift < 0) {
70+
throw new IllegalArgumentException("Shift amount cannot be negative: " + shift);
71+
}
72+
73+
// Normalize shift to the range [0, 31] using modulo 32
74+
shift = shift % 32;
75+
76+
if (shift == 0) {
77+
return value;
78+
}
79+
80+
// Right rotation: (value >>> shift) | (value << (32 - shift))
81+
return (value >>> shift) | (value << (32 - shift));
82+
}
83+
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package com.thealgorithms.graph;
2+
3+
import java.util.Collections;
4+
import java.util.HashMap;
5+
import java.util.HashSet;
6+
import java.util.LinkedList;
7+
import java.util.List;
8+
import java.util.Map;
9+
import java.util.Set;
10+
import java.util.Stack;
11+
12+
/**
13+
* Implementation of Hierholzer's algorithm to find an Eulerian Circuit in an undirected graph.
14+
* <p>
15+
* An Eulerian circuit is a trail in a graph that visits every edge exactly once,
16+
* starting and ending at the same vertex. This algorithm finds such a circuit if one exists.
17+
* </p>
18+
* <p>
19+
* This implementation is designed for an <strong>undirected graph</strong>. For a valid Eulerian
20+
* circuit to exist, the graph must satisfy two conditions:
21+
* <ol>
22+
* <li>All vertices with a non-zero degree must be part of a single connected component.</li>
23+
* <li>Every vertex must have an even degree (an even number of edges connected to it).</li>
24+
* </ol>
25+
* </p>
26+
* <p>
27+
* The algorithm runs in O(E + V) time, where E is the number of edges and V is the number of vertices.
28+
* The graph is represented by a Map where keys are vertices and values are a LinkedList of adjacent vertices.
29+
* </p>
30+
*
31+
* @see <a href="https://en.wikipedia.org/wiki/Eulerian_path#Hierholzer's_algorithm">Wikipedia: Hierholzer's algorithm</a>
32+
*/
33+
public final class HierholzerAlgorithm {
34+
35+
private final Map<Integer, LinkedList<Integer>> graph;
36+
37+
public HierholzerAlgorithm(Map<Integer, LinkedList<Integer>> graph) {
38+
this.graph = (graph == null) ? new HashMap<>() : graph;
39+
}
40+
41+
public boolean hasEulerianCircuit() {
42+
if (graph.isEmpty()) {
43+
return true;
44+
}
45+
46+
for (List<Integer> neighbors : graph.values()) {
47+
if (neighbors.size() % 2 != 0) {
48+
return false;
49+
}
50+
}
51+
52+
return isCoherentlyConnected();
53+
}
54+
55+
public List<Integer> findEulerianCircuit() {
56+
if (!hasEulerianCircuit()) {
57+
return Collections.emptyList();
58+
}
59+
60+
Map<Integer, LinkedList<Integer>> tempGraph = new HashMap<>();
61+
for (Map.Entry<Integer, LinkedList<Integer>> entry : graph.entrySet()) {
62+
tempGraph.put(entry.getKey(), new LinkedList<>(entry.getValue()));
63+
}
64+
65+
Stack<Integer> currentPath = new Stack<>();
66+
LinkedList<Integer> circuit = new LinkedList<>();
67+
68+
int startVertex = -1;
69+
for (Map.Entry<Integer, LinkedList<Integer>> entry : tempGraph.entrySet()) {
70+
if (!entry.getValue().isEmpty()) {
71+
startVertex = entry.getKey();
72+
break;
73+
}
74+
}
75+
76+
if (startVertex == -1) {
77+
if (graph.isEmpty()) {
78+
return Collections.emptyList();
79+
}
80+
return Collections.singletonList(graph.keySet().iterator().next());
81+
}
82+
83+
currentPath.push(startVertex);
84+
85+
while (!currentPath.isEmpty()) {
86+
int currentVertex = currentPath.peek();
87+
88+
if (tempGraph.containsKey(currentVertex) && !tempGraph.get(currentVertex).isEmpty()) {
89+
int nextVertex = tempGraph.get(currentVertex).pollFirst();
90+
tempGraph.get(nextVertex).remove(Integer.valueOf(currentVertex));
91+
currentPath.push(nextVertex);
92+
} else {
93+
circuit.addFirst(currentVertex);
94+
currentPath.pop();
95+
}
96+
}
97+
98+
return circuit;
99+
}
100+
101+
private boolean isCoherentlyConnected() {
102+
if (graph.isEmpty()) {
103+
return true;
104+
}
105+
106+
Set<Integer> visited = new HashSet<>();
107+
int startNode = -1;
108+
109+
for (Map.Entry<Integer, LinkedList<Integer>> entry : graph.entrySet()) {
110+
if (!entry.getValue().isEmpty()) {
111+
startNode = entry.getKey();
112+
break;
113+
}
114+
}
115+
116+
if (startNode == -1) {
117+
return true;
118+
}
119+
120+
dfs(startNode, visited);
121+
122+
for (Map.Entry<Integer, LinkedList<Integer>> entry : graph.entrySet()) {
123+
if (!entry.getValue().isEmpty() && !visited.contains(entry.getKey())) {
124+
return false;
125+
}
126+
}
127+
return true;
128+
}
129+
130+
private void dfs(int u, Set<Integer> visited) {
131+
visited.add(u);
132+
if (graph.containsKey(u)) {
133+
for (int v : graph.get(u)) {
134+
if (!visited.contains(v)) {
135+
dfs(v, visited);
136+
}
137+
}
138+
}
139+
}
140+
}

src/main/java/com/thealgorithms/maths/Area.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,25 @@ public static double surfaceAreaSphere(final double radius) {
4848
return 4 * Math.PI * radius * radius;
4949
}
5050

51+
/**
52+
* Calculate the surface area of a pyramid with a square base.
53+
*
54+
* @param sideLength side length of the square base
55+
* @param slantHeight slant height of the pyramid
56+
* @return surface area of the given pyramid
57+
*/
58+
public static double surfaceAreaPyramid(final double sideLength, final double slantHeight) {
59+
if (sideLength <= 0) {
60+
throw new IllegalArgumentException("Must be a positive sideLength");
61+
}
62+
if (slantHeight <= 0) {
63+
throw new IllegalArgumentException("Must be a positive slantHeight");
64+
}
65+
double baseArea = sideLength * sideLength;
66+
double lateralSurfaceArea = 2 * sideLength * slantHeight;
67+
return baseArea + lateralSurfaceArea;
68+
}
69+
5170
/**
5271
* Calculate the area of a rectangle.
5372
*

src/main/java/com/thealgorithms/maths/JugglerSequence.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public static void jugglerSequence(int inputNumber) {
4343
seq.add(n + "");
4444
}
4545
String res = String.join(",", seq);
46-
System.out.println(res);
46+
System.out.print(res + "\n");
4747
}
4848

4949
// Driver code
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package com.thealgorithms.matrix;
2+
3+
/**
4+
* LU Decomposition algorithm
5+
* --------------------------
6+
* Decomposes a square matrix a into a product of two matrices:
7+
* a = l * u
8+
* where:
9+
* - l is a lower triangular matrix with 1s on its diagonal
10+
* - u is an upper triangular matrix
11+
*
12+
* Reference:
13+
* https://en.wikipedia.org/wiki/lu_decomposition
14+
*/
15+
public final class LUDecomposition {
16+
17+
private LUDecomposition() {
18+
}
19+
20+
/**
21+
* A helper class to store both l and u matrices
22+
*/
23+
public static class LU {
24+
double[][] l;
25+
double[][] u;
26+
27+
LU(double[][] l, double[][] u) {
28+
this.l = l;
29+
this.u = u;
30+
}
31+
}
32+
33+
/**
34+
* Performs LU Decomposition on a square matrix a
35+
*
36+
* @param a input square matrix
37+
* @return LU object containing l and u matrices
38+
*/
39+
public static LU decompose(double[][] a) {
40+
int n = a.length;
41+
double[][] l = new double[n][n];
42+
double[][] u = new double[n][n];
43+
44+
for (int i = 0; i < n; i++) {
45+
// upper triangular matrix
46+
for (int k = i; k < n; k++) {
47+
double sum = 0;
48+
for (int j = 0; j < i; j++) {
49+
sum += l[i][j] * u[j][k];
50+
}
51+
u[i][k] = a[i][k] - sum;
52+
}
53+
54+
// lower triangular matrix
55+
for (int k = i; k < n; k++) {
56+
if (i == k) {
57+
l[i][i] = 1; // diagonal as 1
58+
} else {
59+
double sum = 0;
60+
for (int j = 0; j < i; j++) {
61+
sum += l[k][j] * u[j][i];
62+
}
63+
l[k][i] = (a[k][i] - sum) / u[i][i];
64+
}
65+
}
66+
}
67+
68+
return new LU(l, u);
69+
}
70+
71+
/**
72+
* Utility function to print a matrix
73+
*
74+
* @param m matrix to print
75+
*/
76+
public static void printMatrix(double[][] m) {
77+
for (double[] row : m) {
78+
System.out.print("[");
79+
for (int j = 0; j < row.length; j++) {
80+
System.out.printf("%7.3f", row[j]);
81+
if (j < row.length - 1) {
82+
System.out.print(", ");
83+
}
84+
}
85+
System.out.println("]");
86+
}
87+
}
88+
}

0 commit comments

Comments
 (0)