以最快的方式从一组int中删除子数组?

时间:2012-11-11 20:28:16

标签: java arrays

在Java中,我们有一个数组int[] a = new int[10000000];完全用任意数字填充。我们需要在代码中删除任意子序列:这是一组可能不连续的元素。

使用int[]超过LinkedList的原因是在传递元素时获得了速度提升。目前没有元素的删除,因此在运行应用程序时存储了大量垃圾。删除元素可能会加快速度,这是一个非常有趣的问题。

如何以最快的方式从数组中删除子序列?

2 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分: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;

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