Commits (6)
...@@ -4,4 +4,5 @@ target/ ...@@ -4,4 +4,5 @@ target/
*.classpath *.classpath
*.project *.project
classes/ classes/
test-classes/ test-classes/
\ No newline at end of file /bin/
n,1000,2000,5000,10000,20000,50000
ASCENDANT,1231700,00,4418640,00,30034160,00,116455020,00,474819140,00,3056061360,00
ALEATOIRE,149580,00,167500,00,356340,00,830320,00,1814660,00,5609920,00
n,1000,2000,5000,10000,20000,50000
ASCENDANT,2658220,00,9699160,00,60452520,00,233926280,00,907753720,00,5800536280,00
ALEATOIRE,128340,00,122680,00,310240,00,577920,00,1311820,00,3409080,00
n,1000,2000,5000,10000,20000,50000
ASCENDANT,221140,00,242880,00,405760,00,720540,00,761520,00,1803680,00
ALEATOIRE,153900,00,219500,00,457300,00,938200,00,2106160,00,6222500,00
n,1000,2000,5000,10000,20000,50000
ASCENDANT,136940,00,128920,00,320120,00,733100,00,1475920,00,4872060,00
ALEATOIRE,51780,00,101540,00,308340,00,616120,00,1244160,00,3500360,00
structure,scenario,n,phase,avg_millis
ABR,random,1000,insert,260220,00
ABR,random,1000,search,191900,00
ABR,random,2000,insert,206640,00
ABR,random,2000,search,221760,00
ABR,random,5000,insert,435200,00
ABR,random,5000,search,438360,00
ABR,random,10000,insert,855380,00
ABR,random,10000,search,705300,00
ABR,random,20000,insert,2177680,00
ABR,random,20000,search,1845920,00
ABR,random,50000,insert,6423600,00
ABR,random,50000,search,5389400,00
ABR,ascending,1000,insert,718120,00
ABR,ascending,1000,search,2531360,00
ABR,ascending,2000,insert,4253440,00
ABR,ascending,2000,search,10143660,00
ABR,ascending,5000,insert,28879760,00
ABR,ascending,5000,search,63836740,00
ABR,ascending,10000,insert,115510000,00
ABR,ascending,10000,search,266706780,00
ABR,ascending,20000,insert,475341800,00
ABR,ascending,20000,search,1121616340,00
ABR,ascending,50000,insert,3014206600,00
ABR,ascending,50000,search,6716530900,00
ARN,random,1000,insert,221560,00
ARN,random,1000,search,139960,00
ARN,random,2000,insert,224680,00
ARN,random,2000,search,134720,00
ARN,random,5000,insert,432000,00
ARN,random,5000,search,305080,00
ARN,random,10000,insert,989980,00
ARN,random,10000,search,896760,00
ARN,random,20000,insert,2126220,00
ARN,random,20000,search,1506000,00
ARN,random,50000,insert,7219200,00
ARN,random,50000,search,3469420,00
ARN,ascending,1000,insert,33160,00
ARN,ascending,1000,search,47440,00
ARN,ascending,2000,insert,76180,00
ARN,ascending,2000,search,135580,00
ARN,ascending,5000,insert,216960,00
ARN,ascending,5000,search,374500,00
ARN,ascending,10000,insert,436280,00
ARN,ascending,10000,search,815480,00
ARN,ascending,20000,insert,901520,00
ARN,ascending,20000,search,1773640,00
ARN,ascending,50000,insert,2840800,00
ARN,ascending,50000,search,4844200,00
...@@ -6,148 +6,102 @@ ...@@ -6,148 +6,102 @@
<groupId>edu.Univ-lehavre.MACIA</groupId> <groupId>edu.Univ-lehavre.MACIA</groupId>
<artifactId>ArbreRougeNoir</artifactId> <artifactId>ArbreRougeNoir</artifactId>
<version>1.0-SNAPSHOT</version> <version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>ArbreRougeNoir</name> <name>ArbreRougeNoir</name>
<!-- FIXME change it to the project's website --> <!-- FIXME change it to the project's website -->
<url>http://maven.apache.org</url> <url>http://www.example.com</url>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>14</maven.compiler.source> <maven.compiler.release>17</maven.compiler.release>
<maven.compiler.target>14</maven.compiler.target>
</properties> </properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>6.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>6.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>6.0.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId> <artifactId>maven-jar-plugin</artifactId>
<version>3.6.0</version> <version>3.3.0</version>
<configuration> <configuration>
<configLocation> <archive>
src/properties/stylePerso.xml <manifest>
</configLocation> <mainClass>collection.Benchmark</mainClass>
</configuration> </manifest>
<dependencies> </archive>
<dependency> </configuration>
<groupId>com.puppycrawl.tools</groupId> </plugin>
<artifactId>checkstyle</artifactId> <plugin>
<version>12.1.1</version> <groupId>org.apache.maven.plugins</groupId>
</dependency> <artifactId>maven-project-info-reports-plugin</artifactId>
</dependencies> <version>3.5.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>3.21.0</version>
</plugin> </plugin>
<plugin> </plugins>
<groupId>org.apache.maven.plugins</groupId> <pluginManagement>
<artifactId>maven-surefire-plugin</artifactId> <plugins>
<version>3.5.1</version> <plugin>
</plugin> <groupId>org.apache.maven.plugins</groupId>
<plugin> <artifactId>maven-checkstyle-plugin</artifactId>
<groupId>org.apache.maven.plugins</groupId> <version>3.6.0</version>
<artifactId>maven-jar-plugin</artifactId> <dependencies>
<version>3.4.2</version> <dependency>
<configuration> <groupId>com.puppycrawl.tools</groupId>
<archive> <artifactId>checkstyle</artifactId>
<manifest> <version>12.1.1</version>
<mainClass>collection.Benchmark</mainClass> </dependency>
</manifest> </dependencies>
</archive> </plugin>
</configuration> </plugins>
</plugin> </pluginManagement>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>4.0.0-M16</version>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.12</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>default-report</id>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>default-check</id>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build> </build>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.11.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.11.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.11.3</version>
<scope>test</scope>
</dependency>
</dependencies>
<reporting> <reporting>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId> <artifactId>maven-jxr-plugin</artifactId>
<version>3.10.1</version> <version>3.6.0</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId> <artifactId>maven-surefire-report-plugin</artifactId>
<version>3.5.0</version> <version>3.5.4</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId> <artifactId>maven-checkstyle-plugin</artifactId>
<version>3.5.1</version> <version>3.6.0</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.jacoco</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>jacoco-maven-plugin</artifactId> <artifactId>maven-javadoc-plugin</artifactId>
<version>0.8.12</version> <version>3.12.0</version>
<reportSets> </plugin>
<reportSet> </plugins>
<reports>
<!-- select non-aggregate reports -->
<report>report</report>
</reports>
</reportSet>
</reportSets>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.6.0</version>
</plugin>
</plugins>
</reporting> </reporting>
</project> </project>
...@@ -10,7 +10,7 @@ import java.util.Stack; ...@@ -10,7 +10,7 @@ import java.util.Stack;
/** /**
* Arbre binaire de recherche simple. Implémente l’interface Collection. * Arbre binaire de recherche simple. Implémente l’interface Collection.
*/ */
public class BinarySearchTree<E extends Comparable<E>> implements Collection<E> { public class ArbreBinaireRecherche<E extends Comparable<E>> implements Collection<E> {
/** Classe interne représentant un nœud de l'arbre */ /** Classe interne représentant un nœud de l'arbre */
private class Noeud { private class Noeud {
......
...@@ -9,71 +9,130 @@ import java.util.Collections; ...@@ -9,71 +9,130 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
class Benchmark { public class Benchmark {
private static final Random RNG = new Random(12345);
private static final Random RNG = new Random(12345);
public static void main(final String[] args) throws Exception {
final int[] ns = {1000, 2000, 5000, 10000, 20000, 50000}; // adapte public static void main(final String[] args) throws Exception {
final int reps = 5; // répétitions pour moyenne
String outFile = "benchmark_results.csv"; final int[] N_LIST = { 1000, 2000, 5000, 10000, 20000, 50000 };
final int REP = 5;
try (PrintWriter pw = new PrintWriter(new FileWriter(outFile))) {
pw.println("structure,scenario,n,phase,avg_millis"); // --- Create the 4 CSV writers ---
PrintWriter abrInsert = new PrintWriter(new FileWriter("ABR_insert.csv"));
for (String structure : Arrays.asList("ABR", "ARN")) { PrintWriter abrSearch = new PrintWriter(new FileWriter("ABR_search.csv"));
for (String scenario : Arrays.asList("random", "ascending")) { PrintWriter arnInsert = new PrintWriter(new FileWriter("ARN_insert.csv"));
for (int n : ns) { PrintWriter arnSearch = new PrintWriter(new FileWriter("ARN_search.csv"));
long insertSum = 0;
long searchSum = 0; // Header line : n,1000,2000,...
writeHeader(abrInsert, N_LIST);
for (int r = 0; r < reps; r++) { writeHeader(abrSearch, N_LIST);
List<Integer> keys = new ArrayList<>(); writeHeader(arnInsert, N_LIST);
writeHeader(arnSearch, N_LIST);
for (int i = 0; i < n; i++) {
keys.add(i); // Scenarios
} List<String> scenarios = Arrays.asList("ASCENDANT", "ALEATOIRE");
if (scenario.equals("random")) { // Process each structure
Collections.shuffle(keys, new Random(RNG.nextLong())); for (String structure : Arrays.asList("ABR", "ARN")) {
}
for (String scenario : scenarios) {
// choose structure
Collection<Integer> tree = structure.equals("ARN") // Buffers for one line of insert & search results
? new RedBlackTree<>() : new BinarySearchTree<>(); List<Double> insertLine = new ArrayList<>();
List<Double> searchLine = new ArrayList<>();
long t0 = System.nanoTime();
for (int n : N_LIST) {
for (Integer k : keys) {
tree.add(k); long insertSum = 0;
} long searchSum = 0;
long t1 = System.nanoTime(); for (int r = 0; r < REP; r++) {
long insertMs = (t1 - t0);
insertSum += insertMs; List<Integer> keys = new ArrayList<>();
for (int i = 0; i < n; i++)
// search phase: 0 .. 2n-1 keys.add(i);
long t2 = System.nanoTime();
if (scenario.equals("ALEATOIRE")) {
for (int x = 0; x < 2 * n; x++) { Collections.shuffle(keys, new Random(RNG.nextLong()));
tree.contains(x); }
}
long[] result = structure.equals("ABR") ? benchmarkABR(keys, n) : benchmarkARN(keys, n);
long t3 = System.nanoTime();
long searchMs = (t3 - t2); insertSum += result[0];
searchSum += searchMs; searchSum += result[1];
} }
pw.printf("%s,%s,%d,insert,%.2f%n", structure, scenario, n, insertLine.add(insertSum / (double) REP);
insertSum / (double) reps); searchLine.add(searchSum / (double) REP);
pw.printf("%s,%s,%d,search,%.2f%n", structure, scenario, n,
searchSum / (double) reps); System.out.printf("Done %s %s n=%d\n", structure, scenario, n);
pw.flush(); }
System.out.printf("Done %s %s n=%d%n", structure, scenario, n); // Write to correct CSV
} if (structure.equals("ABR")) {
} writeScenarioLine(abrInsert, scenario, insertLine);
} writeScenarioLine(abrSearch, scenario, searchLine);
} else {
writeScenarioLine(arnInsert, scenario, insertLine);
writeScenarioLine(arnSearch, scenario, searchLine);
}
}
}
abrInsert.close();
abrSearch.close();
arnInsert.close();
arnSearch.close();
System.out.println("4 CSV créés au format tableau.");
}
// -------------------------------------------------------
// Helper: header line
// -------------------------------------------------------
private static void writeHeader(PrintWriter pw, int[] nList) {
pw.print("n");
for (int n : nList)
pw.print("," + n);
pw.println();
}
// -------------------------------------------------------
// Helper: write one scenario line
// -------------------------------------------------------
private static void writeScenarioLine(PrintWriter pw, String scenario, List<Double> values) {
pw.print(scenario);
for (double v : values)
pw.printf(",%.2f", v);
pw.println();
}
// -------------------------------------------------------
// Benchmark ABR / ARN
// -------------------------------------------------------
private static long[] benchmarkABR(List<Integer> keys, int n) {
Collection<Integer> tree = new ArbreBinaireRecherche<>();
return runBenchmark(tree, keys, n);
}
private static long[] benchmarkARN(List<Integer> keys, int n) {
Collection<Integer> tree = new RedBlackTree<>();
return runBenchmark(tree, keys, n);
}
private static long[] runBenchmark(Collection<Integer> tree, List<Integer> keys, int n) {
long t0 = System.nanoTime();
for (Integer k : keys)
tree.add(k);
long t1 = System.nanoTime();
long t2 = System.nanoTime();
for (int x = 0; x < 2 * n; x++)
tree.contains(x);
long t3 = System.nanoTime();
return new long[] { t1 - t0, t3 - t2 };
} }
System.out.println("Wrote results to " + outFile);
}
} }
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker">
<property name="charset" value="UTF-8"/>
<property name="severity" value="${org.checkstyle.google.severity}" default="warning"/>
<property name="fileExtensions" value="java, properties, xml"/>
<!-- Exclure module-info.java -->
<module name="BeforeExecutionExclusionFileFilter">
<property name="fileNamePattern" value="module\-info\.java$"/>
</module>
<module name="SuppressWarningsFilter"/>
<!-- Suppressions -->
<module name="SuppressionFilter">
<property name="file" value="${org.checkstyle.google.suppressionfilter.config}"
default="checkstyle-suppressions.xml" />
<property name="optional" value="true"/>
</module>
<module name="SuppressWithNearbyTextFilter">
<property name="nearbyTextPattern"
value="CHECKSTYLE.SUPPRESS\: (\w+) for ([+-]\d+) lines"/>
<property name="checkPattern" value="$1"/>
<property name="lineRange" value="$2"/>
</module>
<!-- Tabs interdits -->
<module name="FileTabCharacter">
<property name="eachLine" value="true"/>
</module>
<!-- Longueur max des lignes -->
<module name="LineLength">
<property name="fileExtensions" value="java"/>
<property name="max" value="1000"/>
<property name="ignorePattern"
value="^package.*|^import.*|href\s*=\s*&quot;[^&quot;]*&quot;|http://|https://|ftp://"/>
</module>
<!-- Longueur maximale du fichier = 1000 lignes -->
<module name="FileLength">
<property name="max" value="1000"/>
</module>
<module name="SuppressWithPlainTextCommentFilter">
<property name="checkFormat" value="LineLength"/>
<property name="offCommentFormat" value='^.*"""\s*$'/>
<property name="onCommentFormat" value='^\s*"""\s*(?:[,;]|.+)$'/>
</module>
<module name="TreeWalker">
<!-- Règles personnalisées ajoutées -->
<module name="MethodLength">
<property name="max" value="15"/>
</module>
<module name="ParameterNumber">
<property name="max" value="2"/>
</module>
<module name="MagicNumber">
<property name="ignoreNumbers" value="-1,0,1"/>
<property name="ignoreHashCodeMethod" value="true"/>
</module>
<module name="NestedIfDepth">
<property name="max" value="0"/>
</module>
<module name="VariableDeclarationUsageDistance">
<property name="maxDistance" value="5"/>
</module>
<!-- Début de toutes les règles Google Checkstyle… (inchangées) -->
<module name="OuterTypeFilename"/>
<module name="MatchXpath">
<property name="id" value="singleLineCommentStartWithSpace"/>
<property name="query"
value="//SINGLE_LINE_COMMENT[./COMMENT_CONTENT[not(starts-with(@text, ' '))
and not(starts-with(@text, '/'))
and not(@text = '\n') and not(ends-with(@text, '//\n'))]]"/>
<message key="matchxpath.match" value="''//'' must be followed by a whitespace."/>
</module>
<module name="IllegalTokenText">
<property name="tokens" value="STRING_LITERAL, CHAR_LITERAL, TEXT_BLOCK_CONTENT"/>
<property name="format"
value="\\u00(09|0(a|A)|0(b|B)|(0|1)(c|C)|(0|1)(d|D)|1(d|D)|1(e|E)|1(f|F)|22|27|5(C|c))|\\u1680|\\u3000|\\u20(00|0(a|A)|28|29|(2|5)(f|F))|\\(0(10|11|12|14|15|40|42|47)|134)"/>
<property name="message"
value="Consider using special escape sequence instead of octal value or Unicode escaped value."/>
</module>
<module name="AvoidEscapedUnicodeCharacters">
<property name="allowEscapesForControlCharacters" value="true"/>
<property name="allowByTailComment" value="true"/>
<property name="allowNonPrintableEscapes" value="true"/>
</module>
<module name="AvoidStarImport"/>
<module name="OneTopLevelClass"/>
<module name="NoLineWrap">
<property name="tokens" value="PACKAGE_DEF, IMPORT, STATIC_IMPORT"/>
</module>
<module name="NeedBraces">
<property name="tokens"
value="LITERAL_DO, LITERAL_ELSE, LITERAL_FOR, LITERAL_IF, LITERAL_WHILE"/>
</module>
<module name="LeftCurly">
<property name="id" value="LeftCurlyEol"/>
<property name="tokens"
value="ANNOTATION_DEF, CLASS_DEF, CTOR_DEF, ENUM_CONSTANT_DEF, ENUM_DEF,
INTERFACE_DEF, LAMBDA, LITERAL_CATCH,
LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF,
LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, METHOD_DEF,
OBJBLOCK, STATIC_INIT, RECORD_DEF, COMPACT_CTOR_DEF"/>
</module>
<module name="LeftCurly">
<property name="id" value="LeftCurlyNl"/>
<property name="option" value="nl"/>
<property name="tokens"
value="LITERAL_CASE, LITERAL_DEFAULT"/>
</module>
<module name="SuppressionXpathSingleFilter">
<!-- LITERAL_CASE, LITERAL_DEFAULT are reused in SWITCH_RULE -->
<property name="id" value="LeftCurlyNl"/>
<property name="query" value="//SWITCH_RULE/SLIST"/>
</module>
<module name="RightCurly">
<property name="id" value="RightCurlySame"/>
<property name="tokens"
value="LITERAL_TRY, LITERAL_CATCH, LITERAL_IF, LITERAL_ELSE,
LITERAL_DO"/>
</module>
<module name="SuppressionXpathSingleFilter">
<property name="id" value="RightCurlySame"/>
<property name="query" value="//RCURLY[parent::SLIST[parent::LITERAL_CATCH
and not(parent::LITERAL_CATCH/following-sibling::*)]]"/>
</module>
<module name="RightCurly">
<property name="id" value="RightCurlyAlone"/>
<property name="option" value="alone"/>
<property name="tokens"
value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, STATIC_INIT,
INSTANCE_INIT, ANNOTATION_DEF, ENUM_DEF, INTERFACE_DEF, RECORD_DEF,
COMPACT_CTOR_DEF, LITERAL_SWITCH, LITERAL_CASE, LITERAL_FINALLY,
LITERAL_CATCH"/>
</module>
<module name="SuppressionXpathSingleFilter">
<!-- suppression is required till https://github.com/checkstyle/checkstyle/issues/7541 -->
<property name="id" value="RightCurlyAlone"/>
<property name="query" value="//RCURLY[parent::SLIST[count(./*)=1
and not(parent::LITERAL_CATCH)]
or (preceding-sibling::*[last()][self::LCURLY]
and not(parent::SLIST/parent::LITERAL_CATCH))
or (parent::SLIST/parent::LITERAL_CATCH
and parent::SLIST/parent::LITERAL_CATCH/following-sibling::*)]"/>
</module>
<module name="WhitespaceAfter">
<property name="tokens"
value="COMMA, SEMI, TYPECAST, LITERAL_IF, LITERAL_ELSE, LITERAL_RETURN,
LITERAL_WHILE, LITERAL_DO, LITERAL_FOR, LITERAL_FINALLY, DO_WHILE, ELLIPSIS,
LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_CATCH, LAMBDA,
LITERAL_YIELD, LITERAL_CASE, LITERAL_WHEN, ANNOTATIONS"/>
</module>
<module name="WhitespaceAround">
<property name="allowEmptyConstructors" value="true"/>
<property name="allowEmptyLambdas" value="true"/>
<property name="allowEmptyMethods" value="true"/>
<property name="allowEmptyTypes" value="true"/>
<property name="allowEmptyLoops" value="true"/>
<property name="allowEmptySwitchBlockStatements" value="true"/>
<property name="ignoreEnhancedForColon" value="false"/>
<property name="tokens"
value="ASSIGN, BAND, BAND_ASSIGN, BOR, BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR,
BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN, DO_WHILE, EQUAL, GE, GT, LAMBDA, LAND,
LCURLY, LE, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY,
LITERAL_FOR, LITERAL_IF, LITERAL_RETURN, LITERAL_SWITCH, LITERAL_SYNCHRONIZED,
LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS, MINUS_ASSIGN, MOD, MOD_ASSIGN,
NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION, RCURLY, SL, SLIST, SL_ASSIGN, SR,
SR_ASSIGN, STAR, STAR_ASSIGN, LITERAL_ASSERT,
TYPE_EXTENSION_AND, LITERAL_WHEN"/>
<message key="ws.notFollowed"
value="WhitespaceAround: ''{0}'' is not followed by whitespace. Empty blocks
may only be represented as '{}' when not part of a multi-block statement (4.1.3)"/>
<message key="ws.notPreceded"
value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/>
</module>
<module name="SuppressionXpathSingleFilter">
<property name="checks" value="WhitespaceAround"/>
<property name="query" value="//*[self::LITERAL_IF or self::LITERAL_ELSE or
self::STATIC_INIT]/SLIST[count(./*)=1]
| //*[self::STATIC_INIT or self::LITERAL_TRY or self::LITERAL_IF]
//*[self::RCURLY][parent::SLIST[count(./*)=1]]
| //SLIST[count(./*)=1][parent::LITERAL_TRY and
not(following-sibling::*)]
| //SLIST[count(./*)=1][parent::LITERAL_CATCH and
not(parent::LITERAL_CATCH/following-sibling::*)]"/>
</module>
<module name="RegexpSinglelineJava">
<property name="format" value="\{[ ]+\}"/>
<property name="message" value="Empty blocks should have no spaces. Empty blocks
may only be represented as '{}' when not part of a
multi-block statement (4.1.3)"/>
</module>
<module name="OneStatementPerLine"/>
<module name="VariableDeclarationUsageDistance">
<property name="maxDistance" value="5"/>
</module>
<module name="ArrayTypeStyle"/>
<module name="JavadocLeadingAsteriskAlign"/>
<module name="MissingSwitchDefault"/>
<module name="FallThrough"/>
<module name="UpperEll"/>
<module name="ModifierOrder"/>
<module name="EmptyLineSeparator">
<property name="tokens"
value="PACKAGE_DEF, IMPORT, STATIC_IMPORT, CLASS_DEF, INTERFACE_DEF, ENUM_DEF,
STATIC_INIT, INSTANCE_INIT, METHOD_DEF, CTOR_DEF, VARIABLE_DEF, RECORD_DEF,
COMPACT_CTOR_DEF"/>
<property name="allowNoEmptyLineBetweenFields" value="true"/>
<property name="allowMultipleEmptyLines" value="false"/>
</module>
<module name="SeparatorWrap">
<property name="id" value="SeparatorWrapDot"/>
<property name="tokens" value="DOT"/>
<property name="option" value="nl"/>
</module>
<module name="SeparatorWrap">
<property name="id" value="SeparatorWrapComma"/>
<property name="tokens" value="COMMA"/>
<property name="option" value="EOL"/>
</module>
<module name="SeparatorWrap">
<!-- ELLIPSIS is EOL until https://github.com/google/styleguide/issues/259 -->
<property name="id" value="SeparatorWrapEllipsis"/>
<property name="tokens" value="ELLIPSIS"/>
<property name="option" value="EOL"/>
</module>
<module name="SeparatorWrap">
<!-- ARRAY_DECLARATOR is EOL until https://github.com/google/styleguide/issues/258 -->
<property name="id" value="SeparatorWrapArrayDeclarator"/>
<property name="tokens" value="ARRAY_DECLARATOR"/>
<property name="option" value="EOL"/>
</module>
<module name="SeparatorWrap">
<property name="id" value="SeparatorWrapMethodRef"/>
<property name="tokens" value="METHOD_REF"/>
<property name="option" value="nl"/>
</module>
<module name="PackageName">
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
<message key="name.invalidPattern"
value="Package name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="TypeName">
<property name="format" value="^[A-Z][a-zA-Z0-9]*(?:[0-9](?:_[0-9]+)*)?$"/>
<property name="tokens" value="CLASS_DEF"/>
<message key="name.invalidPattern"
value="Type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="TypeName">
<property name="tokens" value="INTERFACE_DEF, ENUM_DEF,
ANNOTATION_DEF, RECORD_DEF"/>
<message key="name.invalidPattern"
value="Type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="MemberName">
<property name="format"
value="^(?![a-z]$)(?![a-z][A-Z])[a-z][a-zA-Z0-9]*(?:_[0-9]+)*$"/>
<message key="name.invalidPattern"
value="Member name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="ParameterName">
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern"
value="Parameter name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="LambdaParameterName">
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern"
value="Lambda parameter name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="CatchParameterName">
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern"
value="Catch parameter name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="LocalVariableName">
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern"
value="Local variable name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="PatternVariableName">
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern"
value="Pattern variable name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="ClassTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern"
value="Class type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="RecordComponentName">
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern"
value="Record component name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="RecordTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern"
value="Record type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="MethodTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern"
value="Method type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="InterfaceTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern"
value="Interface type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="NoFinalizer"/>
<module name="GenericWhitespace">
<message key="ws.followed"
value="GenericWhitespace ''{0}'' is followed by whitespace."/>
<message key="ws.preceded"
value="GenericWhitespace ''{0}'' is preceded with whitespace."/>
<message key="ws.illegalFollow"
value="GenericWhitespace ''{0}'' should followed by whitespace."/>
<message key="ws.notPreceded"
value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
</module>
<module name="Indentation">
<property name="basicOffset" value="2"/>
<property name="braceAdjustment" value="2"/>
<property name="caseIndent" value="2"/>
<property name="throwsIndent" value="4"/>
<property name="lineWrappingIndentation" value="4"/>
<property name="arrayInitIndent" value="2"/>
</module>
<module name="AbbreviationAsWordInName">
<property name="ignoreFinal" value="false"/>
<property name="allowedAbbreviationLength" value="0"/>
<property name="tokens"
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, ANNOTATION_DEF, ANNOTATION_FIELD_DEF,
PARAMETER_DEF, VARIABLE_DEF, METHOD_DEF, PATTERN_VARIABLE_DEF, RECORD_DEF,
RECORD_COMPONENT_DEF"/>
</module>
<module name="NoWhitespaceBeforeCaseDefaultColon"/>
<module name="OverloadMethodsDeclarationOrder"/>
<module name="ConstructorsDeclarationGrouping"/>
<module name="VariableDeclarationUsageDistance"/>
<module name="CustomImportOrder">
<property name="sortImportsInGroupAlphabetically" value="true"/>
<property name="separateLineBetweenGroups" value="true"/>
<property name="customImportOrderRules" value="STATIC###THIRD_PARTY_PACKAGE"/>
<property name="tokens" value="IMPORT, STATIC_IMPORT, PACKAGE_DEF"/>
</module>
<module name="MethodParamPad">
<property name="tokens"
value="CTOR_DEF, LITERAL_NEW, METHOD_CALL, METHOD_DEF, CTOR_CALL,
SUPER_CTOR_CALL, ENUM_CONSTANT_DEF, RECORD_DEF, RECORD_PATTERN_DEF"/>
</module>
<module name="NoWhitespaceBefore">
<property name="tokens"
value="COMMA, SEMI, POST_INC, POST_DEC, DOT,
LABELED_STAT, METHOD_REF, ELLIPSIS"/>
<property name="allowLineBreaks" value="true"/>
</module>
<module name="SuppressionXpathSingleFilter">
<property name="checks" value="NoWhitespaceBefore"/>
<property name="query"
value="//ELLIPSIS[preceding-sibling::TYPE/ANNOTATIONS[ANNOTATION[LPAREN]
or not(following-sibling::*)]]"/>
</module>
<module name="ParenPad">
<property name="tokens"
value="ANNOTATION, ANNOTATION_FIELD_DEF, CTOR_CALL, CTOR_DEF, DOT, ENUM_CONSTANT_DEF,
EXPR, LITERAL_CATCH, LITERAL_DO, LITERAL_FOR, LITERAL_IF, LITERAL_NEW,
LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_WHILE, METHOD_CALL,
METHOD_DEF, QUESTION, RESOURCE_SPECIFICATION, SUPER_CTOR_CALL, LAMBDA,
RECORD_DEF, RECORD_PATTERN_DEF"/>
</module>
<module name="OperatorWrap">
<property name="option" value="NL"/>
<property name="tokens"
value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR,
LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR, METHOD_REF,
TYPE_EXTENSION_AND "/>
</module>
<module name="AnnotationLocation">
<property name="id" value="AnnotationLocationMostCases"/>
<property name="tokens"
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF,
RECORD_DEF, COMPACT_CTOR_DEF, PACKAGE_DEF"/>
</module>
<module name="AnnotationLocation">
<property name="id" value="AnnotationLocationVariables"/>
<property name="tokens" value="VARIABLE_DEF"/>
<property name="allowSamelineMultipleAnnotations" value="true"/>
</module>
<module name="NonEmptyAtclauseDescription"/>
<module name="InvalidJavadocPosition"/>
<module name="JavadocTagContinuationIndentation"/>
<module name="SummaryJavadoc">
<property name="forbiddenSummaryFragments"
value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/>
</module>
<module name="JavadocParagraph">
<property name="allowNewlineParagraph" value="false"/>
</module>
<module name="RequireEmptyLineBeforeBlockTagGroup"/>
<module name="AtclauseOrder">
<property name="tagOrder" value="@param, @return, @throws, @deprecated"/>
<property name="target"
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
</module>
<module name="JavadocMethod">
<property name="accessModifiers" value="public"/>
<property name="allowMissingParamTags" value="true"/>
<property name="allowMissingReturnTag" value="true"/>
<property name="allowedAnnotations" value="Override, Test"/>
<property name="tokens" value="METHOD_DEF, CTOR_DEF, ANNOTATION_FIELD_DEF, COMPACT_CTOR_DEF"/>
</module>
<module name="MissingJavadocMethod">
<property name="scope" value="protected"/>
<property name="allowMissingPropertyJavadoc" value="true"/>
<property name="allowedAnnotations" value="Override, Test"/>
<property name="tokens" value="METHOD_DEF, CTOR_DEF, ANNOTATION_FIELD_DEF,
COMPACT_CTOR_DEF"/>
</module>
<module name="SuppressionXpathSingleFilter">
<property name="checks" value="MissingJavadocMethod"/>
<property name="query" value="//*[self::METHOD_DEF or self::CTOR_DEF
or self::ANNOTATION_FIELD_DEF or self::COMPACT_CTOR_DEF]
[ancestor::*[self::INTERFACE_DEF or self::CLASS_DEF
or self::RECORD_DEF or self::ENUM_DEF]
[not(./MODIFIERS/LITERAL_PUBLIC)]]"/>
</module>
<module name="MissingJavadocType">
<property name="scope" value="protected"/>
<property name="tokens"
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF,
RECORD_DEF, ANNOTATION_DEF"/>
<property name="excludeScope" value="nothing"/>
</module>
<module name="MethodName">
<property name="format"
value="^(?![a-z]$)(?![a-z][A-Z])[a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)*(?:_[0-9]+)*$"/>
<message key="name.invalidPattern"
value="Method name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="SuppressionXpathSingleFilter">
<property name="checks" value="MethodName"/>
<property name="query" value="//METHOD_DEF[
./MODIFIERS/ANNOTATION//IDENT[contains(@text, 'Test')]
]/IDENT"/>
<property name="message" value="'[a-z][a-z0-9][a-zA-Z0-9]*(?:_[a-z][a-z0-9][a-zA-Z0-9]*)*'"/>
</module>
<module name="SingleLineJavadoc"/>
<module name="TodoComment">
<property name="format" value="^[ \t]*(?!TODO:)(?i:TODO)\b:?"/>
<message key="todo.match"
value="''TODO:'' must be written in all caps and followed by a colon."/>
</module>
<module name="EmptyCatchBlock">
<property name="commentFormat" value="\w+"/>
</module>
<module name="CommentsIndentation">
<property name="tokens" value="SINGLE_LINE_COMMENT, BLOCK_COMMENT_BEGIN"/>
</module>
<!-- https://checkstyle.org/filters/suppressionxpathfilter.html -->
<module name="SuppressionXpathFilter">
<property name="file" value="${org.checkstyle.google.suppressionxpathfilter.config}"
default="checkstyle-xpath-suppressions.xml" />
<property name="optional" value="true"/>
</module>
<module name="SuppressWarningsHolder" />
<module name="SuppressionCommentFilter">
<property name="offCommentFormat" value="CHECKSTYLE.OFF\: ([\w\|]+)" />
<property name="onCommentFormat" value="CHECKSTYLE.ON\: ([\w\|]+)" />
<property name="checkFormat" value="$1" />
</module>
<module name="SuppressWithNearbyCommentFilter">
<property name="commentFormat" value="CHECKSTYLE.SUPPRESS\: ([\w\|]+)"/>
<!-- $1 refers to the first match group in the regex defined in commentFormat -->
<property name="checkFormat" value="$1"/>
<!-- The check is suppressed in the next line of code after the comment -->
<property name="influenceFormat" value="1"/>
</module>
</module>
</module>
package collection;
import static org.junit.jupiter.api.Assertions.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import org.junit.jupiter.api.*;
public class RedBlackTreeTest {
@Test
void addContainsRemove() {
RedBlackTree<Integer> t = new RedBlackTree<>();
assertTrue(t.add(5));
assertTrue(t.contains(5));
assertFalse(t.add(5)); // no duplicates
assertTrue(t.add(3));
assertTrue(t.add(7));
assertEquals(3, t.size());
assertTrue(t.remove(3));
assertFalse(t.contains(3));
assertEquals(2, t.size());
}
@Test
void inOrderTraversalIsSorted() {
RedBlackTree<Integer> t = new RedBlackTree<>();
List<Integer> vals = Arrays.asList(5, 2, 8, 1, 3, 7, 9);
Collections.shuffle(vals, new Random(42));
t.addAll(vals);
int prev = Integer.MIN_VALUE;
for (Integer v : t) {
assertTrue(v > prev);
prev = v;
}
}
@Test
void largeRandomInsertions() {
RedBlackTree<Integer> t = new RedBlackTree<>();
int n = 10000;
Random rnd = new Random(123);
List<Integer> arr = new ArrayList<>();
for (int i = 0; i < n; i++)
arr.add(i);
Collections.shuffle(arr, rnd);
for (int x : arr)
t.add(x);
assertEquals(n, t.size());
for (int i = 0; i < n; i++)
assertTrue(t.contains(i));
}
}