0

In Java, we have an array int[] a = new int[10000000]; fully filled in with arbitrary numbers. Quite often in code we need to remove an arbitrary subsequence: that is a set of elements that may be non-contiguous.

The reason to use int[] over LinkedList is a speed gain while passing through elements. Currently there is no removal of elements, so lots of rubbish is stored for the time of running application. Removing elements may give a speed-up, so quite an interesting question.

How to remove a subseqence from an array in a fastest possible way?

4

2 回答 2

2

这取决于您是否要缩短数组,或者是否可以在数组末尾允许未使用的元素。用于此的工具是System.arraycopy. 要缩短数组,您需要分配一个新数组:

public int[] remove(int[] original, removeStart, removeEnd) {
    int originalLen = original.length;
    int[] a = new int[originalLen - removeEnd - removeStart];
    System.arraycopy(original, 0, // from original[0]
        a, 0,                     // to a[0]
        removeStart);             // this many elements
    System.arraycopy(original, removeEnd, // from original[removeEnd]
        a, removeStart,                   // to a[removeStart]
        originalLen - removeEnd);         // this many elements
    return a;
}

要压缩一个数组:

System.arraycopy(array, removeEnd, // from array[removeEnd]
    array, removeStart,            // to array[removeStart]
    array.length - removeEnd);     // this number of elements

您不必担心范围重叠;arraycopy正确处理这些。

如果要删除的元素范围不连续,您可以概括其中一种解决方案(移动的东西更少,但代码更复杂),或者您可以单独删除每个连续块(更易于编程,但您将移动数据你将被丢弃)。

如果您要删除分散的索引,我会手动完成。设计取决于它是分散的单个索引还是范围的集合。使用后者(这是未经测试的,但它应该给你的想法):

/**
 * Simple class to hold the start and end of a range.
 */
public static class Range implements Comparable<Range> {
    int start;
    int end;
    public int compareTo(Range other) {
        if (start < other.start) return -1;
        if (start > other.start) return 1;
        if (end < other.end) return -1;
        if (end > other.end) return 1;
        return 0;
    }
}
/**
 * Remove a list of ranges from an array.
 * @param original the array from which to remove the values.
 * @param toRemove the list of ranges to remove. This must be
 *    sorted in ascending order of range start before calling this method.
 * @param compact flag indicating whether to simply compact the original
 *    array or to copy the values into a new array. If false, will allocate
 *    a new array of the exact size needed to contain the elements not removed.
 */
public int[] remove(int[] original, List<Range> toRemove, boolean compact) {
    int[] a;
    if (compact) {
        a = original;
    } else {
        int len = 0;
        for (Range range : toRemove) len += range.end - range.start;
        a = new int[original.length - len];
    }
    int nextSource = 0;
    int nextDest = 0;
    for (Range range : toRemove) {
        if (nextSource < range.start) {
            System.arraycopy(original, nextSource, a, nextDest,
                range.start - nextSource);
            nextDest += range.start - nextSource;
            nextSource = range.start;
        }
        nextSource = range.end;
    }
    if (nextSource < original.length) {
        System.arraycopy(original, nextSource, a, nextDest,
            original.length - nextSource);
    }
    return a;
}
于 2012-11-11T20:38:22.070 回答
0

使用 [ System#arraycopy ](http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/System.html#arraycopy(java.lang.Object, int, java.lang.Object , int, int)) 如下:

      System.arraycopy(orginalArray, startIndex, newArray, 
                     newArrayStartIndex, numOfElementsToCopy);
      orginalArray = newArray;

请注意:这适用于连续位置。如果有更多的连续部分,这仍然很有帮助,并且可以以类似的方式多次调用。但是如果要删除的位置是完全随机的,那么我相信你需要遍历数组。

于 2012-11-11T20:32:17.113 回答