我正在尝试创建一个名为insertAt的方法,该方法需要3个参数(int索引,int n,int值),以便在调用时: 在[12,42,8,8,934]数组上的list.insertAt(2,4,98),它现在应该存储[12,42,98,98,98,98,8,934]。
int索引是我开始放置值的地方
int n是多少个值
int值是我要输入的实际值或数字。
我正在一个名为ArrayIntList的类中使用此方法:
public class ArrayIntList {
private int[] elementData; // list of integers
private int size; // current # of elements in the list
}
我尝试过使用下面的方法,但是我仍然坚持我所缺少的东西。如果你们能帮助我,我将不胜感激!
public void insertAt(int index, int n, int value) {
if (index < 0 || index > size || n < 0) {
throw new IllegalArgumentException();
}
size = size + n;
for (int i = 0; i < n; i++) {
elementData[(size - 1) - i] = elementData[(size - n) + i];
elementData[n + i] = value;
}
}
答案 0 :(得分:4)
示例中的数组仅包含4个值,但是您尝试添加4个附加值。这是不可能的,因为数组具有固定的长度。因此,您必须创建一个长度为size + n
的新数组:
int[] newElements = new int[size + n];
然后,您必须将所有从0
到index
的元素和index
直到size
的元素从旧复制到新数组:
System.arraycopy(elementData, 0, newElements, 0, index);
System.arraycopy(elementData, index, newElements, index + n, size - index);
然后,您必须将新元素n
次插入数组:
Arrays.fill(newElements, index, index + n, value);
最后,您必须将新数组重新分配给旧实例之一并设置新大小:
elementData = newElements;
size += n;
我从JDK使用了一些辅助方法,例如System.arraycopy
,它具有以下签名:
void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
它将元素从src
到srcPos
到srcPos+length
到dest
到destPos
的{{1}}复制
destPost+length
还是一个不错的帮手,带有以下签名:
Array.fill
它使用值void fill(int[] a, int fromIndex, int toIndex, int val)
将数组a
从fromIndex
填充到toIndex
答案 1 :(得分:2)
Answer by Lino是正确的。此外,对于这种工作,您可能应该使用除简单数组以外的其他数据结构。
如果需要更大的灵活性,请使用Java Collections framework。
List
List
接口按顺序跟踪元素。
Java集合仅存储对象,而不存储基元。因此,我们必须使用包装器类。在您的情况下,请使用Integer
而不是int
。在大多数情况下,Java的自动装箱功能将处理
ArrayList
List
的一种实现是ArrayList
。此类由一个简单的数组支持。因此,将中间插入会产生Lino所描述的rigamarole。但是,至少该类正在执行该工作,并且与您或我正在编写的代码不同,这些代码已经过全面测试。
List< Integer > integers = new ArrayList<>() ;
integers.add( 7 ) ; // Add first element to the empty list.
integers.add( 42 ) ; // Append to the end of the list.
integers.add( 1 , Integer.valueOf( 1999 ) ) ; // Insert in the middle. Using zero-based index counting. So `1` means the second item.
integers.
或者在实践中,我将使用序数2,并将索引号减去1。
integers.add( 2-1 , Integer.valueOf( 1999 ) ) ; // Insert. Do math to convert from ordinal number (2, the second position) to index number (1).
LinkedList
⬅快得多!更好的方法是使用实现List
的{{3}}类。如果数组在内存中将项目连续地打包在一起,则LinkedList
的项目分别在内存中浮动,每个项目都跟踪连续项目的存储位置。
因此,插入中间的费用便宜很多:只需更改前一个项目,使其指向新项目,而新项目则指向后续项目。无需重建列表或四处移动物品。
通过调用linked list插入LinkedList
,其中索引是从零开始的位置计数器,而element是您要插入的对象。
请注意List
上的LinkedList::add( index , element)
方法。您生成多个数字的方法可以产生一个列表,然后将该列表插入目标列表。使用这种单插入方法比多次插入要快得多,因为将链接列表遍历到 find 会花费很多。
// Make a list of values to be inserted into the main list.
int count = 3 ;
List< Integer > inserts = new ArrayList<>( count );
for (int i = 0; i < count; i++) {
inserts.add( 98 ) ;
}
// Insert into main list.
integers.add( 2-1 , inserts ) ; // Do math to convert from ordinal number (2, the second position) to index number (1).
如何选择哪个List
:
ArrayList
。由于元素是连续的,因此按位置跳转非常便宜。LinkedList
。由于这些元素是先后绑定在一起的,因此插入/删除仅影响一个元素,因此非常便宜。还有许多其他List
可用的实现,其中一些实现与Java捆绑在一起,而其他的则可以从第三方获得。通常,ArrayList
和LinkedList
是主要力量,大多数人在大多数工作中都会使用。
答案 2 :(得分:1)
您需要一个数组副本,在索引插入之前复制第一个元素,添加N次新元素并添加最后一个元素
public void insertAt(int index, int n, int value) {
if (index < 0 || index > size || n < 0) {
throw new IllegalArgumentException();
}
size = size + n;
int[] elementDataTemp = new int[elementData.length + n];
// copy first elements
for (int i = 0; i < index; i++) {
elementDataTemp[i] = elementData[i];
}
// add new elements
for (int i = 0; i < n; i++) {
elementDataTemp[index + i] = value;
}
// copy last elements
for (int i = index; i < elementData.length; i++) {
elementDataTemp[ n + i ] = elementData[i];
}
// save temp array
elementData = elementDataTemp;
}
答案 3 :(得分:-1)
您可以通过多种方式执行此操作: