removeAll is now O(n+m) if both lists are sorted

This commit is contained in:
2018-11-20 19:53:33 +01:00
parent 430b4c50ca
commit ee04f21f29
4 changed files with 105 additions and 10 deletions

View File

@@ -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,17 +434,42 @@ 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) {
removeIf((val, index) -> remove.indexOf(val) >= 0);
if (isSorted() && remove.isSorted()) {
removeSorted(remove);
} else {
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;
} }
/** /**

View File

@@ -423,17 +423,42 @@ 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) {
removeIf((val, index) -> remove.indexOf(val) >= 0);
if (isSorted() && remove.isSorted()) {
removeSorted(remove);
} else {
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;
} }
/** /**

View File

@@ -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);

View File

@@ -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);