Skip to content

Commit e13bf32

Browse files
Merge branch 'master' into fix/binary-search-null-key-handling
2 parents 091ef22 + ee34336 commit e13bf32

File tree

8 files changed

+555
-11
lines changed

8 files changed

+555
-11
lines changed

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,14 +112,14 @@
112112
<dependency>
113113
<groupId>com.puppycrawl.tools</groupId>
114114
<artifactId>checkstyle</artifactId>
115-
<version>13.3.0</version>
115+
<version>13.4.0</version>
116116
</dependency>
117117
</dependencies>
118118
</plugin>
119119
<plugin>
120120
<groupId>com.github.spotbugs</groupId>
121121
<artifactId>spotbugs-maven-plugin</artifactId>
122-
<version>4.9.8.2</version>
122+
<version>4.9.8.3</version>
123123
<configuration>
124124
<excludeFilterFile>spotbugs-exclude.xml</excludeFilterFile>
125125
<includeTests>true</includeTests>
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package com.thealgorithms.graph;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
/**
7+
* Implementation of Tarjan's Bridge-Finding Algorithm for undirected graphs.
8+
*
9+
* <p>A <b>bridge</b> (also called a cut-edge) is an edge in an undirected graph whose removal
10+
* increases the number of connected components. Bridges represent critical links
11+
* in a network — if any bridge is removed, part of the network becomes unreachable.</p>
12+
*
13+
* <p>The algorithm performs a single Depth-First Search (DFS) traversal, tracking two
14+
* values for each vertex:</p>
15+
* <ul>
16+
* <li><b>discoveryTime</b> — the time step at which the vertex was first visited.</li>
17+
* <li><b>lowLink</b> — the smallest discovery time reachable from the subtree rooted
18+
* at that vertex (via back edges).</li>
19+
* </ul>
20+
*
21+
* <p>An edge (u, v) is a bridge if and only if {@code lowLink[v] > discoveryTime[u]},
22+
* meaning there is no back edge from the subtree of v that can reach u or any ancestor of u.</p>
23+
*
24+
* <p>Time Complexity: O(V + E), where V is the number of vertices and E is the number of edges.</p>
25+
* <p>Space Complexity: O(V + E) for the adjacency list, discovery/low arrays, and recursion stack.</p>
26+
*
27+
* @see <a href="https://en.wikipedia.org/wiki/Bridge_(graph_theory)">Wikipedia: Bridge (graph theory)</a>
28+
*/
29+
public final class TarjanBridges {
30+
31+
private TarjanBridges() {
32+
throw new UnsupportedOperationException("Utility class");
33+
}
34+
35+
/**
36+
* Finds all bridge edges in an undirected graph.
37+
*
38+
* <p>The graph is represented as an adjacency list where each vertex is identified by
39+
* an integer in the range {@code [0, vertexCount)}. For each undirected edge (u, v),
40+
* v must appear in {@code adjacencyList.get(u)} and u must appear in
41+
* {@code adjacencyList.get(v)}.</p>
42+
*
43+
* @param vertexCount the total number of vertices in the graph (must be non-negative)
44+
* @param adjacencyList the adjacency list representation of the graph; must contain
45+
* exactly {@code vertexCount} entries (one per vertex)
46+
* @return a list of bridge edges, where each bridge is represented as an {@code int[]}
47+
* of length 2 with {@code edge[0] < edge[1]}; returns an empty list if no bridges exist
48+
* @throws IllegalArgumentException if {@code vertexCount} is negative, or if
49+
* {@code adjacencyList} is null or its size does not match
50+
* {@code vertexCount}
51+
*/
52+
public static List<int[]> findBridges(int vertexCount, List<List<Integer>> adjacencyList) {
53+
if (vertexCount < 0) {
54+
throw new IllegalArgumentException("vertexCount must be non-negative");
55+
}
56+
if (adjacencyList == null || adjacencyList.size() != vertexCount) {
57+
throw new IllegalArgumentException("adjacencyList size must equal vertexCount");
58+
}
59+
60+
List<int[]> bridges = new ArrayList<>();
61+
62+
if (vertexCount == 0) {
63+
return bridges;
64+
}
65+
66+
BridgeFinder finder = new BridgeFinder(vertexCount, adjacencyList, bridges);
67+
68+
// Run DFS from every unvisited vertex to handle disconnected graphs
69+
for (int i = 0; i < vertexCount; i++) {
70+
if (!finder.visited[i]) {
71+
finder.dfs(i, -1);
72+
}
73+
}
74+
75+
return bridges;
76+
}
77+
78+
private static class BridgeFinder {
79+
private final List<List<Integer>> adjacencyList;
80+
private final List<int[]> bridges;
81+
private final int[] discoveryTime;
82+
private final int[] lowLink;
83+
boolean[] visited;
84+
private int timer;
85+
86+
BridgeFinder(int vertexCount, List<List<Integer>> adjacencyList, List<int[]> bridges) {
87+
this.adjacencyList = adjacencyList;
88+
this.bridges = bridges;
89+
this.discoveryTime = new int[vertexCount];
90+
this.lowLink = new int[vertexCount];
91+
this.visited = new boolean[vertexCount];
92+
this.timer = 0;
93+
}
94+
95+
/**
96+
* Performs DFS from the given vertex, computing discovery times and low-link values,
97+
* and collects any bridge edges found.
98+
*
99+
* @param u the current vertex being explored
100+
* @param parent the parent of u in the DFS tree (-1 if u is a root)
101+
*/
102+
void dfs(int u, int parent) {
103+
visited[u] = true;
104+
discoveryTime[u] = timer;
105+
lowLink[u] = timer;
106+
timer++;
107+
108+
for (int v : adjacencyList.get(u)) {
109+
if (!visited[v]) {
110+
dfs(v, u);
111+
lowLink[u] = Math.min(lowLink[u], lowLink[v]);
112+
113+
if (lowLink[v] > discoveryTime[u]) {
114+
bridges.add(new int[] {Math.min(u, v), Math.max(u, v)});
115+
}
116+
} else if (v != parent) {
117+
lowLink[u] = Math.min(lowLink[u], discoveryTime[v]);
118+
}
119+
}
120+
}
121+
}
122+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.thealgorithms.maths;
2+
3+
/**
4+
* Class for correlation of two discrete variables
5+
*/
6+
7+
public final class Correlation {
8+
private Correlation() {
9+
}
10+
11+
public static final double DELTA = 1e-9;
12+
13+
/**
14+
* Discrete correlation function.
15+
* Correlation between two discrete variables is calculated
16+
* according to the formula: Cor(x, y)=Cov(x, y)/sqrt(Var(x)*Var(y)).
17+
* Correlation with a constant variable is taken to be zero.
18+
*
19+
* @param x The first discrete variable
20+
* @param y The second discrete variable
21+
* @param n The number of values for each variable
22+
* @return The result of the correlation of variables x,y.
23+
*/
24+
public static double correlation(double[] x, double[] y, int n) {
25+
double exy = 0; // E(XY)
26+
double ex = 0; // E(X)
27+
double exx = 0; // E(X^2)
28+
double ey = 0; // E(Y)
29+
double eyy = 0; // E(Y^2)
30+
for (int i = 0; i < n; i++) {
31+
exy += x[i] * y[i];
32+
ex += x[i];
33+
exx += x[i] * x[i];
34+
ey += y[i];
35+
eyy += y[i] * y[i];
36+
}
37+
exy /= n;
38+
ex /= n;
39+
exx /= n;
40+
ey /= n;
41+
eyy /= n;
42+
double cov = exy - ex * ey; // Cov(X, Y) = E(XY)-E(X)E(Y)
43+
double varx = Math.sqrt(exx - ex * ex); // Var(X) = sqrt(E(X^2)-E(X)^2)
44+
double vary = Math.sqrt(eyy - ey * ey); // Var(Y) = sqrt(E(Y^2)-E(Y)^2)
45+
if (varx * vary < DELTA) { // Var(X) = 0 means X = const, the same about Y
46+
return 0;
47+
} else {
48+
return cov / Math.sqrt(varx * vary);
49+
}
50+
}
51+
}

src/main/java/com/thealgorithms/searches/JumpSearch.java

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,50 @@
1212
* Once the range is found, a linear search is performed within that block.
1313
*
1414
* <p>
15-
* The Jump Search algorithm is particularly effective for large sorted arrays where the cost of
16-
* performing a linear search on the entire array would be prohibitive.
15+
* <b>How it works:</b>
16+
* <ol>
17+
* <li>Calculate the optimal block size as √n (square root of array length)</li>
18+
* <li>Jump ahead by the block size until the current element is greater than the target</li>
19+
* <li>Perform a linear search backwards within the identified block</li>
20+
* </ol>
1721
*
1822
* <p>
19-
* Worst-case performance: O(√N)<br>
20-
* Best-case performance: O(1)<br>
21-
* Average performance: O(√N)<br>
22-
* Worst-case space complexity: O(1)
23+
* <b>Example:</b><br>
24+
* Array: [1, 3, 5, 7, 9, 11, 13, 15, 17, 19], Target: 9<br>
25+
* Step 1: Jump from index 0 → 3 → 6 (9 < 13, so we found the block)<br>
26+
* Step 2: Linear search from index 3 to 6: found 9 at index 4<br>
27+
* Result: Index = 4
28+
*
29+
* <p>
30+
* <b>Time Complexity:</b><br>
31+
* - Best-case: O(1) - element found at first position<br>
32+
* - Average: O(√n) - optimal block size reduces jumps<br>
33+
* - Worst-case: O(√n) - element at end of array or not present<br>
34+
*
35+
* <p>
36+
* <b>Space Complexity:</b> O(1) - only uses a constant amount of extra space
37+
*
38+
* <p>
39+
* <b>Note:</b> Jump Search requires a sorted array. For unsorted arrays, use Linear Search.
40+
* Compared to Linear Search (O(n)), Jump Search is faster for large arrays.
41+
* Compared to Binary Search (O(log n)), Jump Search is less efficient but may be
42+
* preferable when jumping through a linked list or when backward scanning is costly.
2343
*
2444
* <p>
2545
* This class implements the {@link SearchAlgorithm} interface, providing a generic search method
2646
* for any comparable type.
47+
*
48+
* @see SearchAlgorithm
49+
* @see BinarySearch
50+
* @see LinearSearch
2751
*/
2852
public class JumpSearch implements SearchAlgorithm {
2953

3054
/**
3155
* Jump Search algorithm implementation.
3256
*
33-
* @param array the sorted array containing elements
34-
* @param key the element to be searched
57+
* @param array the sorted array containing elements (must be sorted in ascending order)
58+
* @param key the element to be searched for
3559
* @return the index of {@code key} if found, otherwise -1
3660
*/
3761
@Override

src/main/java/com/thealgorithms/searches/LinearSearch.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,13 @@ public class LinearSearch implements SearchAlgorithm {
4141
*
4242
* @param array List to be searched
4343
* @param value Key being searched for
44-
* @return Location of the key
44+
* @return Location of the key, -1 if array is null or empty, or key not found
4545
*/
4646
@Override
4747
public <T extends Comparable<T>> int find(T[] array, T value) {
48+
if (array == null || array.length == 0) {
49+
return -1;
50+
}
4851
for (int i = 0; i < array.length; i++) {
4952
if (array[i].compareTo(value) == 0) {
5053
return i;

0 commit comments

Comments
 (0)