Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
static public int getMiddleIndex(int beginIndex, int endIndex) {
return beginIndex + (endIndex - beginIndex) / 2;
}
static public void main(String[] args) {
System.out.println(getMiddleIndex(0, 10));
}test {
useJUnitPlatform()
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
}package edu.emory.cs.utils;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
@Test
public void getMiddleIndexTest() {
assertEquals(5, Utils.getMiddleIndex(0, 10));
}Jinho D. Choi


git config --global user.email "your_id@emory.edu"
git config --global user.name "Your Name"distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zipcompileJava {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}repositories {
mavenCentral()
}/.gradle/
/.idea/
/.vscode/
/build/Spring 2023
pivotpublic class MergeSort<T extends Comparable<T>> extends AbstractSort<T> {
private T[] temp;
public MergeSort() {
this(Comparator.naturalOrder());
}
public MergeSort(Comparator<T> comparator) {
super(comparator);
}
}@Override
@SuppressWarnings("unchecked")
public void sort(T[] array, int beginIndex, int endIndex) {
if (temp == null || temp.length < array.length)
temp = (T[])Array.newInstance(array[0].getClass(), array.length);
sort(array, temp, beginIndex, endIndex);
}/**
* @param input the input array.
* @param temp the array to hold the copy of the input array.
* @param beginIndex the beginning index of the 1st half (inclusive).
* @param endIndex the ending index of the 2nd half (exclusive).
*/
protected void sort(T[] input, T[] copy, int beginIndex, int endIndex) {
if (beginIndex + 1 >= endIndex) return;
int middleIndex = Utils.getMiddleIndex(beginIndex, endIndex);
sort(input, copy, beginIndex, middleIndex);
sort(input, copy, middleIndex, endIndex);
merge(input, copy, beginIndex, middleIndex, endIndex);
}/**
* @param input the input array.
* @param temp the array to hold the copy of the input array.
* @param beginIndex the beginning index of the 1st half (inclusive).
* @param middleIndex the ending index of the 1st half (exclusive).
* @param endIndex the ending index of the 2nd half (exclusive).
*/
protected void merge(T[] input, T[] copy, int beginIndex, int middleIndex, int endIndex) {
int fst = beginIndex, snd = middleIndex, n = endIndex - beginIndex;
System.arraycopy(input, beginIndex, copy, beginIndex, n);
assignments += n;
for (int k = beginIndex; k < endIndex; k++) {
if (fst >= middleIndex)
assign(input, k, copy[snd++]);
else if (snd >= endIndex)
assign(input, k, copy[fst++]);
else if (compareTo(copy, fst, snd) < 0)
assign(input, k, copy[fst++]);
else
assign(input, k, copy[snd++]);
}
}public class QuickSort<T extends Comparable<T>> extends AbstractSort<T> {
public QuickSort() {
this(Comparator.naturalOrder());
}
public QuickSort(Comparator<T> comparator) {
super(comparator);
}
}@Override
public void sort(T[] array, int beginIndex, int endIndex) {
if (beginIndex >= endIndex) return;
int pivotIndex = partition(array, beginIndex, endIndex);
sort(array, beginIndex, pivotIndex);
sort(array, pivotIndex + 1, endIndex);
}protected int partition(T[] array, int beginIndex, int endIndex) {
int fst = beginIndex, snd = endIndex;
while (true) {
while (++fst < endIndex && compareTo(array, beginIndex, fst) >= 0);
while (--snd > beginIndex && compareTo(array, beginIndex, snd) <= 0);
if (fst >= snd) break;
swap(array, fst, snd);
}
swap(array, beginIndex, snd);
return snd;
}public class IntroSort<T extends Comparable<T>> extends QuickSort<T> {
private final AbstractSort<T> engine;
public IntroSort(AbstractSort<T> engine) {
this(engine, Comparator.naturalOrder());
}
public IntroSort(AbstractSort<T> engine, Comparator<T> comparator) {
super(comparator);
this.engine = engine;
}
@Override
public void resetCounts() {
super.resetCounts();
if (engine != null) engine.resetCounts();
}
}@Override
public void sort(T[] array, int beginIndex, int endIndex) {
final int maxdepth = getMaxDepth(beginIndex, endIndex);
sort(array, beginIndex, endIndex, maxdepth);
comparisons += engine.getComparisonCount();
assignments += engine.getAssignmentCount();
}
protected int getMaxDepth(int beginIndex, int endIndex) {
return 2 * (int)Utils.log2(endIndex - beginIndex);
}private void sort(T[] array, int beginIndex, int endIndex, int maxdepth) {
if (beginIndex >= endIndex) return;
if (maxdepth == 0) // encounter the worst case
engine.sort(array, beginIndex, endIndex);
else {
int pivotIndex = partition(array, beginIndex, endIndex);
sort(array, beginIndex, pivotIndex, maxdepth - 1);
sort(array, pivotIndex + 1, endIndex, maxdepth - 1);
}
}Integer[][] input = {{0, 1, 2, 3},
{7, 6, 5, 4},
{0, 3, 1, 2},
{4, 7, 6, 5},
{9, 8, 11, 10}};[0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 9, 10, 11]public abstract class BucketSort<T extends Comparable<T>> extends AbstractSort<T> {
protected List<Deque<T>> buckets;
/** @param numBuckets the total number of buckets. */
public BucketSort(int numBuckets) {
super(null);
buckets = Stream.generate(ArrayDeque<T>::new).limit(numBuckets).collect(Collectors.toList());
}
}L13-16: puts all keys in the buckets back to the input array while keeping the order.This section describes disjoint sets
LongInteger: implementation.
Lazy and eager priority queues.
This section discusses a type of balanced binary search trees called Red-Black Trees.
This sections discusses the implementation of disjoint sets.
public abstract class AbstractBinaryNode<T extends Comparable<T>, N extends AbstractBinaryNode<T, N>> {
protected T key;
protected N parent;
protected N left_child;
protected N right_child;
public AbstractBinaryNode(T key) {
setKey(key);
}
}public boolean hasParent() { return parent != null; }
public boolean hasLeftChild() { return left_child != null; }
public boolean hasRightChild() { return right_child != null; }
public boolean hasBothChildren() {
return hasLeftChild() && hasRightChild();
}
/** @return true if the specific node is the left child of this node. */
public boolean isLeftChild(N node) {
return left_child == node;
}
/** @return true if the specific node is the right child of this node. */
public boolean isRightChild(N node) {
return right_child == node;
}public T getKey() { return key; }
public N getParent() { return parent; }
public N getLeftChild() { return left_child; }
public N getRightChild() { return right_child; }public N getGrandParent() {
return hasParent() ? parent.getParent() : null;
}
@SuppressWarnings("unchecked")
public N getSibling() {
if (hasParent()) {
N parent = getParent();
return parent.isLeftChild((N)this) ? parent.getRightChild() : parent.getLeftChild();
}
return null;
}
public N getUncle() {
return hasParent() ? parent.getSibling() : null;
}public void setKey(T key) { this.key = key; }
public void setParent(N node) { parent = node; }
public void setLeftChild(N node) {
replaceParent(node);
left_child = node;
}
public void setRightChild(N node) {
replaceParent(node);
right_child = node;
}
/**
* Replaces the parent of the specific node to be this node.
* @param node the node whose parent to be replaced.
*/
@SuppressWarnings("unchecked")
protected void replaceParent(N node) {
if (node != null) {
if (node.hasParent()) node.getParent().replaceChild(node, null);
node.setParent((N)this);
}
}
/**
* Replaces the old child with the new child if exists.
* @param oldChild the old child of this node to be replaced.
* @param newChild the new child to be added to this node.
*/
public void replaceChild(N oldChild, N newChild) {
if (isLeftChild(oldChild)) setLeftChild(newChild);
else if (isRightChild(oldChild)) setRightChild(newChild);
}public class BinaryNode<T extends Comparable<T>> extends AbstractBinaryNode<T, BinaryNode<T>> {
public BinaryNode(T key) {
super(key);
}
}public abstract class AbstractBinarySearchTree<T extends Comparable<T>, N extends AbstractBinaryNode<T, N>> {
protected N root;
public AbstractBinarySearchTree() {
setRoot(null);
}
/** @return a new node with the specific key. */
abstract public N createNode(T key);
public boolean isRoot(N node) { return root == node; }
public N getRoot() { return root; }
public void setRoot(N node) {
if (node != null) node.setParent(null);
root = node;
}
}/** @return the node with the specific key if exists; otherwise, {@code null}. */
public N get(T key) {
return findNode(root, key);
}
/** @return the node with the specific key if exists; otherwise, {@code null}. */
protected N findNode(N node, T key) {
if (node == null) return null;
int diff = key.compareTo(node.getKey());
if (diff < 0)
return findNode(node.getLeftChild(), key);
else if (diff > 0)
return findNode(node.getRightChild(), key);
else
return node;
}
/** @return the node with the minimum key under the subtree of {@code node}. */
protected N findMinNode(N node) {
return node.hasLeftChild() ? findMinNode(node.getLeftChild()) : node;
}
/** @return the node with the maximum key under the subtree of {@code node}. */
protected N findMaxNode(N node) {
return node.hasRightChild() ? findMaxNode(node.getRightChild()) : node;
}public N add(T key) {
N node = null;
if (root == null)
setRoot(node = createNode(key));
else
node = addAux(root, key);
return node;
}
private N addAux(N node, T key) {
int diff = key.compareTo(node.getKey());
N child, newNode = null;
if (diff < 0) {
if ((child = node.getLeftChild()) == null)
node.setLeftChild(newNode = createNode(key));
else
newNode = addAux(child, key);
}
else if (diff > 0) {
if ((child = node.getRightChild()) == null)
node.setRightChild(newNode = createNode(key));
else
newNode = addAux(child, key);
}
return newNode;
}/** @return the removed node with the specific key if exists; otherwise, {@code null}. */
public N remove(T key) {
N node = findNode(root, key);
if (node != null) {
if (node.hasBothChildren()) removeHibbard(node);
else removeSelf(node);
}
return node;
}/** @return the lowest node whose subtree has been updatede. */
protected N removeSelf(N node) {
N parent = node.getParent();
N child = null;
if (node.hasLeftChild()) child = node.getLeftChild();
else if (node.hasRightChild()) child = node.getRightChild();
replaceChild(node, child);
return parent;
}
private void replaceChild(N oldNode, N newNode) {
if (isRoot(oldNode))
setRoot(newNode);
else
oldNode.getParent().replaceChild(oldNode, newNode);
}/** @return the lowest node whose subtree has been updatede. */
protected N removeHibbard(N node) {
N successor = node.getRightChild();
N min = findMinNode(successor);
N parent = min.getParent();
min.setLeftChild(node.getLeftChild());
if (min != successor) {
parent.setLeftChild(min.getRightChild());
min.setRightChild(successor);
}
replaceChild(node, min);
return parent;
}public class BinarySearchTree<T extends Comparable<T>> extends AbstractBinarySearchTree<T, BinaryNode<T>> {
/**
* @param key the key of this node.
* @return a binary node with the specific key.
*/
@Override
public BinaryNode<T> createNode(T key) {
return new BinaryNode<T>(key);
}
}/**
* @param array the input array.
* @param beginIndex the index of the first key to be sorted (inclusive).
* @param endIndex the index of the last key to be sorted (exclusive).
* @param bucketIndex takes a key and returns the index of the bucket that the key to be added.
*/
protected void sort(T[] array, int beginIndex, int endIndex, Function<T, Integer> bucketIndex) {
// add each element in the input array to the corresponding bucket
for (int i = beginIndex; i < endIndex; i++)
buckets.get(bucketIndex.apply(array[i])).add(array[i]);
// merge elements in all buckets to the input array
for (Deque<T> bucket : buckets) {
while (!bucket.isEmpty())
array[beginIndex++] = bucket.remove();
}
}public class IntegerBucketSort extends BucketSort<Integer> {
private final int MIN;
/**
* @param min the minimum integer (inclusive).
* @param max the maximum integer (exclusive).
*/
public IntegerBucketSort(int min, int max) {
super(max - min);
MIN = min;
}
}@Override
public void sort(Integer[] array, int beginIndex, int endIndex) {
sort(array, beginIndex, endIndex, key -> key - MIN);
}public abstract class RadixSort extends BucketSort<Integer> {
public RadixSort() {
super(10);
}
protected int getMaxBit(Integer[] array, int beginIndex, int endIndex) {
Integer max = Arrays.stream(array, beginIndex, endIndex).reduce(Integer::max).orElse(null);
return (max != null && max > 0) ? (int)Math.log10(max) + 1 : 0;
}
}public class LSDRadixSort extends RadixSort {
@Override
public void sort(Integer[] array, int beginIndex, int endIndex) {
int maxBit = getMaxBit(array, beginIndex, endIndex);
for (int bit = 0; bit < maxBit; bit++) {
int div = (int)Math.pow(10, bit);
sort(array, beginIndex, endIndex, key -> (key / div) % 10);
}
}
}public class TrieNode<T> {
private final Map<Character, TrieNode<T>> children;
private TrieNode<T> parent;
private boolean end_state;
private char key;
private T value;
public TrieNode(TrieNode<T> parent, char key) {
children = new HashMap<>();
setEndState(false);
setParent(parent);
setKey(key);
setValue(null);
}
}"sh" -> ["she", "ship", "shell, ...]"sh" -> ["ship", "she", "shell, ...]List<String>getCandidates() method:
union(1, 3) method joins two sets including 1 and 3 as one set:0: {0}
1: {1}
2: {2}
3: {3}
4: {4}inSameSet(1, 3) -> falseL6: the @Test annotation indicates that this method is used for unit testing. public int find(int id) {
return (subsets[id] < 0) ? id : find(subsets[id]);
}public int find(int id) {
return (subsets[id] < 0) ? id : (subsets[id] = find(subsets[id]));
}0: {0}
1: {1, 3}
2: {2}
3: {1, 3}
4: {4}inSameSet(1, 3) -> true
inSameSet(1, 4) -> false0: {0}
1: {1, 3, 4}
2: {2}
3: {1, 3, 4}
4: {1, 3, 4}`inSameSet(1, 4)` -> true
`inSameSet(3, 4)` -> trueimport org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class LongIntegerTest {
@Test
public void testConstructors() {
// default constructor
assertEquals("0", new LongInteger().toString());
// constructor with a string parameter
assertEquals("12", new LongInteger("12").toString());
assertEquals("34", new LongInteger("+34").toString());
assertEquals("-56", new LongInteger("-56").toString());
assertEquals("-0", new LongInteger("-0").toString());
// copy constructor
assertEquals("12", new LongInteger(new LongInteger("12")).toString());
assertEquals("-34", new LongInteger(new LongInteger("-34")).toString());
}
}Tests passed: 1 of 1 test@Test
public void testMultiply() {
LongInteger a = new LongInteger("123456789");
a.multiply(new LongInteger("1"));
assertEquals("123456789", a.toString());
a.multiply(new LongInteger("-1"));
assertEquals("-123456789", a.toString());
a.multiply(new LongInteger("-1234567890123456789"));
assertEquals("152415787517146788750190521", a.toString());
a.multiply(new LongInteger("0"));
assertEquals("0", a.toString());
a.multiply(new LongInteger("-0"));
assertEquals("-0", a.toString());
}@Test
public void testCompareTo() {
assertTrue(0 < new LongInteger("0").compareTo(new LongInteger("-0")));
assertTrue(0 > new LongInteger("-0").compareTo(new LongInteger("0")));
assertTrue(0 < new LongInteger("12").compareTo(new LongInteger("-34")));
assertTrue(0 > new LongInteger("-12").compareTo(new LongInteger("34")));
assertTrue(0 > new LongInteger("-34").compareTo(new LongInteger("12")));
assertTrue(0 < new LongInteger("34").compareTo(new LongInteger("-12")));
}public abstract class AbstractSort<T extends Comparable<T>> {
private final Comparator<T> comparator;
protected long comparisons;
protected long assignments;
/** @param comparator specifies the precedence of comparable keys. */
public AbstractSort(Comparator<T> comparator) {
this.comparator = comparator;
resetCounts();
}
/** @return the total number of comparisons performed during sort. */
public long getComparisonCount() {
return comparisons;
}
/** @return the total number of assignments performed during sort. */
public long getAssignmentCount() {
return assignments;
}
public void resetCounts() {
comparisons = assignments = 0;
}
}/**
* @param array an array of comparable keys.
* @param i the index of the first key.
* @param j the index of the second key.
* @return array[i].compareTo(array[j]).
*/
protected int compareTo(T[] array, int i, int j) {
comparisons++;
return comparator.compare(array[i], array[j]);
}
/**
* array[index] = value.
* @param array an array of comparable keys.
* @param index the index of the array to assign.
* @param value the value to be assigned.
*/
protected void assign(T[] array, int index, T value) {
assignments++;
array[index] = value;
}
/**
* Swaps array[i] and array[j].
* @param array an array of comparable keys.
* @param i the index of the first key.
* @param j the index of the second key.
*/
protected void swap(T[] array, int i, int j) {
T t = array[i];
assign(array, i, array[j]);
assign(array, j, t);
}/**
* Sorts the array in ascending order.
* @param array an array of comparable keys.
*/
public void sort(T[] array) {
sort(array, 0, array.length);
}
/**
* Sorts the array[beginIndex:endIndex].
* @param array an array of comparable keys.
* @param beginIndex the index of the first key to be sorted (inclusive).
* @param endIndex the index of the last key to be sorted (exclusive).
*/
abstract public void sort(T[] array, int beginIndex, int endIndex);public class DisjointSet {
private final int[] subsets;
public DisjointSet(int size) {
subsets = new int[size];
Arrays.fill(subsets, -1);
}
public DisjointSet(DisjointSet set) {
subsets = Arrays.copyOf(set.subsets, set.subsets.length);
}
}public boolean inSameSet(int key1, int key2) {
return find(key1) == find(key2);
}public int union(int key1, int key2) {
int r1 = find(key1);
int r2 = find(key2);
if (r1 == r2) return r1;
if (subsets[r1] < subsets[r2]) {
subsets[r1] += subsets[r2];
subsets[r2] = r1;
return r1;
}
else {
subsets[r2] += subsets[r1];
subsets[r1] = r2;
return r2;
}
}[3, 1, 2]keyL8: returns the value of the previously key if exists; otherwise, null.L7-10: if the retrieved node has children, sets its end-state to false and returns true.BigInteger although the implementations of LongIntegerandBigIntegerare completely independent.L6: the generic type T is defined specifically for this method such that the priority queue pq, the list keys, and the comparator comp take the same type T that is comparable.["she", "shell", "see", "shore", "selling", "sell"]This section describes an algorithm to detect a cycle in a graph.
public boolean containsCycle() {
Deque<Integer> notVisited = IntStream.range(0, size()).boxed().collect(Collectors.toCollection(ArrayDeque::new));
while (!notVisited.isEmpty()) {
if (containsCycleAux(notVisited.poll(), notVisited, new HashSet<>()))
return true;
}
return false;
}This section discusses Prim's Algorithm that finds a minimum spanning tree in an undirected graph.
This section discusses Chu-Liu-Edmonds' Algorithm that finds a MST in a directed graph.
This section discusses Kruskal's Algorithm that finds a minimum spanning tree in an undirected graph.
public abstract class AbstractBalancedBinarySearchTree<T extends Comparable<T>, N extends AbstractBinaryNode<T, N>> extends AbstractBinarySearchTree<T, N> {
/**
* Rotates the specific node to the left.
* @param node the node to be rotated.
*/
protected void rotateLeft(N node) {
N child = node.getRightChild();
node.setRightChild(child.getLeftChild());
if (node.hasParent())
node.getParent().replaceChild(node, child);
else
setRoot(child);
child.setLeftChild(node);
}
/**
* Rotates the specific node to the right.
* @param node the node to be rotated.
*/
protected void rotateRight(N node) {
N child = node.getLeftChild();
node.setLeftChild(child.getRightChild());
if (node.hasParent())
node.getParent().replaceChild(node, child);
else
setRoot(child);
child.setRightChild(node);
}
}@Override
public N add(T key) {
N node = super.add(key);
balance(node);
return node;
}
@Override
public N remove(T key) {
N node = findNode(root, key);
if (node != null) {
N lowest = node.hasBothChildren() ? removeHibbard(node) : removeSelf(node);
if (lowest != null && lowest != node) balance(lowest);
}
return node;
}
/**
* Preserves the balance of the specific node and its ancestors.
* @param node the node to be balanced.
*/
protected abstract void balance(N node);public TrieNode<T> getParent() { return parent; }
public char getKey() { return key; }
public T getValue() { return value; }
public TrieNode<T> getChild(char key) { return children.get(key); }
/** @return the map whose keys and values are children's characters and nodes. */
public Map<Character, TrieNode<T>> getChildrenMap() {
return children;
}public void setParent(TrieNode<T> node) { parent = node; }
public void setKey(char key) { this.key = key; }
public void setEndState(boolean endState) { end_state = endState; }
public T setValue(T value) {
T tmp = this.value;
this.value = value;
return tmp;
}
public TrieNode<T> addChild(char key) {
TrieNode<T> child = getChild(key);
if (child == null) {
child = new TrieNode<>(this, key);
children.put(key, child);
}
return child;
}
public TrieNode<T> removeChild(char key) {
return children.remove(key);
}public boolean isEndState() { return end_state; }
public boolean hasValue() { return value != null; }
public boolean hasChildren() { return !children.isEmpty(); }public class Trie<T> {
private final TrieNode<T> root;
public Trie() {
root = new TrieNode<>(null, (char)0);
}
public TrieNode<T> getRoot() { return root; }
}/** @return the node with the specific key if exists; otherwise, {@code null}. */
public TrieNode<T> find(String key) {
TrieNode<T> node = root;
for (char c : key.toCharArray()) {
node = node.getChild(c);
if (node == null) return null;
}
return node;
}public T get(String key) {
TrieNode<T> node = find(key);
return (node != null && node.isEndState()) ? node.getValue() : null;
}
public boolean contains(String key) {
return get(key) != null;
}public T put(String key, T value) {
TrieNode<T> node = root;
for (char c : key.toCharArray())
node = node.addChild(c);
node.setEndState(true);
return node.setValue(value);
}public boolean remove(String key) {
TrieNode<T> node = find(key);
if (node == null || !node.isEndState())
return false;
if (node.hasChildren()) {
node.setEndState(false);
return true;
}
TrieNode<T> parent = node.getParent();
while (parent != null) {
parent.removeChild(node.getKey());
if (parent.hasChildren() || parent.isEndState())
break;
else {
node = parent;
parent = parent.getParent();
}
}
return true;
}String s = "";
if (sign == Sign.NEGATIVE) s += "-";
for (int i = digits.length - 1; i >= 0; i--)
s += digits[i];
return s;public class LongInteger extends SignedNumeral<LongInteger> {
/** The values of this integer (excluding the sign). */
protected byte[] digits;
.../** Creates a long integer with the default value of "0". */
public LongInteger() {
this("0");
}
/**
* Creates a long integer by copying the specific object.
* @param n the object to be copied.
*/
public LongInteger(LongInteger n) {
super(n.sign);
digits = Arrays.copyOf(n.digits, n.digits.length);
}
/**
* Creates a long integer with the specific sign and values.
* @param n the sign and values to be set.
* @see #set(String)
*/
public LongInteger(String n) {
set(n);
}/**
* Sets the sign and values of this integer.
* @param n the sign and values to be set.
* @throws NullPointerException when `n` is null.
* @throws InvalidParameterException when `n` contains non-digit character
* except for the first character that can be [+-\d].
*/
public void set(String n) {
// 'n' must not be null
if (n == null)
throw new NullPointerException();
// set this.sign
sign = switch (n.charAt(0)) {
case '-' -> { n = n.substring(1); yield Sign.NEGATIVE; }
case '+' -> { n = n.substring(1); yield Sign.POSITIVE; }
default -> Sign.POSITIVE;
};
// set this.digits
digits = new byte[n.length()];
for (int i = 0, j = n.length() - 1; i < n.length(); i++, j--) {
byte v = (byte)(n.charAt(i) - 48);
if (0 > v || v > 9) {
String s = String.format("%d is not a valid value", v);
throw new InvalidParameterException(s);
}
digits[j] = v;
}
}@Override
public void add(LongInteger n) {
if (sign == n.sign)
addSameSign(n);
else
addDifferentSign(n);
}/**
* Adds the specific integer that has the same sign as this integer.
* @param n the integer to be added with the same sign.
*/
protected void addSameSign(LongInteger n) {
// copy this integer to result[]
int m = Math.max(digits.length, n.digits.length);
byte[] result = new byte[m + 1];
System.arraycopy(digits, 0, result, 0, digits.length);
// add n to result
for (int i = 0; i < n.digits.length; i++) {
if (i < n.digits.length)
result[i] += n.digits[i];
if (result[i] >= 10) {
result[i] -= 10;
result[i + 1] += 1;
}
}
// set this.digits
digits = result[m] == 0 ? Arrays.copyOf(result, m) : result;
}/**
* Adds the specific integer that has a different sign from this integer.
* @param n the integer to be added with a different sign
*/
protected void addDifferentSign(LongInteger n) {
throw new UnsupportedOperationException();
}@Override
public void multiply(LongInteger n) {
// set this.sign
sign = (sign == n.sign) ? Sign.POSITIVE : Sign.NEGATIVE;
// multiply this and n and save it to result
byte[] result = new byte[digits.length + n.digits.length];
for (int i = 0; i < digits.length; i++) {
for (int j = 0; j < n.digits.length; j++) {
int k = i + j, prod = digits[i] * n.digits[j];
result[k] += prod;
result[k + 1] += result[k] / 10;
result[k] %= 10;
}
}
// set this.digits
int m; for (m = result.length - 1; m > 0; m--)
if (result[m] != 0) break;
digits = ++m < result.length ? Arrays.copyOf(result, m) : result;
}public class LongIntegerRun {
static public void main(String[] args) {
System.out.println(args);
}
}[Ljava.lang.String;@d716361static public void main(String[] args) {
System.out.println(Arrays.toString(args));
}[][123, -456]static public void main(String[] args) {
LongInteger a = new LongInteger(args[0]);
LongInteger b = new LongInteger(args[1]);
System.out.println(a);
System.out.println(b);
}edu.emory.cs.algebraic.LongInteger@4d7e1886
edu.emory.cs.algebraic.LongInteger@3cd1a2f1public class LongInteger extends SignedNumeral<LongInteger> {
...
@Override
public String toString() {
StringBuilder build = new StringBuilder();
if (sign == Sign.NEGATIVE) build.append("-");
for (int i = digits.length - 1; i >= 0; i--)
build.append(digits[i]);
return build.toString();
}
...123
-456boolean c = a < b; // gives a compile errorpublic class LongInteger extends SignedNumeral<LongInteger>
implements Comparable<LongInteger> {
...
}@Override
public int compareTo(LongInteger n) {
if (isPositive())
return n.isNegative() ? 1 : compareAbs(n);
else
return n.isPositive() ? -1 : -compareAbs(n);
}/**
* @param n the object to be compared.
* @return a negative integer, zero, or a positive integer as the absolute value of this object is
* less than, equal to, or greater than the absolute value of the specified object.
*/
public int compareAbs(LongInteger n) {
int diff = digits.length - n.digits.length;
if (diff == 0) {
for (int i = digits.length - 1; i >= 0; i--) {
diff = digits[i] - n.digits[i];
if (diff != 0) break;
}
}
return diff;
}static public void main(String[] args) {
List<LongInteger> list = new ArrayList<>();
list.add(new LongInteger("78"));
list.add(new LongInteger("-45"));
list.add(new LongInteger("0"));
list.add(new LongInteger("6"));
list.add(new LongInteger("-0"));
list.add(new LongInteger("-123"));
list.sort(Comparator.naturalOrder());
System.out.println(list);
list.sort(Comparator.reverseOrder());
System.out.println(list);
}[-123, -45, -0, 0, 6, 78]
[78, 6, 0, -0, -45, -123]public class SelectionSort<T extends Comparable<T>> extends AbstractSort<T> {
public SelectionSort() {
this(Comparator.naturalOrder());
}
public SelectionSort(Comparator<T> comparator) {
super(comparator);
}
}@Override
public void sort(T[] array, final int beginIndex, final int endIndex) {
for (int i = endIndex; i > beginIndex; i--) {
int max = beginIndex;
for (int j = beginIndex + 1; j < i; j++) {
if (compareTo(array, j, max) > 0)
max = j;
}
swap(array, max, i - 1);
}
}public class HeapSort<T extends Comparable<T>> extends AbstractSort<T> {
public HeapSort() {
this(Comparator.naturalOrder());
}
public HeapSort(Comparator<T> comparator) {
super(comparator);
}
}private void sink(T[] array, int k, int beginIndex, int endIndex) {
for (int i = getLeftChildIndex(beginIndex, k); i < endIndex; k = i, i = getLeftChildIndex(beginIndex, k)) {
if (i + 1 < endIndex && compareTo(array, i, i + 1) < 0) i++;
if (compareTo(array, k, i) >= 0) break;
swap(array, k, i);
}
}
private int getParentIndex(int beginIndex, int k) {
return beginIndex + (k - beginIndex - 1) / 2;
}
private int getLeftChildIndex(int beginIndex, int k) {
return beginIndex + 2 * (k - beginIndex) + 1;
}@Override
public void sort(T[] array, int beginIndex, int endIndex) {
// heapify all elements
for (int k = getParentIndex(beginIndex, endIndex - 1); k >= beginIndex; k--)
sink(array, k, beginIndex, endIndex);
// swap the endIndex element with the root element and sink it
while (endIndex > beginIndex + 1) {
swap(array, beginIndex, --endIndex);
sink(array, beginIndex, beginIndex, endIndex);
}
}public class InsertionSort<T extends Comparable<T>> extends AbstractSort<T> {
public InsertionSort() {
this(Comparator.naturalOrder());
}
public InsertionSort(Comparator<T> comparator) {
super(comparator);
}
}protected void sort(T[] array, int beginIndex, int endIndex, final int h) {
int begin_h = beginIndex + h;
for (int i = begin_h; i < endIndex; i++)
for (int j = i; begin_h <= j && compareTo(array, j, j - h) < 0; j -= h)
swap(array, j, j - h);
}@Override
public void sort(T[] array, int beginIndex, int endIndex) {
sort(array, beginIndex, endIndex, 1);
}public abstract class ShellSort<T extends Comparable<T>> extends InsertionSort<T> {
protected List<Integer> sequence;
public ShellSort(Comparator<T> comparator) {
super(comparator);
sequence = new ArrayList<>();
populateSequence(10000);
}
}/**
* Populates the gap sequence with respect to the size of the list.
* @param n the size of the list to be sorted.
*/
protected abstract void populateSequence(int n);
/**
* @param n the size of the list to be sorted.
* @return the starting index of the sequence with respect to the size of the list.
*/
protected abstract int getSequenceStartIndex(int n);@Override
public void sort(T[] array, int beginIndex, int endIndex) {
int n = endIndex - beginIndex;
populateSequence(n);
for (int i = getSequenceStartIndex(n); i >= 0; i--)
sort(array, beginIndex, endIndex, sequence.get(i));
}public class ShellSortKnuth<T extends Comparable<T>> extends ShellSort<T> {
public ShellSortKnuth() {
this(Comparator.naturalOrder());
}
public ShellSortKnuth(Comparator<T> comparator) {
super(comparator);
}
}@Override
protected void populateSequence(int n) {
n /= 3;
for (int t = sequence.size() + 1; ; t++) {
int h = (int) ((Math.pow(3, t) - 1) / 2);
if (h <= n) sequence.add(h);
else break;
}
}
@Override
protected int getSequenceStartIndex(int n) {
int index = Collections.binarySearch(sequence, n / 3);
if (index < 0) index = -(index + 1);
if (index == sequence.size()) index--;
return index;
}package edu.emory.cs.algebraic;
public class Numeral {
}public class Numeral {
/**
* Adds `n` to this numeral.
* @param n the numeral to be added.
*/
public void add(Numeral n) { /* cannot be implemented */ }
}public interface Numeral {
void add(Numeral n);
}public interface SignedNumeral extends Numeral {
/** Flips the sign of this numeral. */
void flipSign();
/**
* Subtracts `n` from this numeral.
* @param n the numeral to be subtracted.
*/
default void subtract(Numeral n) {
n.flipSign();
add(n);
n.flipSign();
}
}default void subtract(Numeral n) {
((SignedNumeral)n).flipSign();
add(n);
((SignedNumeral)n).flipSign();
}default void subtract(SignedNumeral n) {
n.flipSign();
add(n);
n.flipSign();
}public interface SignedNumeral extends Numeral {
@Override
void add(SignedNumeral n);
...public interface SignedNumeral extends Numeral {
void add(SignedNumeral n);
...public interface Numeral<T extends Numeral<T>> {
void add(T n);
}public interface SignedNumeral extends Numeral<SignedNumeral> {
void flipSign();
default void subtract(SignedNumeral n) {
n.flipSign();
add(n);
n.flipSign();
}
}void add(SignedNumeral n);public class LongInteger implements SignedNumeral {
@Override
public void flipSign() { /* to be implemented */ }
@Override
public void add(SignedNumeral n) { /* to be implemented */ }
}public interface SignedNumeral<T extends SignedNumeral<T>> extends Numeral<T> {
void flipSign();
default void subtract(T n) {
n.flipSign();
add(n);
n.flipSign();
}
}public enum Sign {
POSITIVE,
NEGATIVE;
}public enum Sign {
POSITIVE('+'),
NEGATIVE('-');
private final char value;
Sign(char value) {
this.value = value;
}
/** @return the value of the corresponding item. */
public char value() {
return value;
}
}public interface SignedNumeral<T extends SignedNumeral<T>> extends Numeral<T> {
Sign sign = Sign.POSITIVE;
.../** Flips the sign of this numeral. */
default void flipSign() {
sign = (sign == Sign.POSITIVE) ? Sign.NEGATIVE : Sign.POSITIVE;
}public abstract class SignedNumeral<T extends SignedNumeral<T>> implements Numeral<T> {
/** The sign of this numeral. */
protected Sign sign;
/**
* Create a signed numeral.
* the default sign is {@link Sign#POSITIVE}.
*/
public SignedNumeral() {
this(Sign.POSITIVE);
}
/**
* Create a signed numeral.
* @param sign the sign of this numeral.
*/
public SignedNumeral(Sign sign) {
this.sign = sign;
}
... ...
/** @return true if this numeral is positive; otherwise, false. */
public boolean isPositive() {
return sign == Sign.POSITIVE;
}
/** @return true if this numeral is negative; otherwise, false. */
public boolean isNegative() {
return sign == Sign.NEGATIVE;
}
/** Flips the sign of this numeral. */
public void flipSign() {
sign = isPositive() ? Sign.NEGATIVE : Sign.POSITIVE;
}
/**
* Subtracts `n` from this numeral.
* @param n the numeral to be subtracted.
*/
public void subtract(T n) {
n.flipSign(); add(n); n.flipSign();
}
/**
* Multiplies `n` to this numeral.
* @param n the numeral to be multiplied.
*/
public abstract void multiply(T n);
}public class BinaryHeap<T extends Comparable<T>> extends AbstractPriorityQueue<T> {
private final List<T> keys;
public BinaryHeap() {
this(Comparator.naturalOrder());
}
public BinaryHeap(Comparator<T> priority) {
super(priority);
keys = new ArrayList<>();
keys.add(null);
}
@Override
public int size() {
return keys.size() - 1;
}
}/**
* @param i1 the index of the first key in {@link #keys}.
* @param i2 the index of the second key in {@link #keys}.
* @return a negative integer, zero, or a positive integer as the first key is
* less than, equal to, or greater than the second key.
*/
private int compare(int k1, int k2) {
return priority.compare(keys.get(k1), keys.get(k2));
}@Override
public void add(T key) {
keys.add(key);
swim(size());
}
private void swim(int k) {
for (; 1 < k && compare(k / 2, k) < 0; k /= 2)
Collections.swap(keys, k / 2, k);
}@Override
public T remove() {
if (isEmpty()) return null;
Collections.swap(keys, 1, size());
T max = keys.remove(size());
sink();
return max;
}
private void sink() {
for (int k = 1, i = 2; i <= size(); k = i, i *= 2) {
if (i < size() && compare(i, i + 1) < 0) i++;
if (compare(k, i) >= 0) break;
Collections.swap(keys, k, i);
}
}public abstract class AbstractPriorityQueue<T extends Comparable<T>> {
protected final Comparator<T> priority;
/**
* Initializes this PQ as either a maximum or minimum PQ.
* @param priority if {@link Comparator#naturalOrder()}, this is a max PQ;
* if {@link Comparator#reverseOrder()}, this is a min PQ.
*/
public AbstractPriorityQueue(Comparator<T> priority) {
this.priority = priority;
}
}/**
* Adds a comparable key to this PQ.
* @param key the key to be added.
*/
abstract public void add(T key);
/**
* Removes the key with the highest/lowest priority if exists.
* @return the key with the highest/lowest priority if exists; otherwise, null.
*/
abstract public T remove();
/** @return the size of this PQ. */
abstract public int size();/** @return true if this PQ is empty; otherwise, false. */
public boolean isEmpty() {
return size() == 0;
}public class LazyPriorityQueue<T extends Comparable<T>> extends AbstractPriorityQueue<T> {
private final List<T> keys;
/** Initializes this as a maximum PQ. */
public LazyPriorityQueue() {
this(Comparator.naturalOrder());
}
/** @see AbstractPriorityQueue#AbstractPriorityQueue(Comparator). */
public LazyPriorityQueue(Comparator<T> priority) {
super(priority);
keys = new ArrayList<>();
}
@Override
public int size() {
return keys.size();
}
}/**
* Appends a key to {@link #keys}.
* @param key the key to be added.
*/
@Override
public void add(T key) {
keys.add(key);
}
/**
* Finds the key with the highest/lowest priority, and removes it from {@link #keys}.
* @return the key with the highest/lowest priority if exists; otherwise, null.
*/
@Override
public T remove() {
if (isEmpty()) return null;
T max = Collections.max(keys, priority);
keys.remove(max);
return max;
}public class EagerPriorityQueue<T extends Comparable<T>> extends AbstractPriorityQueue<T> {
private final List<T> keys;
public EagerPriorityQueue() {
this(Comparator.naturalOrder());
}
public EagerPriorityQueue(Comparator<T> priority) {
super(priority);
keys = new ArrayList<>();
}
@Override
public int size() {
return keys.size();
}
}/**
* Adds a key to {@link #keys} by the priority.
* @param key the key to be added.
*/
@Override
public void add(T key) {
// binary search (if not found, index < 0)
int index = Collections.binarySearch(keys, key, priority);
// if not found, the appropriate index is {@code -(index +1)}
if (index < 0) index = -(index + 1);
keys.add(index, key);
}
/**
* Remove the last key in the list.
* @return the key with the highest priority if exists; otherwise, {@code null}.
*/
@Override
public T remove() {
return isEmpty() ? null : keys.remove(keys.size() - 1);
}/**
* @param pq a priority queue.
* @param keys a list of comparable keys.
* @param comp a comparator used for sorting.
*/
<T extends Comparable<T>> void testRobustness(AbstractPriorityQueue<T> pq, List<T> keys, Comparator<T> comp) {
keys.forEach(pq::add);
keys = keys.stream().sorted(comp).collect(Collectors.toList());
keys.forEach(key -> assertEquals(key, pq.remove()));
}for (int i=0; i<keys.size(); i++)
pq.add(keys.get(i));for (T key : keys)
pq.add(key);keys.forEach(key -> pq.add(key));keys.forEach(pq::add);@Test
public void testRobustness() {
List<Integer> keys = List.of(4, 1, 3, 2, 5, 6, 8, 3, 4, 7, 5, 9, 7);
Comparator<Integer> natural = Comparator.naturalOrder();
Comparator<Integer> reverse = Comparator.reverseOrder();
testRobustness(new LazyPriorityQueue<>(), keys, reverse);
testRobustness(new EagerPriorityQueue<>(), keys, reverse);
testRobustness(new BinaryHeap<>(), keys, reverse);
testRobustness(new LazyPriorityQueue<>(reverse), keys, natural);
testRobustness(new EagerPriorityQueue<>(reverse), keys, natural);
testRobustness(new BinaryHeap<>(reverse), keys, natural);
}static class Time {
long add = 0;
long remove = 0;
}<T extends Comparable<T>> void addRuntime(AbstractPriorityQueue<T> queue, Time time, List<T> keys) {
long st, et;
// runtime for add()
st = System.currentTimeMillis();
keys.forEach(queue::add);
et = System.currentTimeMillis();
time.add += et - st;
// runtime for remove()
st = System.currentTimeMillis();
while (!queue.isEmpty()) queue.remove();
et = System.currentTimeMillis();
time.remove += et - st;
}<T extends Comparable<T>> Time[] benchmark(AbstractPriorityQueue<T>[] queues, int size, int iter, Supplier<T> sup) {
Time[] times = Stream.generate(Time::new).limit(queues.length).toArray(Time[]::new);
for (int i = 0; i < iter; i++) {
List<T> keys = Stream.generate(sup).limit(size).collect(Collectors.toList());
for (int j = 0; j < queues.length; j++)
addRuntime(queues[j], times[j], keys);
}
return times;
}@SafeVarargs
final void testRuntime(AbstractPriorityQueue<Integer>... queues) {
final int begin_size = 1000;
final int end_size = 10000;
final int inc = 1000;
final Random rand = new Random();
for (int size = begin_size; size <= end_size; size += inc) {
// JVM warm-up
benchmark(queues, size, 10, rand::nextInt);
// benchmark all priority queues with the same keys
Time[] times = benchmark(queues, size, 1000, rand::nextInt);
StringJoiner joiner = new StringJoiner("\t");
joiner.add(Integer.toString(size));
joiner.add(Arrays.stream(times).map(t -> Long.toString(t.add)).collect(Collectors.joining("\t")));
joiner.add(Arrays.stream(times).map(t -> Long.toString(t.remove)).collect(Collectors.joining("\t")));
System.out.println(joiner.toString());
}
}public class RedBlackNode<T extends Comparable<T>> extends AbstractBinaryNode<T, RedBlackNode<T>> {
private boolean is_red;
public RedBlackNode(T key) {
super(key);
setToRed();
}
public void setToRed() { is_red = true; }
public void setToBlack() { is_red = false; }
public boolean isRed() { return is_red; }
public boolean isBlack() { return !is_red; }
}public class RedBlackTree<T extends Comparable<T>> extends AbstractBalancedBinarySearchTree<T, RedBlackNode<T>> {
@Override
public RedBlackNode<T> createNode(T key) {
return new RedBlackNode<T>(key);
}
}@Override
protected void balance(RedBlackNode<T> node) {
if (isRoot(node))
node.setToBlack();
else if (node.getParent().isRed()) {
RedBlackNode<T> uncle = node.getUncle();
if (uncle != null && uncle.isRed())
balanceWithRedUncle(node, uncle);
else
balanceWithBlackUncle(node);
}
}private void balanceWithRedUncle(RedBlackNode<T> node, RedBlackNode<T> uncle) {
node.getParent().setToBlack();
uncle.setToBlack();
RedBlackNode<T> grandParent = node.getGrandParent();
grandParent.setToRed();
balance(grandParent);
}private void balanceWithBlackUncle(RedBlackNode<T> node) {
RedBlackNode<T> grandParent = node.getGrandParent();
if (grandParent != null) {
RedBlackNode<T> parent = node.getParent();
if (grandParent.isLeftChild(parent) && parent.isRightChild(node)) {
rotateLeft(parent);
node = parent;
}
else if (grandParent.isRightChild(parent) && parent.isLeftChild(node)) {
rotateRight(parent);
node = parent;
}
node.getParent().setToBlack();
grandParent.setToRed();
if (node.getParent().isLeftChild(node))
rotateRight(grandParent);
else
rotateLeft(grandParent);
}
}public class AVLNode<T extends Comparable<T>> extends AbstractBinaryNode<T, AVLNode<T>> {
private int height;
public AVLNode(T key) {
super(key);
height = 1;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}@Override
public void setLeftChild(AVLNode<T> node) {
super.setLeftChild(node);
resetHeights();
}
@Override
public void setRightChild(AVLNode<T> node) {
super.setRightChild(node);
resetHeights();
}
/** Resets the heights of this node and its ancestor, recursively. */
public void resetHeights() {
resetHeightsAux(this);
}
private void resetHeightsAux(AVLNode<T> node) {
if (node != null) {
int lh = node.hasLeftChild() ? node.getLeftChild().getHeight() : 0;
int rh = node.hasRightChild() ? node.getRightChild().getHeight() : 0;
int height = Math.max(lh, rh) + 1;
if (height != node.getHeight()) {
node.setHeight(height);
resetHeightsAux(node.getParent()); // recursively update parent height
}
}
}/** @return height(left-subtree) - height(right-subtree). */
public int getBalanceFactor() {
if (hasBothChildren())
return left_child.getHeight() - right_child.getHeight();
else if (hasLeftChild())
return left_child.getHeight();
else if (hasRightChild())
return -right_child.getHeight();
else
return 0;
}public class AVLTree<T extends Comparable<T>> extends AbstractBalancedBinarySearchTree<T, AVLNode<T>> {
@Override
public AVLNode<T> createNode(T key) {
return new AVLNode<>(key);
}
@Override
protected void rotateLeft(AVLNode<T> node) {
super.rotateLeft(node);
node.resetHeights();
}
@Override
protected void rotateRight(AVLNode<T> node) {
super.rotateRight(node);
node.resetHeights();
}
}@Override
protected void balance(AVLNode<T> node) {
if (node == null) return;
int bf = node.getBalanceFactor();
if (bf == 2) {
AVLNode<T> child = node.getLeftChild();
if (child.getBalanceFactor() == -1)
rotateLeft(child);
rotateRight(node);
}
else if (bf == -2) {
AVLNode<T> child = node.getRightChild();
if (child.getBalanceFactor() == 1)
rotateRight(child);
rotateLeft(node);
}
else
balance(node.getParent());
}public int find(int id) {
return (subsets[id] < 0) ? id : find(subsets[id]);
}public int find(int id) {
return (subsets[id] < 0) ? id : (subsets[id] = find(subsets[id]));
}public class Edge implements Comparable<Edge> {
private int source;
private int target;
private double weight;
public Edge(int source, int target, double weight) {
init(source, target, weight);
}
public Edge(int source, int target) {
this(source, target, 0);
}
public Edge(Edge edge) {
this(edge.getSource(), edge.getTarget(), edge.getWeight());
}
}private void init(int source, int target, double weight) {
setSource(source);
setTarget(target);
setWeight(weight);
}
public int getSource() { return source; }
public int getTarget() { return target; }
public double getWeight() { return weight; }
public void setSource(int vertex) { source = vertex; }
public void setTarget(int vertex) { target = vertex; }
public void setWeight(double weight) { this.weight = weight; }
public void addWeight(double weight) { this.weight += weight; }@Override
public int compareTo(Edge edge) {
double diff = weight - edge.weight;
if (diff > 0) return 1;
else if (diff < 0) return -1;
else return 0;
}public class Graph {
private final List<List<Edge>> incoming_edges;
public Graph(int size) {
incoming_edges = Stream.generate(ArrayList<Edge>::new).limit(size).collect(Collectors.toList());
}
public Graph(Graph g) {
incoming_edges = g.incoming_edges.stream().map(ArrayList::new).collect(Collectors.toList());
}
public boolean hasNoEdge() {
return IntStream.range(0, size()).allMatch(i -> getIncomingEdges(i).isEmpty());
}
public int size() {
return incoming_edges.size();
}
}incoming_edges.set(0, new ArrayList());
incoming_edges.set(1, new ArrayList(new Edge(0, 1), new Edge(2, 1));
incoming_edges.set(2, new ArrayList(new Edge(0, 2)));public Edge setDirectedEdge(int source, int target, double weight) {
List<Edge> edges = getIncomingEdges(target);
Edge edge = new Edge(source, target, weight);
edges.add(edge);
return edge;
}
public void setUndirectedEdge(int source, int target, double weight) {
setDirectedEdge(source, target, weight);
setDirectedEdge(target, source, weight);
}public List<Edge> getIncomingEdges(int target) {
return incoming_edges.get(target);
}
public List<Edge> getAllEdges() {
return incoming_edges.stream().flatMap(List::stream).collect(Collectors.toList());
}
public Deque<Integer> getVerticesWithNoIncomingEdges() {
return IntStream.range(0, size()).filter(i -> getIncomingEdges(i).isEmpty()).boxed().collect(Collectors.toCollection(ArrayDeque::new));
}public List<Deque<Edge>> getOutgoingEdges() {
List<Deque<Edge>> outgoing_edges = Stream.generate(ArrayDeque<Edge>::new).limit(size()).collect(Collectors.toList());
for (int target = 0; target < size(); target++) {
for (Edge incoming_edge : getIncomingEdges(target))
outgoing_edges.get(incoming_edge.getSource()).add(incoming_edge);
}
return outgoing_edges;
}public List<Integer> topological_sort(boolean depth_first) {
Deque<Integer> global = getVerticesWithNoIncomingEdges();
List<Deque<Edge>> outgoingEdgesAll = getOutgoingEdges();
List<Integer> order = new ArrayList<>();
while (!global.isEmpty()) {
Deque<Integer> local = new ArrayDeque<>();
int vertex = global.poll();
order.add(vertex);
Deque<Edge> outgoingEdges = outgoingEdgesAll.get(vertex);
while (!outgoingEdges.isEmpty()) {
Edge edge = outgoingEdges.poll();
//Remove edge in all incomingEdges of the target vertex
List<Edge> incomingEdges = getIncomingEdges(edge.getTarget());
incomingEdges.remove(edge);
//If the vertex has no incoming edges, add it to the local queue awaited to be added to the global deque
if (incomingEdges.isEmpty())
local.add(edge.getTarget());
}
//Transfer all vertices in local to global
while (!local.isEmpty())
if (depth_first) global.addFirst(local.removeLast());
else global.addLast(local.removeFirst());
}
if (!hasNoEdge()) throw new IllegalArgumentException("Cyclic graph.");
return order;
}
L12: iterates through all the outgoing edges of the source vertex:L6-7
private boolean containsCycleAux(int target, Deque<Integer> notVisited, Set<Integer> visited) {
notVisited.remove(target);
visited.add(target);
for (Edge edge : getIncomingEdges(target)) {
if (visited.contains(edge.getSource()))
return true;
if (containsCycleAux(edge.getSource(), notVisited, new HashSet<>(visited)))
return true;
}
return false;
}public class SpanningTree implements Comparable<SpanningTree> {
private final List<Edge> edges;
private double total_weight;
public SpanningTree() {
edges = new ArrayList<>();
}
public SpanningTree(SpanningTree tree) {
edges = new ArrayList<>(tree.getEdges());
total_weight = tree.getTotalWeight();
}
}public List<Edge> getEdges() { return edges; }
public double getTotalWeight() { return total_weight; }
public int size() { return edges.size(); }
public void addEdge(Edge edge) {
edges.add(edge);
total_weight += edge.getWeight();
}@Override
public int compareTo(SpanningTree tree) {
double diff = total_weight - tree.total_weight;
if (diff > 0) return 1;
else if (diff < 0) return -1;
else return 0;
}public interface MST {
public SpanningTree getMinimumSpanningTree(Graph graph);
}public class FordFulkerson implements NetworkFlow {
public MaxFlow getMaximumFlow(Graph graph, int source, int target) {
MaxFlow mf = new MaxFlow(graph);
Subgraph sub;
while ((sub = getAugmentingPath(graph, mf, new Subgraph(), source, target)) != null) {
double min = getMin(mf, sub.getEdges());
mf.updateFlow(sub.getEdges(), min);
}
return mf;
}
}public class FordFulkerson implements NetworkFlow {
public MaxFlow getMaximumFlow(Graph graph, int source, int target) {
MaxFlow mf = new MaxFlow(graph);
Subgraph sub;
while ((sub = getAugmentingPath(graph, mf, new Subgraph(), source, target)) != null) {
double min = getMin(mf, sub.getEdges());
mf.updateFlow(sub.getEdges(), min);
updateBackward(graph, sub, mf, min);
}
return mf;
}
}public class Subgraph {
private final List<Edge> edges;
private final Set<Integer> vertices;
public Subgraph() {
edges = new ArrayList<>();
vertices = new HashSet<>();
}
public Subgraph(Subgraph graph) {
edges = new ArrayList<>(graph.getEdges());
vertices = new HashSet<>(graph.getVertices());
}
}public List<Edge> getEdges() { return edges; }
public Set<Integer> getVertices() { return vertices; }
public void addEdge(Edge edge) {
edges.add(edge);
vertices.add(edge.getSource());
vertices.add(edge.getTarget());
}
public boolean contains(int vertex) {
return vertices.contains(vertex);
}private double getMin(MaxFlow mf, List<Edge> path) {
double min = mf.getResidual(path.get(0));
for (int i = 1; i < path.size(); i++)
min = Math.min(min, mf.getResidual(path.get(i)));
return min;
}private Subgraph getAugmentingPath(Graph graph, MaxFlow mf, Subgraph sub, int source, int target) {
if (source == target) return sub;
Subgraph tmp;
for (Edge edge : graph.getIncomingEdges(target)) {
if (sub.contains(edge.getSource())) continue;
if (mf.getResidual(edge) <= 0) continue;
tmp = new Subgraph(sub);
tmp.addEdge(edge);
tmp = getAugmentingPath(graph, mf, tmp, source, edge.getSource());
if (tmp != null) return tmp;
}
return null;
}protected void updateBackward(Graph graph, Subgraph sub, MaxFlow mf, double min) {
boolean found;
for (Edge edge : sub.getEdges()) {
found = false;
for (Edge rEdge : graph.getIncomingEdges(edge.getSource())) {
if (rEdge.getSource() == edge.getTarget()) {
mf.updateFlow(rEdge, -min);
found = true;
break;
}
}
if (!found) {
Edge rEdge = graph.setDirectedEdge(edge.getTarget(), edge.getSource(), 0);
mf.updateFlow(rEdge, -min);
}
}
}private void add(PriorityQueue<Edge> queue, Set<Integer> visited, Graph graph, int target) {
visited.add(target);
for (Edge edge : graph.getIncomingEdges(target)) {
if (!visited.contains(edge.getSource()))
queue.add(edge);
}
}private void add(PriorityQueue<Edge> queue, Set<Integer> visited, Graph graph, int target) {
visited.add(target);
graph.getIncomingEdges(target).stream().
filter(edge -> !visited.contains(edge.getSource())).
collect(Collectors.toCollection(() -> queue));
}public class MSTPrim implements MST {
@Override
public SpanningTree getMinimumSpanningTree(Graph graph) {
PriorityQueue<Edge> queue = new PriorityQueue<>();
SpanningTree tree = new SpanningTree();
Set<Integer> visited = new HashSet<>();
Edge edge;
add(queue, visited, graph, 0);
while (!queue.isEmpty()) {
edge = queue.poll();
if (!visited.contains(edge.getSource())) {
tree.addEdge(edge);
if (tree.size() + 1 == graph.size()) break;
add(queue, visited, graph, edge.getSource());
}
}
return tree;
}
}public class MSTKruskal implements MST {
@Override
public SpanningTree getMinimumSpanningTree(Graph graph) {
PriorityQueue<Edge> queue = new PriorityQueue<>(graph.getAllEdges());
DisjointSet forest = new DisjointSet(graph.size());
SpanningTree tree = new SpanningTree();
while (!queue.isEmpty()) {
Edge edge = queue.poll();
if (!forest.inSameSet(edge.getTarget(), edge.getSource())) {
tree.addEdge(edge);
if (tree.size() + 1 == graph.size()) break;
forest.union(edge.getTarget(), edge.getSource());
}
}
return tree;
}
}public class MaxFlow {
private Map<Edge, Double> flow_map;
private double maxflow;
public MaxFlow(Graph graph) {
init(graph);
}
public void init(Graph graph) {
flow_map = new HashMap<>();
maxflow = 0;
for (Edge edge : graph.getAllEdges())
flow_map.put(edge, 0d);
}
}public abstract class Hanoi {
/**
* @param n the total number of rings.
* @param source the source tower.
* @param intermediate the intermediate tower.
* @param destination the destination tower.
* @return a list of steps to move all rings in the source tower to the destination tower.
*/
public abstract List<String> solve(int n, char source, char intermediate, char destination);
protected String getKey(int n, char source, char destination) {
return n + ":" + source + "->" + destination;
}
}
L17L3L7: gets the longest common subsequence between c[:i-1] and d[:j].L5: gets the longest common subsequence between c[:i] and d[:j-1].Maximize p = 0x1 + x2 + 0x3 + x4 subject to
x1 <= 4
x2 <= 2
x3 <= 3
x4 <= 2
x2 - x1 <= 0
x4 - x3 <= 0
Maximize p = 0x1 + 0x2 + 0x3 + 0x4 + 0x5 + 0x6 + x7 + x8 subject to
x1 <= 4
x2 <= 2
x3 <= 3
x4 <= 2
x5 <= 3
x6 <= 1
x7 <= 2
x8 <= 4
x3 - x1 <= 0
x4 + x5 - x2 - x6 <= 0
x6 + x7 - x3 - x4 <= 0
x8 - x5 <= 0
public interface Fibonacci {
int get(int k);
}public class FibonacciRecursive implements Fibonacci {
@Override
public int get(int k) {
return switch (k) {
case 0 -> 0;
case 1 -> 1;
default -> get(k - 1) + get(k - 2);
};
}
}public class FibonacciDynamic implements Fibonacci {
@Override
public int get(int k) {
return getAux(k, createTable(k));
}
private int[] createTable(int k) {
int[] table = new int[k + 1];
table[0] = 0;
table[1] = 1;
Arrays.fill(table, 2, k + 1, -1);
return table;
}
private int getAux(int k, int[] table) {
if (table[k] >= 0) return table[k];
return table[k] = getAux(k - 1, table) + getAux(k - 2, table);
}
}public class FibonacciIterative implements Fibonacci {
@Override
public int get(int k) {
if (k < 2) return k;
int f0 = 0, f1 = 1, f2;
for (int i = 2; i < k; i++) {
f2 = f0 + f1;
f0 = f1;
f1 = f2;
}
return f0 + f1;
}
}public double getMaxFlow() {
return maxflow;
}
public double getResidual(Edge edge) {
return edge.getWeight() - flow_map.get(edge);
}public void updateFlow(List<Edge> path, double flow) {
path.forEach(e -> updateFlow(e, flow));
maxflow += flow;
}
public void updateFlow(Edge edge, double flow) {
Double prev = flow_map.getOrDefault(edge, 0d);
flow_map.put(edge, prev + flow);
}public class HanoiRecursive extends Hanoi {
@Override
public List<String> solve(int n, char source, char intermediate, char destination) {
List<String> list = new ArrayList<>();
solve(list, n, source, intermediate, destination);
return list;
}
private void solve(List<String> list, int n, char source, char intermediate, char destination) {
if (n == 0) return;
solve(list, n - 1, source, destination, intermediate);
list.add(getKey(n, source, destination));
solve(list, n - 1, intermediate, source, destination);
}
}public class HanoiDynamic extends Hanoi {
@Override
public List<String> solve(int n, char source, char intermediate, char destination) {
List<String> list = new ArrayList<>();
solve(list, n, source, intermediate, destination, new HashMap<>());
return list;
}
private void solve(List<String> list, int n, char source, char intermediate, char destination, Map<String, int[]> map) {
if (n == 0) return;
int fromIndex = list.size();
int[] sub = map.get(getKey(n - 1, source, intermediate));
if (sub != null) addAll(list, sub[0], sub[1]);
else solve(list, n - 1, source, destination, intermediate, map);
String key = getKey(n, source, destination);
list.add(key);
sub = map.get(getKey(n - 1, intermediate, destination));
if (sub != null) addAll(list, sub[0], sub[1]);
else solve(list, n - 1, intermediate, source, destination, map);
if (!map.containsKey(key))
map.put(key, new int[]{fromIndex, list.size()});
}
private void addAll(List<String> list, int fromIndex, int toIndex) {
for (int i = fromIndex; i < toIndex; i++)
list.add(list.get(i));
}
}public abstract class LCS {
/**
* @param a the first string.
* @param b the second string.
* @return a longest common sequence of the two specific strings.
*/
public String solve(String a, String b) {
return solve(a.toCharArray(), b.toCharArray(), a.length() - 1, b.length() - 1);
}
/**
* @param c the first array of characters.
* @param d the second array of characters.
* @param i the index of the character in {@code c} to be compared.
* @param j the index of the character in {@code d} to be compared.
* @return a longest common sequence of the two specific strings.
*/
protected abstract String solve(char[] c, char[] d, int i, int j);
}public class LCSRecursive extends LCS {
@Override
protected String solve(char[] c, char[] d, int i, int j) {
if (i < 0 || j < 0) return "";
if (c[i] == d[j]) return solve(c, d, i - 1, j - 1) + c[i];
String c1 = solve(c, d, i - 1, j);
String d1 = solve(c, d, i, j - 1);
return (c1.length() > d1.length()) ? c1 : d1;
}
}public class LCSDynamic extends LCS {
@Override
protected String solve(char[] c, char[] d, int i, int j) {
return solve(c, d, i, j, createTable(c, d));
}
/**
* @param c the first string.
* @param d the second string.
* @return the dynamic table populated by estimating the # of LCSs in the grid of the two specific strings.
*/
protected int[][] createTable(char[] c, char[] d) {
final int N = c.length, M = d.length;
int[][] table = new int[N][M];
for (int i = 1; i < N; i++)
for (int j = 1; j < M; j++)
table[i][j] = (c[i] == d[j]) ? table[i - 1][j - 1] + 1 : Math.max(table[i - 1][j], table[i][j - 1]);
return table;
}
}protected String solve(char[] c, char[] d, int i, int j, int[][] table) {
if (i < 0 || j < 0) return "";
if (c[i] == d[j]) return solve(c, d, i - 1, j - 1, table) + c[i];
if (i == 0) return solve(c, d, i, j - 1, table);
if (j == 0) return solve(c, d, i - 1, j, table);
return (table[i - 1][j] > table[i][j - 1]) ? solve(c, d, i - 1, j, table) : solve(c, d, i, j - 1, table);
}Minimize p = 4x1 + 2x2 + 3x3 + 2x4 + 0y1 + 0y3 subject to
x1 + y1 >= 1
x3 + y3 >= 1
x2 - y1 >= 0
x4 - y3 >= 0
Minimize p = 4x1 + 2x2 + 3x3 + 2x4 +
3x5 + x6 + 2x7 + 4x8 + 0y1 + 0y2 + 0y3 + 0y4 subject to
x1 + y1 >= 1
x2 + y2 >= 1
x3 - y1 + y3 >= 0
x4 - y2 + y3 >= 0
x5 - y2 + y4 >= 0
x6 - y3 + y2 >= 0
x7 - y3 >= 0
x8 - y4 >= 0