Add TreeCharBag (WIP)
This commit is contained in:
parent
941a0973e7
commit
a64a685e75
@ -0,0 +1,71 @@
|
|||||||
|
package me.mrletsplay.shareclientcore.document;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import me.mrletsplay.shareclientcore.debug.DebugValues;
|
||||||
|
import me.mrletsplay.shareclientcore.util.AVLOrderTree;
|
||||||
|
|
||||||
|
public class BinaryTreeCharBag implements CharBag {
|
||||||
|
|
||||||
|
private AVLOrderTree<Char> chars;
|
||||||
|
|
||||||
|
public BinaryTreeCharBag() {
|
||||||
|
this.chars = new AVLOrderTree<>(Util::compareChars);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int add(Char character) {
|
||||||
|
return chars.addIndex(character);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int remove(Char character) {
|
||||||
|
return chars.removeIndex(character);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Char get(int index) {
|
||||||
|
return chars.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
chars.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return chars.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Char> toList() {
|
||||||
|
return chars.stream().toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getContents() {
|
||||||
|
byte[] bytes = new byte[chars.size()];
|
||||||
|
int i = 0;
|
||||||
|
Iterator<Char> it = chars.iterator();
|
||||||
|
while(it.hasNext()) {
|
||||||
|
Char c = it.next();
|
||||||
|
bytes[i++] = c.value();
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getContentsAsString() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DebugValues getDebugValues() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,188 @@
|
|||||||
|
package me.mrletsplay.shareclientcore.util;
|
||||||
|
|
||||||
|
import java.util.AbstractCollection;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A balanced binary tree that supports order statistics ({@link #get(int)} and {@link #indexOf(Object)}).<br>
|
||||||
|
* Can only hold unique elements
|
||||||
|
* @param <E> The element type
|
||||||
|
*/
|
||||||
|
public class AVLOrderTree<E> extends AbstractCollection<E> {
|
||||||
|
|
||||||
|
private Node root;
|
||||||
|
private Comparator<E> comparator;
|
||||||
|
|
||||||
|
public AVLOrderTree(Comparator<E> comparator) {
|
||||||
|
this.comparator = comparator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public AVLOrderTree() {
|
||||||
|
this.comparator = (Comparator<E>) Comparator.naturalOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean add(E e) {
|
||||||
|
return addIndex(e) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int addIndex(E e) {
|
||||||
|
if(root == null) {
|
||||||
|
root = new Node(e);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return index(root.add(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean remove(Object o) {
|
||||||
|
return removeIndex(o) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public int removeIndex(Object o) {
|
||||||
|
if(root == null) return -1;
|
||||||
|
|
||||||
|
Node removed = root.remove((E) o);
|
||||||
|
if(removed == root) root = null;
|
||||||
|
return index(removed);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
root = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int indexOf(E e) {
|
||||||
|
return 0; // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
private int index(Node n) {
|
||||||
|
return 0; // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
public E get(int index) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<E> iterator() {
|
||||||
|
return new TreeIterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
Iterator<E> it = iterator();
|
||||||
|
int i = 0;
|
||||||
|
while(it.hasNext()) {
|
||||||
|
it.next();
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TreeIterator implements Iterator<E> {
|
||||||
|
|
||||||
|
private Node current;
|
||||||
|
private Node next;
|
||||||
|
|
||||||
|
public TreeIterator() {
|
||||||
|
this.current = null;
|
||||||
|
this.next = root == null ? null : root.leftmostChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return next != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public E next() {
|
||||||
|
// FIXME incorrect
|
||||||
|
if(next == null) throw new NoSuchElementException();
|
||||||
|
|
||||||
|
current = next;
|
||||||
|
|
||||||
|
Node afterNext;
|
||||||
|
if(next.right == null) {
|
||||||
|
afterNext = (next.parent != null && next.parent.left == next) ? next.parent : null;
|
||||||
|
}else {
|
||||||
|
afterNext = next.right.leftmostChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
next = afterNext;
|
||||||
|
return current.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
throw new UnsupportedOperationException(); // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Node {
|
||||||
|
|
||||||
|
private E value;
|
||||||
|
private Node parent;
|
||||||
|
private Node left;
|
||||||
|
private Node right;
|
||||||
|
private int balance;
|
||||||
|
private int size;
|
||||||
|
|
||||||
|
public Node(E value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node add(E value) {
|
||||||
|
// TODO: rebalance
|
||||||
|
int comp = comparator.compare(this.value, value);
|
||||||
|
if(comp == 0) return null;
|
||||||
|
|
||||||
|
if(comp < 0) {
|
||||||
|
if(left == null) {
|
||||||
|
return left = new Node(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return left.add(value);
|
||||||
|
}else {
|
||||||
|
if(right == null) {
|
||||||
|
return right = new Node(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return right.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node remove(E value) {
|
||||||
|
// TODO: rebalance
|
||||||
|
int comp = comparator.compare(value, value);
|
||||||
|
if(comp == 0) return this;
|
||||||
|
|
||||||
|
if(comp < 0) {
|
||||||
|
if(left == null) return null;
|
||||||
|
|
||||||
|
Node removed = left.remove(value);
|
||||||
|
if(removed == left) left = null;
|
||||||
|
return removed;
|
||||||
|
}else {
|
||||||
|
if(right == null) return null;
|
||||||
|
|
||||||
|
Node removed = right.remove(value);
|
||||||
|
if(removed == right) right = null;
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node leftmostChild() {
|
||||||
|
if(left == null) return this;
|
||||||
|
return left.leftmostChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,38 +1,36 @@
|
|||||||
package me.mrletsplay.shareclientcore;
|
package me.mrletsplay.shareclientcore;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.ValueSource;
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
|
||||||
import me.mrletsplay.shareclientcore.document.ArrayCharBag;
|
import me.mrletsplay.shareclientcore.document.ArrayCharBag;
|
||||||
|
import me.mrletsplay.shareclientcore.document.BinaryTreeCharBag;
|
||||||
import me.mrletsplay.shareclientcore.document.Char;
|
import me.mrletsplay.shareclientcore.document.Char;
|
||||||
import me.mrletsplay.shareclientcore.document.CharBag;
|
import me.mrletsplay.shareclientcore.document.CharBag;
|
||||||
import me.mrletsplay.shareclientcore.document.Identifier;
|
import me.mrletsplay.shareclientcore.document.Identifier;
|
||||||
|
|
||||||
public class CharBagTest {
|
public class CharBagTest {
|
||||||
|
|
||||||
private CharBag createBag(Class<? extends CharBag> bagClass) {
|
private static List<CharBag> getBags() {
|
||||||
return assertDoesNotThrow(() -> bagClass.getDeclaredConstructor().newInstance());
|
return List.of(new ArrayCharBag(), new BinaryTreeCharBag());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@ValueSource(classes = { ArrayCharBag.class })
|
@MethodSource("getBags")
|
||||||
public void testCharBagAdd(Class<? extends CharBag> bagClass) {
|
public void testCharBagAdd(CharBag bag) {
|
||||||
CharBag bag = createBag(bagClass);
|
|
||||||
Char c = new Char(new Identifier[] { new Identifier(0, 0) }, 0, (byte) 0);
|
Char c = new Char(new Identifier[] { new Identifier(0, 0) }, 0, (byte) 0);
|
||||||
assertEquals(0, bag.add(c));
|
assertEquals(0, bag.add(c));
|
||||||
assertEquals(List.of(c), bag.toList());
|
assertEquals(List.of(c), bag.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@ValueSource(classes = { ArrayCharBag.class })
|
@MethodSource("getBags")
|
||||||
public void testCharBagAddBetween(Class<? extends CharBag> bagClass) {
|
public void testCharBagAddBetween(CharBag bag) {
|
||||||
CharBag bag = createBag(bagClass);
|
|
||||||
Char c = new Char(new Identifier[] { new Identifier(0, 0) }, 0, (byte) 0);
|
Char c = new Char(new Identifier[] { new Identifier(0, 0) }, 0, (byte) 0);
|
||||||
Char c2 = new Char(new Identifier[] { new Identifier(1, 0) }, 1, (byte) 0);
|
Char c2 = new Char(new Identifier[] { new Identifier(1, 0) }, 1, (byte) 0);
|
||||||
Char cBetween = new Char(new Identifier[] { new Identifier(0, 1) }, 2, (byte) 0);
|
Char cBetween = new Char(new Identifier[] { new Identifier(0, 1) }, 2, (byte) 0);
|
||||||
@ -48,9 +46,8 @@ public class CharBagTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@ValueSource(classes = { ArrayCharBag.class })
|
@MethodSource("getBags")
|
||||||
public void testCharBagRemove(Class<? extends CharBag> bagClass) {
|
public void testCharBagRemove(CharBag bag) {
|
||||||
CharBag bag = createBag(bagClass);
|
|
||||||
Char c = new Char(new Identifier[] { new Identifier(0, 0) }, 0, (byte) 0);
|
Char c = new Char(new Identifier[] { new Identifier(0, 0) }, 0, (byte) 0);
|
||||||
bag.add(c);
|
bag.add(c);
|
||||||
assertEquals(0, bag.remove(c));
|
assertEquals(0, bag.remove(c));
|
||||||
@ -58,9 +55,8 @@ public class CharBagTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@ValueSource(classes = { ArrayCharBag.class })
|
@MethodSource("getBags")
|
||||||
public void testCharBagGet(Class<? extends CharBag> bagClass) {
|
public void testCharBagGet(CharBag bag) {
|
||||||
CharBag bag = createBag(bagClass);
|
|
||||||
Char c = new Char(new Identifier[] { new Identifier(0, 0) }, 0, (byte) 0);
|
Char c = new Char(new Identifier[] { new Identifier(0, 0) }, 0, (byte) 0);
|
||||||
Char c2 = new Char(new Identifier[] { new Identifier(0, 1) }, 2, (byte) 0);
|
Char c2 = new Char(new Identifier[] { new Identifier(0, 1) }, 2, (byte) 0);
|
||||||
Char c3 = new Char(new Identifier[] { new Identifier(1, 0) }, 1, (byte) 0);
|
Char c3 = new Char(new Identifier[] { new Identifier(1, 0) }, 1, (byte) 0);
|
||||||
@ -74,9 +70,8 @@ public class CharBagTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@ValueSource(classes = { ArrayCharBag.class })
|
@MethodSource("getBags")
|
||||||
public void testCharBagClear(Class<? extends CharBag> bagClass) {
|
public void testCharBagClear(CharBag bag) {
|
||||||
CharBag bag = createBag(bagClass);
|
|
||||||
Char c = new Char(new Identifier[] { new Identifier(0, 0) }, 0, (byte) 0);
|
Char c = new Char(new Identifier[] { new Identifier(0, 0) }, 0, (byte) 0);
|
||||||
Char c2 = new Char(new Identifier[] { new Identifier(0, 1) }, 2, (byte) 0);
|
Char c2 = new Char(new Identifier[] { new Identifier(0, 1) }, 2, (byte) 0);
|
||||||
Char c3 = new Char(new Identifier[] { new Identifier(1, 0) }, 1, (byte) 0);
|
Char c3 = new Char(new Identifier[] { new Identifier(1, 0) }, 1, (byte) 0);
|
||||||
|
Loading…
Reference in New Issue
Block a user