Skip to content
Merged
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Requires Java 25. Maven comes with the wrapper.

```
src/main/java/io/github/diegourban/algorithms/
datastructure/ array (shuffle), binarytree, linkedlist, queue, set, stack, vector
datastructure/ array (shuffle, swap), binarytree, linkedlist, queue, set (WordSet), stack, vector
io/ Reader: fast tokenising stdin reader for judge-style input
math/ NumberTheory (gcd, lcm, primes, factorisation), Sequences (Fibonacci), Combinatorics, Geometry, Measurement, Numbers, Statistics
search/ BinarySearch.indexOf
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,25 @@ public static void shuffle(final int[] values) {

// place our random choice in the spot by swapping
if (randomChoiceIndex != targetIndex) {
final int displacedValue = values[targetIndex];
values[targetIndex] = values[randomChoiceIndex];
values[randomChoiceIndex] = displacedValue;
swap(values, targetIndex, randomChoiceIndex);
}
}
}

/**
* Swaps two positions of an array in place.
*
* @param values the array
* @param i the first position
* @param j the second position
* @throws ArrayIndexOutOfBoundsException if either position is outside the array
*/
public static void swap(final int[] values, final int i, final int j) {
final int value = values[i];
values[i] = values[j];
values[j] = value;
}

private static int randomBetweenInclusive(final int min, final int max) {
return RANDOM.nextInt((max - min) + 1) + min;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public void add(final int position, final Element element) {
final LinkedListNode previous = this.getNode(position - 1);
final LinkedListNode next = previous.getNext();

final LinkedListNode newNode = new LinkedListNode(element, previous.getNext());
final LinkedListNode newNode = new LinkedListNode(element, next);
newNode.setPrevious(previous);
previous.setNext(newNode);
next.setPrevious(newNode);
Expand Down Expand Up @@ -211,8 +211,8 @@ public boolean contains(final Element element) {
}

/**
* Returns the element names in order, each followed by a comma, inside brackets, for example {@code "[a,b,]"};
* an empty list gives {@code "[]"}.
* Returns the element names in order, separated by commas, inside brackets, for example {@code "[a,b]"}; an
* empty list gives {@code "[]"}.
*
* @return the string form of the list
*/
Expand All @@ -225,8 +225,10 @@ public String toString() {

final StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < this.totalElements; i++) {
if (i > 0) {
sb.append(",");
}
sb.append(current.getElement().getName());
sb.append(",");
current = current.getNext();
}
sb.append("]");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.github.diegourban.algorithms.datastructure.set;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

Expand All @@ -8,16 +9,16 @@
* the character code of its lower-cased first character modulo 26, so buckets do not line up with alphabetical
* order ({@code 'a'} goes to bucket 19).
*/
public class Set {
public class WordSet {

private static final int BUCKET_COUNT = 26;

private final List<LinkedList<String>> table = new LinkedList<LinkedList<String>>();
private final List<List<String>> buckets = new ArrayList<>(BUCKET_COUNT);

/** Creates an empty set with 26 empty buckets. */
public Set() {
public WordSet() {
for (int i = 0; i < BUCKET_COUNT; i++) {
this.table.add(new LinkedList<String>());
this.buckets.add(new LinkedList<>());
}
}

Expand All @@ -28,10 +29,9 @@ public Set() {
* @throws IllegalArgumentException if {@code word} is empty
*/
public void add(final String word) {
if (!contains(word)) {
final int index = calculateTableIndex(word);
final List<String> list = this.table.get(index);
list.add(word);
final List<String> bucket = bucketFor(word);
if (!bucket.contains(word)) {
bucket.add(word);
}
}

Expand All @@ -42,16 +42,11 @@ public void add(final String word) {
* @throws IllegalArgumentException if {@code word} is empty
*/
public void remove(final String word) {
if (contains(word)) {
final int index = calculateTableIndex(word);
final List<String> list = this.table.get(index);
list.remove(word);
}
bucketFor(word).remove(word);
}

private boolean contains(final String word) {
final int index = calculateTableIndex(word);
return this.table.get(index).contains(word);
private List<String> bucketFor(final String word) {
return this.buckets.get(calculateTableIndex(word));
}

private int calculateTableIndex(final String word) {
Expand All @@ -65,10 +60,10 @@ private int calculateTableIndex(final String word) {
* Returns all 26 buckets in index order, each in {@link java.util.AbstractCollection#toString()} format, for
* example {@code "[[], [], ..., [apple], ...]"}.
*
* @return the string form of the bucket table
* @return the string form of the buckets
*/
@Override
public String toString() {
return this.table.toString();
return this.buckets.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public void add(final Element element) {
* @throws IllegalArgumentException if {@code position} is negative or greater than {@link #size()}
*/
public void add(final int position, final Element element) {
if (!isPositionValid(position)) {
if (!isInsertablePosition(position)) {
throw new IllegalArgumentException("Invalid position");
}

Expand All @@ -50,7 +50,7 @@ public void add(final int position, final Element element) {
this.totalElements++;
}

private boolean isPositionValid(final int position) {
private boolean isInsertablePosition(final int position) {
return position >= 0 && position <= totalElements;
}

Expand Down Expand Up @@ -117,22 +117,17 @@ public int size() {

private void ensureCapacity() {
if (this.totalElements == this.elements.length) {
final Element[] newElements = new Element[this.elements.length * 2];
for (int i = 0; i < this.elements.length; i++) {
newElements[i] = this.elements[i];
}
this.elements = newElements;
this.elements = Arrays.copyOf(this.elements, this.elements.length * 2);
}
}

/**
* Returns the whole backing array, including the unused {@code null} slots, in the form
* {@code "Vector{elements=[a, b, null, ...]}"}.
* Returns the stored elements in order, in the form {@code "Vector{elements=[a, b]}"}.
*
* @return the string form of the vector
*/
@Override
public String toString() {
return "Vector{" + "elements=" + Arrays.toString(elements) + '}';
return "Vector{" + "elements=" + Arrays.toString(Arrays.copyOf(elements, totalElements)) + '}';
}
}
50 changes: 23 additions & 27 deletions src/main/java/io/github/diegourban/algorithms/io/Reader.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;

/**
* Fast, buffered reader of ASCII tokens and lines from an {@link InputStream}, for competitive programming.
Expand All @@ -21,9 +22,11 @@
public class Reader {

private static final int BUFFER_SIZE = 1 << 16;
private static final int INITIAL_LINE_CAPACITY = 64;
private DataInputStream input;
private final byte[] buffer;
private int bufferPointer, bytesRead;
private int bufferPointer;
private int bytesRead;

/**
* Creates a reader over the given stream. Nothing is read until the first read method is called.
Expand All @@ -33,23 +36,20 @@ public class Reader {
public Reader(final InputStream input) {
this.input = new DataInputStream(input);
buffer = new byte[BUFFER_SIZE];
bufferPointer = bytesRead = 0;
}

/**
* Reads the next non-empty line.
* <p>
* Leading {@code '\n'} and {@code '\r'} bytes are skipped, so blank lines are never returned; the line ends at
* the next {@code '\n'} or {@code '\r'}, which is consumed but not included. Lines longer than 10,000 bytes are
* not supported.
* the next {@code '\n'} or {@code '\r'}, which is consumed but not included.
*
* @return the line without its terminator; the remaining text, or an empty string, if the input ends first
* @throws EOFException if a previous read already reached the end of the input
* @throws ArrayIndexOutOfBoundsException if the line is longer than 10,000 bytes
* @throws IOException if the underlying stream fails
*/
public String readLine() throws IOException {
final byte[] line = new byte[10000]; // line length
byte[] line = new byte[INITIAL_LINE_CAPACITY];
int length = 0;
int nextByte = 0;

Expand All @@ -60,6 +60,9 @@ public String readLine() throws IOException {
}
break;
}
if (length == line.length) {
line = Arrays.copyOf(line, line.length * 2);
}
line[length++] = (byte) nextByte;
}
return new String(line, 0, length);
Expand All @@ -77,11 +80,7 @@ public String readLine() throws IOException {
*/
public int nextInt() throws IOException {
int result = 0;
byte nextByte = read();

while (nextByte <= ' ') {
nextByte = read();
}
byte nextByte = skipWhitespace();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 MEDIUM RISK

Suggestion: Consider extracting shared token acquisition or digit-parsing logic from the numeric reader methods so future parser fixes remain consistent across numeric types.

See Clone in Codacy

TIP React 👍 if this review is right, or reply with what's wrong and how it could be better to help improve the reviewer.


final boolean negative = (nextByte == '-');
if (negative) {
Expand All @@ -107,11 +106,7 @@ public int nextInt() throws IOException {
* @throws IOException if the underlying stream fails
*/
public char nextChar() throws IOException {
byte nextByte = read();

while (nextByte <= ' ') {
nextByte = read();
}
final byte nextByte = skipWhitespace();

return (char) nextByte;
}
Expand All @@ -127,11 +122,7 @@ public char nextChar() throws IOException {
*/
public long nextLong() throws IOException {
long result = 0;
byte nextByte = read();

while (nextByte <= ' ') {
nextByte = read();
}
byte nextByte = skipWhitespace();

final boolean negative = (nextByte == '-');
if (negative) {
Expand Down Expand Up @@ -162,11 +153,7 @@ public long nextLong() throws IOException {
public double nextDouble() throws IOException {
double result = 0;
double div = 1;
byte nextByte = read();

while (nextByte <= ' ') {
nextByte = read();
}
byte nextByte = skipWhitespace();

final boolean negative = (nextByte == '-');
if (negative) {
Expand Down Expand Up @@ -204,12 +191,21 @@ public void skip(final int n) throws IOException {
}

private void fillBuffer() throws IOException {
bytesRead = input.read(buffer, bufferPointer = 0, BUFFER_SIZE);
bufferPointer = 0;
bytesRead = input.read(buffer, 0, BUFFER_SIZE);
if (isEOF()) {
buffer[0] = -1;
}
}

private byte skipWhitespace() throws IOException {
byte nextByte = read();
while (nextByte <= ' ') {
nextByte = read();
}
return nextByte;
}

private byte read() throws IOException {
if (isEOF()) {
throw new EOFException();
Expand Down
Loading
Loading