removeAll is now O(n+m) if both lists are sorted
This commit is contained in:
@@ -17,6 +17,7 @@ import java.util.stream.StreamSupport;
|
|||||||
*/
|
*/
|
||||||
public final class IntList implements Serializable, Cloneable {
|
public final class IntList implements Serializable, Cloneable {
|
||||||
|
|
||||||
|
// TODO retainAll on sorted lists
|
||||||
// TODO support Iterator
|
// TODO support Iterator
|
||||||
// TODO add mod counts
|
// TODO add mod counts
|
||||||
// TODO support sublists
|
// TODO support sublists
|
||||||
@@ -433,18 +434,43 @@ public final class IntList implements Serializable, Cloneable {
|
|||||||
* This method does not release any memory. Call {@link #trim()} to free unused
|
* This method does not release any memory. Call {@link #trim()} to free unused
|
||||||
* memory.
|
* memory.
|
||||||
* <p>
|
* <p>
|
||||||
* If {@code retain} is sorted, then the algorithm has a complexity of
|
* If both lists are sorted, then the algorithms has time complexity of O(n+m),
|
||||||
* O(n*log(m)), where n is the length of {@code this} and m the length of
|
* where n is the length of {@code this} and m the length of {@code remove}. If
|
||||||
* {@code retain}. If {@code retain} is not sorted, then the complexity is
|
* only {@code remove} is sorted, then the algorithm has a complexity of
|
||||||
* O(n*m).
|
* O(n*log(m)). If {@code remove} is not sorted, then the complexity is O(n*m).
|
||||||
|
* The space complexity is constant in all cases.
|
||||||
*
|
*
|
||||||
* @param remove the elements to remove
|
* @param remove the elements to remove
|
||||||
* @throws NullPointerException if the specified {@link IntList} is null
|
* @throws NullPointerException if the specified {@link IntList} is null
|
||||||
* @see #trim()
|
* @see #trim()
|
||||||
*/
|
*/
|
||||||
public void removeAll(final IntList remove) {
|
public void removeAll(final IntList remove) {
|
||||||
|
|
||||||
|
if (isSorted() && remove.isSorted()) {
|
||||||
|
removeSorted(remove);
|
||||||
|
} else {
|
||||||
removeIf((val, index) -> remove.indexOf(val) >= 0);
|
removeIf((val, index) -> remove.indexOf(val) >= 0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeSorted(final IntList remove) {
|
||||||
|
int posInRemoveList = 0;
|
||||||
|
int insertPosition = 0;
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
final int current = data[i];
|
||||||
|
|
||||||
|
while (posInRemoveList < remove.size() && remove.get(posInRemoveList) < current) {
|
||||||
|
posInRemoveList++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (posInRemoveList >= remove.size() || remove.get(posInRemoveList) != current) {
|
||||||
|
// keep current element
|
||||||
|
data[insertPosition] = current;
|
||||||
|
insertPosition++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
size = insertPosition;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove all elements that match the given predicate.
|
* Remove all elements that match the given predicate.
|
||||||
|
|||||||
@@ -423,18 +423,43 @@ public final class LongList implements Serializable, Cloneable {
|
|||||||
* This method does not release any memory. Call {@link #trim()} to free unused
|
* This method does not release any memory. Call {@link #trim()} to free unused
|
||||||
* memory.
|
* memory.
|
||||||
* <p>
|
* <p>
|
||||||
* If {@code retain} is sorted, then the algorithm has a complexity of
|
* If both lists are sorted, then the algorithms has time complexity of O(n+m),
|
||||||
* O(n*log(m)), where n is the length of {@code this} and m the length of
|
* where n is the length of {@code this} and m the length of {@code remove}. If
|
||||||
* {@code retain}. If {@code retain} is not sorted, then the complexity is
|
* only {@code remove} is sorted, then the algorithm has a complexity of
|
||||||
* O(n*m).
|
* O(n*log(m)). If {@code remove} is not sorted, then the complexity is O(n*m).
|
||||||
|
* The space complexity is constant in all cases.
|
||||||
*
|
*
|
||||||
* @param remove the elements to remove
|
* @param remove the elements to remove
|
||||||
* @throws NullPointerException if the specified {@link LongList} is null
|
* @throws NullPointerException if the specified {@link LongList} is null
|
||||||
* @see #trim()
|
* @see #trim()
|
||||||
*/
|
*/
|
||||||
public void removeAll(final LongList remove) {
|
public void removeAll(final LongList remove) {
|
||||||
|
|
||||||
|
if (isSorted() && remove.isSorted()) {
|
||||||
|
removeSorted(remove);
|
||||||
|
} else {
|
||||||
removeIf((val, index) -> remove.indexOf(val) >= 0);
|
removeIf((val, index) -> remove.indexOf(val) >= 0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeSorted(final LongList remove) {
|
||||||
|
int posInRemoveList = 0;
|
||||||
|
int insertPosition = 0;
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
final long current = data[i];
|
||||||
|
|
||||||
|
while (posInRemoveList < remove.size() && remove.get(posInRemoveList) < current) {
|
||||||
|
posInRemoveList++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (posInRemoveList >= remove.size() || remove.get(posInRemoveList) != current) {
|
||||||
|
// keep current element
|
||||||
|
data[insertPosition] = current;
|
||||||
|
insertPosition++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
size = insertPosition;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove all elements that match the given predicate.
|
* Remove all elements that match the given predicate.
|
||||||
|
|||||||
@@ -1114,6 +1114,28 @@ public class IntListTest {
|
|||||||
Assertions.assertEquals(0, list.size());
|
Assertions.assertEquals(0, list.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveAllFromSortedList() {
|
||||||
|
final IntList list = IntList.of(1, 2, 3, 4, 5);
|
||||||
|
final IntList remove = IntList.of(1, 3);
|
||||||
|
|
||||||
|
list.removeAll(remove);
|
||||||
|
Assertions.assertArrayEquals(new int[] { 2, 4, 5 }, list.toArray());
|
||||||
|
Assertions.assertEquals(3, list.size());
|
||||||
|
Assertions.assertTrue(list.isSorted());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveAllFromSortedList2() {
|
||||||
|
final IntList list = IntList.of(2, 4, 4, 6, 8);
|
||||||
|
final IntList remove = IntList.of(1, 4, 9);
|
||||||
|
|
||||||
|
list.removeAll(remove);
|
||||||
|
Assertions.assertArrayEquals(new int[] { 2, 6, 8 }, list.toArray());
|
||||||
|
Assertions.assertEquals(3, list.size());
|
||||||
|
Assertions.assertTrue(list.isSorted());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRetainAll() {
|
public void testRetainAll() {
|
||||||
final IntList list = IntList.of(-2, -1, 0, 1, 2, 3, 4, 5, 6);
|
final IntList list = IntList.of(-2, -1, 0, 1, 2, 3, 4, 5, 6);
|
||||||
|
|||||||
@@ -1104,6 +1104,28 @@ public class LongListTest {
|
|||||||
Assertions.assertEquals(0, list.size());
|
Assertions.assertEquals(0, list.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveAllFromSortedList() {
|
||||||
|
final LongList list = LongList.of(1, 2, 3, 4, 5);
|
||||||
|
final LongList remove = LongList.of(1, 3);
|
||||||
|
|
||||||
|
list.removeAll(remove);
|
||||||
|
Assertions.assertArrayEquals(new long[] { 2, 4, 5 }, list.toArray());
|
||||||
|
Assertions.assertEquals(3, list.size());
|
||||||
|
Assertions.assertTrue(list.isSorted());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveAllFromSortedList2() {
|
||||||
|
final LongList list = LongList.of(2, 4, 4, 6, 8);
|
||||||
|
final LongList remove = LongList.of(1, 4, 9);
|
||||||
|
|
||||||
|
list.removeAll(remove);
|
||||||
|
Assertions.assertArrayEquals(new long[] { 2, 6, 8 }, list.toArray());
|
||||||
|
Assertions.assertEquals(3, list.size());
|
||||||
|
Assertions.assertTrue(list.isSorted());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRetainAll() {
|
public void testRetainAll() {
|
||||||
final LongList list = LongList.of(-2, -1, 0, 1, 2, 3, 4, 5, 6);
|
final LongList list = LongList.of(-2, -1, 0, 1, 2, 3, 4, 5, 6);
|
||||||
|
|||||||
Reference in New Issue
Block a user