Skip to content

Commit 1863193

Browse files
Merge branch 'master' into master
2 parents 4e0c78b + 746457c commit 1863193

33 files changed

+1739
-32
lines changed

.github/workflows/infer.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333

3434
- name: Cache infer build
3535
id: cache-infer
36-
uses: actions/cache@v4
36+
uses: actions/cache@v5
3737
with:
3838
path: infer
3939
key: ${{ runner.os }}-infer-${{ env.year_week }}

.gitpod.dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM gitpod/workspace-java-21:2025-10-06-13-14-25
1+
FROM gitpod/workspace-java-21:2025-11-14-10-05-32
22

33
ENV LLVM_SCRIPT="tmp_llvm.sh"
44

DIRECTORY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,7 @@
385385
- 📄 [Dinic](src/main/java/com/thealgorithms/graph/Dinic.java)
386386
- 📄 [Edmonds](src/main/java/com/thealgorithms/graph/Edmonds.java)
387387
- 📄 [EdmondsKarp](src/main/java/com/thealgorithms/graph/EdmondsKarp.java)
388+
- 📄 [GomoryHuTree](src/main/java/com/thealgorithms/graph/GomoryHuTree.java)
388389
- 📄 [HierholzerAlgorithm](src/main/java/com/thealgorithms/graph/HierholzerAlgorithm.java)
389390
- 📄 [HierholzerEulerianPath](src/main/java/com/thealgorithms/graph/HierholzerEulerianPath.java)
390391
- 📄 [HopcroftKarp](src/main/java/com/thealgorithms/graph/HopcroftKarp.java)

pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
<dependency>
4343
<groupId>org.mockito</groupId>
4444
<artifactId>mockito-core</artifactId>
45-
<version>5.20.0</version>
45+
<version>5.21.0</version>
4646
<scope>test</scope>
4747
</dependency>
4848
<dependency>
@@ -112,7 +112,7 @@
112112
<dependency>
113113
<groupId>com.puppycrawl.tools</groupId>
114114
<artifactId>checkstyle</artifactId>
115-
<version>12.1.2</version>
115+
<version>12.2.0</version>
116116
</dependency>
117117
</dependencies>
118118
</plugin>
@@ -127,7 +127,7 @@
127127
<plugin>
128128
<groupId>com.mebigfatguy.fb-contrib</groupId>
129129
<artifactId>fb-contrib</artifactId>
130-
<version>7.7.0</version>
130+
<version>7.7.2</version>
131131
</plugin>
132132
<plugin>
133133
<groupId>com.h3xstream.findsecbugs</groupId>

src/main/java/com/thealgorithms/backtracking/Combination.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
import java.util.TreeSet;
88

99
/**
10-
* Finds all permutations of given array
11-
* @author Alan Piao (<a href="https://github.com/cpiao3">git-Alan Piao</a>)
10+
* Finds all combinations of a given array using backtracking algorithm * @author Alan Piao (<a href="https://github.com/cpiao3">git-Alan Piao</a>)
1211
*/
1312
public final class Combination {
1413
private Combination() {
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package com.thealgorithms.ciphers;
2+
3+
import java.security.SecureRandom;
4+
import java.util.Objects;
5+
6+
/**
7+
* One-Time Pad (OTP) cipher implementation.
8+
*
9+
* <p>The One-Time Pad is information-theoretically secure if:
10+
* <ul>
11+
* <li>The key is truly random.</li>
12+
* <li>The key length is at least as long as the plaintext.</li>
13+
* <li>The key is used only once and kept secret.</li>
14+
* </ul>
15+
*
16+
* <p>This implementation is for <b>educational purposes only</b> and should not be
17+
* used in production systems.
18+
*/
19+
public final class OneTimePadCipher {
20+
21+
private static final SecureRandom RANDOM = new SecureRandom();
22+
23+
private OneTimePadCipher() {
24+
// utility class
25+
}
26+
27+
/**
28+
* Generates a random key of the given length in bytes.
29+
*
30+
* @param length the length of the key in bytes, must be non-negative
31+
* @return a new random key
32+
* @throws IllegalArgumentException if length is negative
33+
*/
34+
public static byte[] generateKey(int length) {
35+
if (length < 0) {
36+
throw new IllegalArgumentException("length must be non-negative");
37+
}
38+
byte[] key = new byte[length];
39+
RANDOM.nextBytes(key);
40+
return key;
41+
}
42+
43+
/**
44+
* Encrypts the given plaintext bytes using the provided key.
45+
* <p>The key length must be exactly the same as the plaintext length.
46+
*
47+
* @param plaintext the plaintext bytes, must not be {@code null}
48+
* @param key the one-time pad key bytes, must not be {@code null}
49+
* @return the ciphertext bytes
50+
* @throws IllegalArgumentException if the key length does not match plaintext length
51+
* @throws NullPointerException if plaintext or key is {@code null}
52+
*/
53+
public static byte[] encrypt(byte[] plaintext, byte[] key) {
54+
validateInputs(plaintext, key);
55+
return xor(plaintext, key);
56+
}
57+
58+
/**
59+
* Decrypts the given ciphertext bytes using the provided key.
60+
* <p>For a One-Time Pad, decryption is identical to encryption:
61+
* {@code plaintext = ciphertext XOR key}.
62+
*
63+
* @param ciphertext the ciphertext bytes, must not be {@code null}
64+
* @param key the one-time pad key bytes, must not be {@code null}
65+
* @return the decrypted plaintext bytes
66+
* @throws IllegalArgumentException if the key length does not match ciphertext length
67+
* @throws NullPointerException if ciphertext or key is {@code null}
68+
*/
69+
public static byte[] decrypt(byte[] ciphertext, byte[] key) {
70+
validateInputs(ciphertext, key);
71+
return xor(ciphertext, key);
72+
}
73+
74+
private static void validateInputs(byte[] input, byte[] key) {
75+
Objects.requireNonNull(input, "input must not be null");
76+
Objects.requireNonNull(key, "key must not be null");
77+
if (input.length != key.length) {
78+
throw new IllegalArgumentException("Key length must match input length");
79+
}
80+
}
81+
82+
private static byte[] xor(byte[] data, byte[] key) {
83+
byte[] result = new byte[data.length];
84+
for (int i = 0; i < data.length; i++) {
85+
result[i] = (byte) (data[i] ^ key[i]);
86+
}
87+
return result;
88+
}
89+
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*
2+
* TheAlgorithms (https://github.com/TheAlgorithms/Java)
3+
* Author: Shewale41
4+
* This file is licensed under the MIT License.
5+
*/
6+
7+
package com.thealgorithms.datastructures.trees;
8+
9+
import java.util.ArrayList;
10+
import java.util.List;
11+
12+
/**
13+
* Threaded binary tree implementation that supports insertion and
14+
* in-order traversal without recursion or stack by using threads.
15+
*
16+
* <p>In this implementation, a node's null left/right pointers are used
17+
* to point to the in-order predecessor/successor respectively. Two flags
18+
* indicate whether left/right pointers are real children or threads.
19+
*
20+
* @see <a href="https://en.wikipedia.org/wiki/Threaded_binary_tree">Wikipedia:
21+
* Threaded binary tree</a>
22+
*/
23+
public final class ThreadedBinaryTree {
24+
25+
private Node root;
26+
27+
private static final class Node {
28+
int value;
29+
Node left;
30+
Node right;
31+
boolean leftIsThread;
32+
boolean rightIsThread;
33+
34+
Node(int value) {
35+
this.value = value;
36+
this.left = null;
37+
this.right = null;
38+
this.leftIsThread = false;
39+
this.rightIsThread = false;
40+
}
41+
}
42+
43+
public ThreadedBinaryTree() {
44+
this.root = null;
45+
}
46+
47+
/**
48+
* Inserts a value into the threaded binary tree. Duplicate values are inserted
49+
* to the right subtree (consistent deterministic rule).
50+
*
51+
* @param value the integer value to insert
52+
*/
53+
public void insert(int value) {
54+
Node newNode = new Node(value);
55+
if (root == null) {
56+
root = newNode;
57+
return;
58+
}
59+
60+
Node current = root;
61+
Node parent = null;
62+
63+
while (true) {
64+
parent = current;
65+
if (value < current.value) {
66+
if (!current.leftIsThread && current.left != null) {
67+
current = current.left;
68+
} else {
69+
break;
70+
}
71+
} else { // value >= current.value
72+
if (!current.rightIsThread && current.right != null) {
73+
current = current.right;
74+
} else {
75+
break;
76+
}
77+
}
78+
}
79+
80+
if (value < parent.value) {
81+
// attach newNode as left child
82+
newNode.left = parent.left;
83+
newNode.leftIsThread = parent.leftIsThread;
84+
newNode.right = parent;
85+
newNode.rightIsThread = true;
86+
87+
parent.left = newNode;
88+
parent.leftIsThread = false;
89+
} else {
90+
// attach newNode as right child
91+
newNode.right = parent.right;
92+
newNode.rightIsThread = parent.rightIsThread;
93+
newNode.left = parent;
94+
newNode.leftIsThread = true;
95+
96+
parent.right = newNode;
97+
parent.rightIsThread = false;
98+
}
99+
}
100+
101+
/**
102+
* Returns the in-order traversal of the tree as a list of integers.
103+
* Traversal is done without recursion or an explicit stack by following threads.
104+
*
105+
* @return list containing the in-order sequence of node values
106+
*/
107+
public List<Integer> inorderTraversal() {
108+
List<Integer> result = new ArrayList<>();
109+
Node current = root;
110+
if (current == null) {
111+
return result;
112+
}
113+
114+
// Move to the leftmost node
115+
while (current.left != null && !current.leftIsThread) {
116+
current = current.left;
117+
}
118+
119+
while (current != null) {
120+
result.add(current.value);
121+
122+
// If right pointer is a thread, follow it
123+
if (current.rightIsThread) {
124+
current = current.right;
125+
} else {
126+
// Move to leftmost node in right subtree
127+
current = current.right;
128+
while (current != null && !current.leftIsThread && current.left != null) {
129+
current = current.left;
130+
}
131+
}
132+
}
133+
134+
return result;
135+
}
136+
137+
/**
138+
* Helper: checks whether the tree is empty.
139+
*
140+
* @return true if tree has no nodes
141+
*/
142+
public boolean isEmpty() {
143+
return root == null;
144+
}
145+
}

0 commit comments

Comments
 (0)