在 Java 中做一个可调整大小的数组的最佳方法是什么?我尝试使用 Vector,但是当你进行插入时,所有元素都会转移,我需要一个可以增长但元素保持原位的数组。我确信对此有一个简单的答案,但我仍然不太确定。
9 回答
作为替代方案,您可以使用ArrayList。它是 List 接口的可调整大小的数组实现。
用法(使用字符串):
List<String> myList = new ArrayList<String>();
myList.add("a");
myList.add("c");
myList.add("b");
顺序就像你把它们放进去一样:a、c、b。
您还可以获得这样的单个项目:
String myString = myList.get(0);
这将为您提供第 0 个元素:“a”。
就像三条指出的那样:“ An array is a static datastructure, so they can't grow
”。列表接口可以由数组支持(例如Kevin 在他的帖子中指出的ArrayList)。当列表结构已满并且必须将新项目添加到列表中时。然后该结构首先创建一个新数组,该数组可以包含旧元素以及必须添加到列表中的新元素。
列表接口有不同的实现,它们都有优点/缺点,你应该选择最能解决你的问题集的一个。下面我将尝试简要总结何时使用哪种实现:
不是线程安全的实现:
- ArrayList : List 接口的 Resizable-array 实现。
size, isEmpty, get, set, iterator, and listIterator
当您在恒定时间内执行大量操作时,您应该使用此实现。该add
操作在摊销常数时间内运行,即添加 n 个元素需要 O(n) 时间。我认为您应该在进行更多查找(get()
)然后将项目添加到列表(add()
)时使用此实现。 - LinkedList:此实现不是由数组备份,而是将节点“链接”在一起。在我看来,当你做更多的时候,你应该使用这个
add()
实现get()
。
线程安全的实现:
请注意,这些列表实现不是线程安全的,这意味着在从多个线程访问它们时可能会出现竞争条件。如果您想使用来自多个线程的 List 实现,我建议您研究java.util.concurrent包并使用该类的实现。
出于其他答案中解释的原因,您可能应该使用 ArrayList 而不是 Vector。
然而 ...
我尝试使用 Vector,但是当你进行插入时,所有元素都会转移,我需要一个可以增长但元素保持原位的数组。
当您执行 时insertElementAt(pos, elem)
,您已明确要求进行元素转换。如果你不希望元素被移动,你应该使用set(pos, elem)
。或者如果你想在向量的末尾添加元素,你也可以使用add(elem)
.
顺便说一句,上一段适用于所有的实现,List
而不仅仅是.Vector
List
我尝试使用 Vector,但是当你进行插入时,所有元素都会转移,我需要一个可以增长但元素保持原位的数组。
您可能想使用 ArrayList 而不是 Vector。
它们都提供了大致相同的接口,您可以通过调用set(idx, element)
. 这不会做任何转移。但是,它也不允许您扩大数组:您只能在已经占用的位置(不能超出数组的当前大小)插入,以便在您必须使用的末尾添加新元素add(element)
。
ArrayList 和 Vector 之间的区别在于 Vector 具有您很可能不需要的同步代码,这使得 ArrayList 更快一些。
ArrayList 和 LinkedList
空间复杂度:
a) ArrayList:在初始化时分配一块内存,并在动态添加元素时每次达到最大大小时加倍。
b) LinkedList:它只在每次将项目添加到列表时分配内存。
运行时复杂性:
a) ArrayList:与链表相比,查找更快,插入和删除更慢
b) LinkedList:相比数组列表,插入和删除更快,搜索更慢
如果要在所有元素都已插入或删除后操作数组数据,有一种方法是尝试创建一个LinkedList或ArrayList,只需调整大小,数据输入完成后,可以将ArrayList转为Array,然后做所有你平时对 Array 做的事情。
数组不能在 Java 中动态调整大小。对此的解决方案是使用 ArrayList 或创建另一个临时数组然后分配它。
您可以找到有关 ArrayList 的教程,但如果您只想在 Java 中自定义 ResizableArray。就是这样。但不建议使用!它只是一个 FAKE 可调整大小的数组,当您创建太多对象时,堆内存会增加。这只是向您展示这个想法。
- 界面
public interface Resizable<T> {
void add(T data);
int delete(int index);
int size();
void print();
}
- 实现类
public class ResizeableImpl<T> implements Resizable<T> {
private Object[] temp = null;
private Object[] originals = new Object[0];
@Override
public void add(T data) {
Object[] temp = new Object[originals.length+1];
for (int i=0; i<originals.length; i++) {
temp[i]=originals[i];
}
temp[originals.length]=data;
originals=temp;
}
@Override
public int delete(int index) {
int success=0;
switch (originals.length) {
case 0: //No Data to delete
success=0;
break;
case 1: //One Data is delete and so no data, too!
originals = new Object[0];
success = 1;
break;
default: //>=2
int count=0;
originals[index]=null;
temp = new Object[originals.length-1];
for (int i=0; i<originals.length; i++) {
if (originals[i]!=null)
temp[count++]=originals[i];
}
originals = temp;
success = 1;
}
return success;
}
@Override
public int size() {
return originals.length;
}
@Override
public void print() {
StringBuilder sb = null;
if (originals.length==0) {
System.out.println("No data available!");
return;
}
for (int i=0; i<originals.length; i++) {
if (sb==null) {
sb = new StringBuilder();
sb.append(originals[i]);
}
else {
sb.append(", "+originals[i]);
}
}
sb.append(".");
System.out.println(sb.toString());
}
}
- 主要方法
public class App {
public static void main(String[] args) {
//Program to interfaces, not implementations
Resizable<Integer> obj = new ResizeableImpl<>();
obj.add(13);
obj.add(20);
obj.add(17);
obj.add(25);
obj.add(100);
obj.add(12);
obj.print();
int result = obj.delete(2); //This will delete 17.
if (result==1) {
System.out.println("Deletion is successful!");
}
obj.print();
obj.delete(3); //This will delete 100.
obj.print();
}
}
输出
13, 20, 17, 25, 100, 12.
Deletion is successful!
13, 20, 25, 100, 12.
13, 20, 25, 12.
使用 ArrayList 或 LinkedList。
在 Collections 框架中使用精彩的类比使用数组更好。但是,如果您的问题是从“测验”的角度提出的,那么您应该这样做。创建您自己的调整大小方法,例如:
int[] oldArray = {1,2,3};
int oldSize = java.lang.reflect.Array.getLength(oldArray);
Class elementType = oldArray.getClass().getComponentType();
Object newArray = java.lang.reflect.Array.newInstance(
elementType,newSize);
int preserveLength = Math.min(oldSize,newSize);
if (preserveLength > 0)
System.arraycopy (oldArray,0,newArray,0,preserveLength);
oldArray = newArray;