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;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
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.BinaryTreeCharBag;
|
||||
import me.mrletsplay.shareclientcore.document.Char;
|
||||
import me.mrletsplay.shareclientcore.document.CharBag;
|
||||
import me.mrletsplay.shareclientcore.document.Identifier;
|
||||
|
||||
public class CharBagTest {
|
||||
|
||||
private CharBag createBag(Class<? extends CharBag> bagClass) {
|
||||
return assertDoesNotThrow(() -> bagClass.getDeclaredConstructor().newInstance());
|
||||
private static List<CharBag> getBags() {
|
||||
return List.of(new ArrayCharBag(), new BinaryTreeCharBag());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(classes = { ArrayCharBag.class })
|
||||
public void testCharBagAdd(Class<? extends CharBag> bagClass) {
|
||||
CharBag bag = createBag(bagClass);
|
||||
@MethodSource("getBags")
|
||||
public void testCharBagAdd(CharBag bag) {
|
||||
Char c = new Char(new Identifier[] { new Identifier(0, 0) }, 0, (byte) 0);
|
||||
assertEquals(0, bag.add(c));
|
||||
assertEquals(List.of(c), bag.toList());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(classes = { ArrayCharBag.class })
|
||||
public void testCharBagAddBetween(Class<? extends CharBag> bagClass) {
|
||||
CharBag bag = createBag(bagClass);
|
||||
@MethodSource("getBags")
|
||||
public void testCharBagAddBetween(CharBag bag) {
|
||||
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 cBetween = new Char(new Identifier[] { new Identifier(0, 1) }, 2, (byte) 0);
|
||||
@ -48,9 +46,8 @@ public class CharBagTest {
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(classes = { ArrayCharBag.class })
|
||||
public void testCharBagRemove(Class<? extends CharBag> bagClass) {
|
||||
CharBag bag = createBag(bagClass);
|
||||
@MethodSource("getBags")
|
||||
public void testCharBagRemove(CharBag bag) {
|
||||
Char c = new Char(new Identifier[] { new Identifier(0, 0) }, 0, (byte) 0);
|
||||
bag.add(c);
|
||||
assertEquals(0, bag.remove(c));
|
||||
@ -58,9 +55,8 @@ public class CharBagTest {
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(classes = { ArrayCharBag.class })
|
||||
public void testCharBagGet(Class<? extends CharBag> bagClass) {
|
||||
CharBag bag = createBag(bagClass);
|
||||
@MethodSource("getBags")
|
||||
public void testCharBagGet(CharBag bag) {
|
||||
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 c3 = new Char(new Identifier[] { new Identifier(1, 0) }, 1, (byte) 0);
|
||||
@ -74,9 +70,8 @@ public class CharBagTest {
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(classes = { ArrayCharBag.class })
|
||||
public void testCharBagClear(Class<? extends CharBag> bagClass) {
|
||||
CharBag bag = createBag(bagClass);
|
||||
@MethodSource("getBags")
|
||||
public void testCharBagClear(CharBag bag) {
|
||||
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 c3 = new Char(new Identifier[] { new Identifier(1, 0) }, 1, (byte) 0);
|
||||
|
Loading…
Reference in New Issue
Block a user