是的,您可以在开头插入和在结尾插入一样有效。您只需要在中间而不是索引 0 处开始填充后备数组。为此,您不需要任何不同的 System.arraycopy,请参见下面的示例代码。
不仅存储后备数组 ( data
) 和 current size
,还存储当前start
偏移量,并相应地考虑它。
BetterArrayList<T> extends AbstractList<T> {
private int size; // Used elements in data.
private int start; // Position of element 0 in data.
private T[] data; // data.length is the current total capacity.
public BetterArrayList<T>(int initialCapacity) {
data = new Object[initialCapacity];
start = initialCapacity / 2;
size = 0;
}
public void add(int index, T value) {
if (index < size / 2) { // Insert at the front or end?
if (start == 0) {
realloc(data.length * 2);
}
System.arraycopy(data, start, data, start - 1, index);
start--;
} else {
if (size + start == data.length) {
realloc(data.length * 2);
}
System.arraycopy(data, start + index,
data, start + index + 1, size - index);
}
data[start + index] = value;
size++;
}
public T get(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException();
}
return data[start + index];
}
private void realloc(int newCapacity) {
T[] newData = new Object[newCapacity];
int newStart = newCapacity - size / 2;
System.arraycopy(data, start, newData, newStart, size);
start = newStart;
data = newData;
}
public T set(int index, T value) {
Value old = get(index);
data[size + index] = value;
return old;
}
public int size() {
return size;
}
}
我猜 Sun 没有走这条路,因为它在数组列表的典型用例中浪费了更多内存(在末尾追加)。而且您只会在前面获得更有效的插入,在其他任何地方插入仍然是 O(n) 因为内容仍然需要移动。
顺便说一句:取决于您的用例,但您可能对 Rope 数据结构感兴趣:http ://en.wikipedia.org/wiki/Rope_%28data_structure%29