de.tum.in.naturals.set.IntArraySortedSet Maven / Gradle / Ivy
Show all versions of naturals-util Show documentation
/*
* Copyright (C) 2017 Tobias Meggendorfer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package de.tum.in.naturals.set;
import it.unimi.dsi.fastutil.ints.AbstractIntSet;
import it.unimi.dsi.fastutil.ints.IntArrays;
import it.unimi.dsi.fastutil.ints.IntCollection;
import it.unimi.dsi.fastutil.ints.IntIterator;
import java.util.Arrays;
import java.util.Collection;
import java.util.NoSuchElementException;
/**
* A int set which uses a sorted array as backing data structure. This gives excellent lookup
* complexity of {@code O(log n)}, but very costly worst case insertion time of {@code O(n)}.
*/
public class IntArraySortedSet extends AbstractIntSet {
/**
* The backing array (valid up to {@link #size}, excluded).
*/
private int[] array;
/**
* The number of valid entries in {@link #array}.
*/
private int size = 0;
/**
* Creates a new empty array set.
*/
public IntArraySortedSet() {
this.array = IntArrays.EMPTY_ARRAY;
}
/**
* Creates a new empty array set of given initial capacity.
*
* @param capacity
* the initial capacity.
*/
public IntArraySortedSet(int capacity) {
this.array = new int[capacity];
}
/**
* Creates a new array set copying the contents of a given collection.
*
* @param c
* a collection.
*/
@SuppressWarnings("OverridableMethodCallDuringObjectConstruction")
public IntArraySortedSet(IntCollection c) {
this(c.size());
addAll(c);
}
/**
* Creates a new array set copying the contents of a given set.
*
* @param c
* a collection.
*/
@SuppressWarnings("OverridableMethodCallDuringObjectConstruction")
public IntArraySortedSet(Collection c) {
this(c.size());
addAll(c);
}
/**
* Creates a new array set using the given backing array and the given number of elements of the
* array.
*
* It is responsibility of the caller that the first {@code size} elements of {@code a} are
* distinct and sorted.
*
* @param array
* the backing array.
* @param size
* the number of valid elements in {@code a}.
*/
@SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType")
public IntArraySortedSet(int[] array, int size) {
if (size > array.length) {
throw new IllegalArgumentException(String.format("Size %d larger than array %d", size, array.length));
}
assert isSortedUnique(array, size);
this.array = array;
this.size = size;
}
/**
* Creates a new array set using the given backing array. The resulting set will have as many
* elements as the array.
*
*
It is responsibility of the caller that the elements of {@code a} are distinct and sorted.
*
* @param array
* the backing array.
*/
@SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType")
public IntArraySortedSet(int[] array) {
assert isSortedUnique(array, array.length);
this.array = array;
size = array.length;
}
private static boolean isSortedUnique(int[] array, int size) {
assert size <= array.length;
if (array.length <= 1) {
return true;
}
int val = array[0];
for (int i = 1; i < size; i++) {
int next = array[i];
if (next <= val) {
return false;
}
val = next;
}
return true;
}
@Override
public boolean add(int k) {
if (array.length == 0) {
array = new int[] {k, 0};
size = 1;
return true;
}
int index = keyIndex(k);
if (index >= 0) {
return false;
}
int insertionPoint = -(index + 1);
int tailLength = size - insertionPoint;
if (size == array.length) {
int newSize = size * 2;
if (insertionPoint == size) {
array = Arrays.copyOf(array, newSize);
array[insertionPoint] = k;
} else {
int[] newArray = new int[newSize];
System.arraycopy(array, 0, newArray, 0, insertionPoint);
System.arraycopy(array, insertionPoint, newArray, insertionPoint + 1, tailLength);
array = newArray;
newArray[insertionPoint] = k;
}
} else if (insertionPoint == size) {
array[size] = k;
} else {
System.arraycopy(array, insertionPoint, array, insertionPoint + 1, tailLength);
array[insertionPoint] = k;
}
size++;
return true;
}
@Override
public void clear() {
size = 0;
}
/**
* Returns a deep copy of this set.
*/
@Override
public IntArraySortedSet clone() throws CloneNotSupportedException {
IntArraySortedSet clone = (IntArraySortedSet) super.clone();
clone.array = array.clone();
return clone;
}
@Override
public boolean contains(int k) {
return keyIndex(k) >= 0;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public IntIterator iterator() {
return new Iterator(this);
}
private int keyIndex(int key) {
return Arrays.binarySearch(array, 0, size, key);
}
@Override
public boolean remove(int k) {
int index = keyIndex(k);
if (index < 0) {
return false;
}
removeIndex(index);
return true;
}
private void removeIndex(int index) {
assert index >= 0;
int nextIndex = index + 1;
if (nextIndex < size) {
int tail = size - nextIndex;
assert tail > 0;
System.arraycopy(array, nextIndex, array, index, tail);
}
size--;
}
@Override
public int size() {
return size;
}
public void trim() {
if (array.length == size) {
return;
}
array = Arrays.copyOf(array, size);
}
private static class Iterator implements IntIterator {
private final IntArraySortedSet set;
private int next = 0;
private boolean removed = false;
Iterator(IntArraySortedSet set) {
this.set = set;
}
@Override
public boolean hasNext() {
return next < set.size;
}
@Override
public int nextInt() {
if (!hasNext()) {
throw new NoSuchElementException();
}
int result = set.array[next];
removed = false;
next += 1;
return result;
}
@Override
public void remove() {
if (removed || next == 0) {
throw new IllegalStateException();
}
next -= 1;
removed = true;
set.removeIndex(next);
}
}
}