Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions Data Structures/DisjointSetUnion.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/**
* Disjoint Set Union (Union-Find) with path compression and union by rank.
*
* <p>This data structure maintains a collection of disjoint sets over elements labeled
* {@code 0..n-1}. It supports near-constant-time merging of sets and connectivity queries, which
* makes it a staple for Kruskal's minimum spanning tree algorithm, offline connectivity problems,
* and clustering applications.</p>
*/
public class DisjointSetUnion {

private final int[] parent;
private final int[] rank;
private final int[] size;
private int components;

/**
* Creates {@code n} singleton sets {0}, {1}, ..., {n-1}.
*/
public DisjointSetUnion(int n) {
if (n <= 0) {
throw new IllegalArgumentException("Size must be positive");
}
this.parent = new int[n];
this.rank = new int[n];
this.size = new int[n];
this.components = n;
for (int i = 0; i < n; i++) {
parent[i] = i;
size[i] = 1;
}
}

/**
* Finds the representative for {@code x} using path compression.
*/
public int find(int x) {
if (parent[x] != x) {
parent[x] = find(parent[x]);
}
return parent[x];
}

/**
* Merges the sets containing {@code a} and {@code b}. Returns {@code true} if the sets were
* previously disjoint.
*/
public boolean union(int a, int b) {
int rootA = find(a);
int rootB = find(b);
if (rootA == rootB) {
return false;
}
if (rank[rootA] < rank[rootB]) {
int tmp = rootA;
rootA = rootB;
rootB = tmp;
}
parent[rootB] = rootA;
size[rootA] += size[rootB];
if (rank[rootA] == rank[rootB]) {
rank[rootA]++;
}
components--;
return true;
}

/**
* Returns the size of the set containing {@code x}.
*/
public int componentSize(int x) {
return size[find(x)];
}

/**
* Returns how many disjoint components remain.
*/
public int components() {
return components;
}

public static void main(String[] args) {
DisjointSetUnion dsu = new DisjointSetUnion(10);
dsu.union(1, 2);
dsu.union(2, 3);
dsu.union(4, 5);
dsu.union(6, 7);
dsu.union(7, 8);
System.out.println("Components: " + dsu.components());
System.out.println("1 and 3 connected? " + (dsu.find(1) == dsu.find(3)));
System.out.println("1 and 8 connected? " + (dsu.find(1) == dsu.find(8)));
dsu.union(3, 7);
System.out.println("Components after union(3, 7): " + dsu.components());
System.out.println("Size of component containing 7: " + dsu.componentSize(7));
}
}
15 changes: 8 additions & 7 deletions Data Structures/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# Data Structures
* [Binary Indexed Tree (Fenwick Tree)](https://github.com/jpa99/Algorithms/edit/master/Data%20Structures/Binary_Indexed_Tree.java)
* [Binary Tree](https://github.com/jpa99/Algorithms/edit/master/Data%20Structures/BinaryTree.java)
* [Tree](https://github.com/jpa99/Algorithms/edit/master/Data%20Structures/Tree.java)
* [Graph](https://github.com/jpa99/Algorithms/edit/master/Data%20Structures/Graphs.java)
+ [Edge](https://github.com/jpa99/Algorithms/edit/master/Data%20Structures/Edge.java)
+ [Vertex](https://github.com/jpa99/Algorithms/edit/master/Data%20Structures/Vertex.java)

* [Binary Indexed Tree (Fenwick Tree)](Binary_Indexed_Tree.java)
* [Binary Tree](BinaryTree.java)
* [Tree](Tree.java)
* [Graph](Graphs.java)
+ [Edge](Edge.java)
+ [Vertex](Vertex.java)
* [Disjoint Set Union (Union-Find)](DisjointSetUnion.java)
* [Segment Tree](SegmentTree.java)
137 changes: 137 additions & 0 deletions Data Structures/SegmentTree.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import java.util.Arrays;

/**
* Segment tree for range sum and minimum queries with point updates.
*
* <p>This implementation exposes both range sum and range minimum queries to demonstrate how a
* single tree can maintain multiple aggregate statistics. It is designed for educational purposes
* to showcase how a tree decomposes an array into power-of-two intervals for logarithmic query and
* update times.</p>
*/
public class SegmentTree {

private final int size;
private final long[] sumTree;
private final long[] minTree;

/**
* Builds the tree using the provided input array.
*
* @param values the array whose values should be indexed. The array is copied so that updates do
* not mutate the caller's data.
*/
public SegmentTree(long[] values) {
this.size = values.length;
int treeSize = 1;
while (treeSize < size) {
treeSize <<= 1;
}
treeSize <<= 1; // allocate enough space for the full binary tree
this.sumTree = new long[treeSize];
this.minTree = new long[treeSize];
build(1, 0, size - 1, Arrays.copyOf(values, values.length));
}

private void build(int node, int left, int right, long[] values) {
if (left == right) {
sumTree[node] = values[left];
minTree[node] = values[left];
return;
}
int mid = left + (right - left) / 2;
build(node * 2, left, mid, values);
build(node * 2 + 1, mid + 1, right, values);
pull(node);
}

/**
* Performs a range sum query on the inclusive interval [queryLeft, queryRight].
*/
public long rangeSum(int queryLeft, int queryRight) {
validateRange(queryLeft, queryRight);
return rangeSum(1, 0, size - 1, queryLeft, queryRight);
}

private long rangeSum(int node, int left, int right, int queryLeft, int queryRight) {
if (queryLeft > right || queryRight < left) {
return 0;
}
if (queryLeft <= left && right <= queryRight) {
return sumTree[node];
}
int mid = left + (right - left) / 2;
return rangeSum(node * 2, left, mid, queryLeft, queryRight)
+ rangeSum(node * 2 + 1, mid + 1, right, queryLeft, queryRight);
}

/**
* Performs a range minimum query on the inclusive interval [queryLeft, queryRight].
*/
public long rangeMin(int queryLeft, int queryRight) {
validateRange(queryLeft, queryRight);
return rangeMin(1, 0, size - 1, queryLeft, queryRight);
}

private long rangeMin(int node, int left, int right, int queryLeft, int queryRight) {
if (queryLeft > right || queryRight < left) {
return Long.MAX_VALUE;
}
if (queryLeft <= left && right <= queryRight) {
return minTree[node];
}
int mid = left + (right - left) / 2;
return Math.min(
rangeMin(node * 2, left, mid, queryLeft, queryRight),
rangeMin(node * 2 + 1, mid + 1, right, queryLeft, queryRight));
}

/**
* Updates the value at {@code index} to {@code newValue}.
*/
public void update(int index, long newValue) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("Index " + index + " is outside the tree");
}
update(1, 0, size - 1, index, newValue);
}

private void update(int node, int left, int right, int index, long newValue) {
if (left == right) {
sumTree[node] = newValue;
minTree[node] = newValue;
return;
}
int mid = left + (right - left) / 2;
if (index <= mid) {
update(node * 2, left, mid, index, newValue);
} else {
update(node * 2 + 1, mid + 1, right, index, newValue);
}
pull(node);
}

private void pull(int node) {
sumTree[node] = sumTree[node * 2] + sumTree[node * 2 + 1];
minTree[node] = Math.min(minTree[node * 2], minTree[node * 2 + 1]);
}

private void validateRange(int left, int right) {
if (left < 0 || right >= size || left > right) {
throw new IllegalArgumentException(
"Invalid query range [" + left + ", " + right + "] for size " + size);
}
}

public static void main(String[] args) {
long[] values = {5, 2, 9, -4, 7, 6, 3, 8};
SegmentTree tree = new SegmentTree(values);
System.out.println("Initial sum [0, 7]: " + tree.rangeSum(0, 7));
System.out.println("Initial min [2, 5]: " + tree.rangeMin(2, 5));

tree.update(3, 10);
System.out.println("After updating index 3 to 10");
System.out.println("Sum [0, 7]: " + tree.rangeSum(0, 7));
System.out.println("Min [2, 5]: " + tree.rangeMin(2, 5));
System.out.println("Min [3, 3]: " + tree.rangeMin(3, 3));
}
}
147 changes: 147 additions & 0 deletions Optimization/LinearProgrammingSimplex.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import java.util.Arrays;

/**
* Solves linear programs of the form maximize c^T x subject to Ax <= b and x >= 0 using the simplex
* algorithm.
*
* <p>The implementation follows the textbook tableau method and automatically introduces slack
* variables to obtain an initial basic feasible solution. It is intended for classroom-sized
* problems, so the implementation favors clarity over advanced pivoting rules.</p>
*/
public class LinearProgrammingSimplex {

private static final double EPS = 1e-9;

private final int constraints;
private final int variables;
private final double[][] tableau;
private final int[] basis;

/**
* Constructs a simplex solver.
*
* @param A constraint matrix where each row corresponds to an inequality of the form
* A[i] * x <= b[i]
* @param b right-hand side vector
* @param c objective function coefficients for maximize c^T x
*/
public LinearProgrammingSimplex(double[][] A, double[] b, double[] c) {
this.constraints = b.length;
this.variables = c.length;
int width = variables + constraints + 1;
this.tableau = new double[constraints + 1][width];
this.basis = new int[constraints];

for (int i = 0; i < constraints; i++) {
if (A[i].length != variables) {
throw new IllegalArgumentException("Row " + i + " has incorrect length");
}
System.arraycopy(A[i], 0, tableau[i], 0, variables);
tableau[i][variables + i] = 1.0; // slack variable
if (b[i] < 0) {
throw new IllegalArgumentException("Right-hand side must be non-negative");
}
tableau[i][width - 1] = b[i];
basis[i] = variables + i;
}

for (int j = 0; j < variables; j++) {
tableau[constraints][j] = -c[j];
}

solve();
}

private void solve() {
while (true) {
int entering = enteringColumn();
if (entering == -1) {
break; // optimal reached
}
int leaving = leavingRow(entering);
if (leaving == -1) {
throw new IllegalStateException("Linear program is unbounded");
}
pivot(leaving, entering);
basis[leaving] = entering;
}
}

private int enteringColumn() {
int width = tableau[0].length;
for (int j = 0; j < width - 1; j++) {
if (tableau[constraints][j] > EPS) {
return j;
}
}
return -1;
}

private int leavingRow(int entering) {
double bestRatio = Double.POSITIVE_INFINITY;
int row = -1;
for (int i = 0; i < constraints; i++) {
if (tableau[i][entering] > EPS) {
double ratio = tableau[i][tableau[i].length - 1] / tableau[i][entering];
if (ratio < bestRatio - EPS) {
bestRatio = ratio;
row = i;
}
}
}
return row;
}

private void pivot(int pivotRow, int pivotColumn) {
double pivot = tableau[pivotRow][pivotColumn];
for (int j = 0; j < tableau[pivotRow].length; j++) {
tableau[pivotRow][j] /= pivot;
}
for (int i = 0; i < tableau.length; i++) {
if (i == pivotRow) {
continue;
}
double factor = tableau[i][pivotColumn];
if (Math.abs(factor) < EPS) {
continue;
}
for (int j = 0; j < tableau[i].length; j++) {
tableau[i][j] -= factor * tableau[pivotRow][j];
}
}
}

/**
* Returns the optimal primal solution.
*/
public double[] primal() {
double[] solution = new double[variables];
for (int i = 0; i < constraints; i++) {
if (basis[i] < variables) {
solution[basis[i]] = tableau[i][tableau[i].length - 1];
}
}
return solution;
}

/**
* Returns the optimal objective value.
*/
public double value() {
return tableau[constraints][tableau[constraints].length - 1];
}

public static void main(String[] args) {
double[][] A = {
{2, 1},
{1, 2},
{1, 0}
};
double[] b = {14, 14, 6};
double[] c = {3, 2};

LinearProgrammingSimplex simplex = new LinearProgrammingSimplex(A, b, c);
System.out.println("Optimal value: " + simplex.value());
System.out.println("Solution: " + Arrays.toString(simplex.primal()));
}
}
Loading