Skip to content

Commit ce61a94

Browse files
Merge remote-tracking branch 'upstream/master'
2 parents e5b1527 + 849ab91 commit ce61a94

File tree

10 files changed

+429
-191
lines changed

10 files changed

+429
-191
lines changed

.gitpod.dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM gitpod/workspace-java-21:2024-11-26-08-43-19
1+
FROM gitpod/workspace-java-21:2025-02-10-10-54-28
22

33
ENV LLVM_SCRIPT="tmp_llvm.sh"
44

DIRECTORY.md

+34-21
Large diffs are not rendered by default.

pom.xml

+4-13
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>5.11.4</version>
23+
<version>5.12.0</version>
2424
<type>pom</type>
2525
<scope>import</scope>
2626
</dependency>
@@ -31,7 +31,6 @@
3131
<dependency>
3232
<groupId>org.junit.jupiter</groupId>
3333
<artifactId>junit-jupiter</artifactId>
34-
<version>5.11.4</version>
3534
<scope>test</scope>
3635
</dependency>
3736
<dependency>
@@ -46,14 +45,6 @@
4645
<version>5.15.2</version>
4746
<scope>test</scope>
4847
</dependency>
49-
50-
51-
<dependency>
52-
<groupId>org.junit.jupiter</groupId>
53-
<artifactId>junit-jupiter-api</artifactId>
54-
<version>5.11.4</version>
55-
<scope>test</scope>
56-
</dependency>
5748
<dependency>
5849
<groupId>org.apache.commons</groupId>
5950
<artifactId>commons-lang3</artifactId>
@@ -78,7 +69,7 @@
7869
<plugin>
7970
<groupId>org.apache.maven.plugins</groupId>
8071
<artifactId>maven-compiler-plugin</artifactId>
81-
<version>3.13.0</version>
72+
<version>3.14.0</version>
8273
<configuration>
8374
<source>21</source>
8475
<target>21</target>
@@ -125,14 +116,14 @@
125116
<dependency>
126117
<groupId>com.puppycrawl.tools</groupId>
127118
<artifactId>checkstyle</artifactId>
128-
<version>10.21.2</version>
119+
<version>10.21.3</version>
129120
</dependency>
130121
</dependencies>
131122
</plugin>
132123
<plugin>
133124
<groupId>com.github.spotbugs</groupId>
134125
<artifactId>spotbugs-maven-plugin</artifactId>
135-
<version>4.8.6.6</version>
126+
<version>4.9.1.0</version>
136127
<configuration>
137128
<excludeFilterFile>spotbugs-exclude.xml</excludeFilterFile>
138129
<includeTests>true</includeTests>

spotbugs-exclude.xml

+3
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@
8383
<Match>
8484
<Bug pattern="RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE" />
8585
</Match>
86+
<Match>
87+
<Bug pattern="AT_STALE_THREAD_WRITE_OF_PRIMITIVE" />
88+
</Match>
8689
<!-- fb-contrib -->
8790
<Match>
8891
<Bug pattern="LSC_LITERAL_STRING_COMPARISON" />
Original file line numberDiff line numberDiff line change
@@ -1,138 +1,126 @@
11
package com.thealgorithms.datastructures.crdt;
22

3+
import java.time.Instant;
34
import java.util.HashMap;
45
import java.util.Map;
56

67
/**
7-
* Last-Write-Wins Element Set (LWWElementSet) is a state-based CRDT (Conflict-free Replicated Data Type)
8-
* designed for managing sets in a distributed and concurrent environment. It supports the addition and removal
9-
* of elements, using timestamps to determine the order of operations. The set is split into two subsets:
10-
* the add set for elements to be added and the remove set for elements to be removed.
8+
* Last-Write-Wins Element Set (LWWElementSet) is a state-based CRDT (Conflict-free Replicated Data
9+
* Type) designed for managing sets in a distributed and concurrent environment. It supports the
10+
* addition and removal of elements, using timestamps to determine the order of operations. The set
11+
* is split into two subsets: the add set for elements to be added and the remove set for elements
12+
* to be removed. The LWWElementSet ensures that the most recent operation (based on the timestamp)
13+
* wins in the case of concurrent operations.
1114
*
12-
* @author itakurah (Niklas Hoefflin) (https://github.com/itakurah)
13-
* @see <a href="https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type">Conflict-free_replicated_data_type</a>
14-
* @see <a href="https://github.com/itakurah">itakurah (Niklas Hoefflin)</a>
15+
* @param <T> The type of the elements in the LWWElementSet.
16+
* @author <a href="https://github.com/itakurah">itakurah (GitHub)</a>, <a
17+
* href="https://www.linkedin.com/in/niklashoefflin/">Niklas Hoefflin (LinkedIn)</a>
18+
* @see <a href="https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type">Conflict free
19+
* replicated data type (Wikipedia)</a>
20+
* @see <a href="https://inria.hal.science/inria-00555588v1/document">A comprehensive study of
21+
* Convergent and Commutative Replicated Data Types</a>
1522
*/
16-
17-
class Element {
18-
String key;
19-
int timestamp;
20-
Bias bias;
23+
class LWWElementSet<T> {
24+
final Map<T, Element<T>> addSet;
25+
final Map<T, Element<T>> removeSet;
2126

2227
/**
23-
* Constructs a new Element with the specified key, timestamp and bias.
24-
*
25-
* @param key The key of the element.
26-
* @param timestamp The timestamp associated with the element.
27-
* @param bias The bias of the element (ADDS or REMOVALS).
28-
*/
29-
Element(String key, int timestamp, Bias bias) {
30-
this.key = key;
31-
this.timestamp = timestamp;
32-
this.bias = bias;
33-
}
34-
}
35-
36-
enum Bias {
37-
/**
38-
* ADDS bias for the add set.
39-
* REMOVALS bias for the remove set.
40-
*/
41-
ADDS,
42-
REMOVALS
43-
}
44-
45-
class LWWElementSet {
46-
private final Map<String, Element> addSet;
47-
private final Map<String, Element> removeSet;
48-
49-
/**
50-
* Constructs an empty LWWElementSet.
28+
* Constructs an empty LWWElementSet. This constructor initializes the addSet and removeSet as
29+
* empty HashMaps. The addSet stores elements that are added, and the removeSet stores elements
30+
* that are removed.
5131
*/
5232
LWWElementSet() {
5333
this.addSet = new HashMap<>();
5434
this.removeSet = new HashMap<>();
5535
}
5636

5737
/**
58-
* Adds an element to the addSet.
38+
* Adds an element to the addSet with the current timestamp. This method stores the element in the
39+
* addSet, ensuring that the element is added to the set with an associated timestamp that
40+
* represents the time of the addition.
5941
*
60-
* @param e The element to be added.
42+
* @param key The key of the element to be added.
6143
*/
62-
public void add(Element e) {
63-
addSet.put(e.key, e);
44+
public void add(T key) {
45+
addSet.put(key, new Element<>(key, Instant.now()));
6446
}
6547

6648
/**
67-
* Removes an element from the removeSet.
49+
* Removes an element by adding it to the removeSet with the current timestamp. This method adds
50+
* the element to the removeSet, marking it as removed with the current timestamp.
6851
*
69-
* @param e The element to be removed.
52+
* @param key The key of the element to be removed.
7053
*/
71-
public void remove(Element e) {
72-
if (lookup(e)) {
73-
removeSet.put(e.key, e);
74-
}
54+
public void remove(T key) {
55+
removeSet.put(key, new Element<>(key, Instant.now()));
7556
}
7657

7758
/**
78-
* Checks if an element is in the LWWElementSet by comparing timestamps in the addSet and removeSet.
59+
* Checks if an element is in the LWWElementSet. An element is considered present if it exists in
60+
* the addSet and either does not exist in the removeSet, or its add timestamp is later than any
61+
* corresponding remove timestamp.
7962
*
80-
* @param e The element to be checked.
81-
* @return True if the element is present, false otherwise.
63+
* @param key The key of the element to be checked.
64+
* @return {@code true} if the element is present in the set (i.e., its add timestamp is later
65+
* than its remove timestamp, or it is not in the remove set), {@code false} otherwise (i.e.,
66+
* the element has been removed or its remove timestamp is later than its add timestamp).
8267
*/
83-
public boolean lookup(Element e) {
84-
Element inAddSet = addSet.get(e.key);
85-
Element inRemoveSet = removeSet.get(e.key);
68+
public boolean lookup(T key) {
69+
Element<T> inAddSet = addSet.get(key);
70+
Element<T> inRemoveSet = removeSet.get(key);
8671

87-
return (inAddSet != null && (inRemoveSet == null || inAddSet.timestamp > inRemoveSet.timestamp));
72+
return inAddSet != null && (inRemoveSet == null || inAddSet.timestamp.isAfter(inRemoveSet.timestamp));
8873
}
8974

9075
/**
91-
* Compares the LWWElementSet with another LWWElementSet to check if addSet and removeSet are a subset.
76+
* Merges another LWWElementSet into this set. This method takes the union of both the add-sets
77+
* and remove-sets from the two sets, resolving conflicts by keeping the element with the latest
78+
* timestamp. If an element appears in both the add-set and remove-set of both sets, the one with
79+
* the later timestamp will be retained.
9280
*
93-
* @param other The LWWElementSet to compare.
94-
* @return True if the set is subset, false otherwise.
81+
* @param other The LWWElementSet to merge with the current set.
9582
*/
96-
public boolean compare(LWWElementSet other) {
97-
return other.addSet.keySet().containsAll(addSet.keySet()) && other.removeSet.keySet().containsAll(removeSet.keySet());
83+
public void merge(LWWElementSet<T> other) {
84+
for (Map.Entry<T, Element<T>> entry : other.addSet.entrySet()) {
85+
addSet.merge(entry.getKey(), entry.getValue(), this::resolveConflict);
86+
}
87+
for (Map.Entry<T, Element<T>> entry : other.removeSet.entrySet()) {
88+
removeSet.merge(entry.getKey(), entry.getValue(), this::resolveConflict);
89+
}
9890
}
9991

10092
/**
101-
* Merges another LWWElementSet into this set by resolving conflicts based on timestamps.
93+
* Resolves conflicts between two elements by selecting the one with the later timestamp. This
94+
* method is used when merging two LWWElementSets to ensure that the most recent operation (based
95+
* on timestamps) is kept.
10296
*
103-
* @param other The LWWElementSet to merge.
97+
* @param e1 The first element.
98+
* @param e2 The second element.
99+
* @return The element with the later timestamp.
104100
*/
105-
public void merge(LWWElementSet other) {
106-
for (Element e : other.addSet.values()) {
107-
if (!addSet.containsKey(e.key) || compareTimestamps(addSet.get(e.key), e)) {
108-
addSet.put(e.key, e);
109-
}
110-
}
111-
112-
for (Element e : other.removeSet.values()) {
113-
if (!removeSet.containsKey(e.key) || compareTimestamps(removeSet.get(e.key), e)) {
114-
removeSet.put(e.key, e);
115-
}
116-
}
101+
private Element<T> resolveConflict(Element<T> e1, Element<T> e2) {
102+
return e1.timestamp.isAfter(e2.timestamp) ? e1 : e2;
117103
}
104+
}
105+
106+
/**
107+
* Represents an element in the LWWElementSet, consisting of a key and a timestamp. This class is
108+
* used to store the elements in both the add and remove sets with their respective timestamps.
109+
*
110+
* @param <T> The type of the key associated with the element.
111+
*/
112+
class Element<T> {
113+
T key;
114+
Instant timestamp;
118115

119116
/**
120-
* Compares timestamps of two elements based on their bias (ADDS or REMOVALS).
117+
* Constructs a new Element with the specified key and timestamp.
121118
*
122-
* @param e The first element.
123-
* @param other The second element.
124-
* @return True if the first element's timestamp is greater or the bias is ADDS and timestamps are equal.
119+
* @param key The key of the element.
120+
* @param timestamp The timestamp associated with the element.
125121
*/
126-
public boolean compareTimestamps(Element e, Element other) {
127-
if (e.bias != other.bias) {
128-
throw new IllegalArgumentException("Invalid bias value");
129-
}
130-
Bias bias = e.bias;
131-
int timestampComparison = Integer.compare(e.timestamp, other.timestamp);
132-
133-
if (timestampComparison == 0) {
134-
return bias != Bias.ADDS;
135-
}
136-
return timestampComparison < 0;
122+
Element(T key, Instant timestamp) {
123+
this.key = key;
124+
this.timestamp = timestamp;
137125
}
138126
}

src/main/java/com/thealgorithms/strings/ReverseString.java

+21
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,25 @@ public static String reverse2(String str) {
3636
}
3737
return new String(value);
3838
}
39+
40+
/**
41+
* Reverse version 3 the given string using a StringBuilder.
42+
* This method converts the string to a character array,
43+
* iterates through it in reverse order, and appends each character
44+
* to a StringBuilder.
45+
*
46+
* @param string The input string to be reversed.
47+
* @return The reversed string.
48+
*/
49+
public static String reverse3(String string) {
50+
if (string.isEmpty()) {
51+
return string;
52+
}
53+
char[] chars = string.toCharArray();
54+
StringBuilder sb = new StringBuilder();
55+
for (int i = string.length() - 1; i >= 0; i--) {
56+
sb.append(chars[i]);
57+
}
58+
return sb.toString();
59+
}
3960
}

0 commit comments

Comments
 (0)