I\'m not too concerned about time efficiency (the operation will be rare), but rather about memory efficiency: Can I grow the array without temporarily having all th
Is the array itself large, or are you referencing large ReferenceTypes?
There is a difference between an array of a PrimitiveType with billions of elements, and an array with thousands of elements, but they refer to large class instances.
int[] largeArrayWithSmallElements = new int[1000000000000];
myClass[] smallArrayWithLargeElements = new myClass[10000];
Edit:
If you have performance considerations using ArrayList, I can assure you it will perform more or less exactly as Array indexing.
And if the application has limited memory resources, you can try to play around with the initial size of the ArrayList (one of it's constructors).
For optimal memory efficiency, you could create a container class with an ArrayList of Arrays.
Something like:
class DynamicList
{
public long BufferSize;
public long CurrentIndex;
ArrayList al = new ArrayList();
public DynamicList(long bufferSize)
{
BufferSize = bufferSize;
al.add(new long[BufferSize]);
}
public void add(long val)
{
long[] array;
int arrayIndex = (int)(CurrentIndex / BufferSize);
if (arrayIndex > al.size() - 1)
{
array = new long[BufferSize];
al.add(array);
}
else
{
array = (long[])al.get(arrayIndex);
}
array[CurrentIndex % BufferSize] = val;
}
public void removeLast()
{
CurrentIndex--;
}
public long get(long index)
{
long[] array;
int arrayIndex = (int)(index / BufferSize);
if (arrayIndex < al.size())
{
array = (long[])al.get(arrayIndex);
}
else
{
// throw Exception
}
return array[index % BufferSize];
}
}
(my java is rusty, so please bear with me...)
One way of doing this is having a linked list of array nodes. This is somewhat complex but the premise is this:
You have a linked list and each node within the list references an array. This way, your array can grow without ever copying. To grow you only need to add additional nodes at the end. Therefore the 'expensive' grow operation only occurs every M operations where M is the size of each node. Granted, this assumes that you always append to the end and you don't remove.
Insertion and removal in this structure is quite complicated, but if you can avoid them then that's perfect.
The only loss with this structure (ignoring insertion and deletion) is with the gets. The gets will be slightly longer; accessing the correct node requires accessing the correct node within the linked list and then fetching there. If there are a lot of accesses around the middle, this can be slow however there are tricks to speeding linked lists up.
Is there a more efficient way to grow a large array than creating a new one and copying over all the values? Like, concatenating it with a new one?
No. And probably there is no language, that guarantees growing an array will always take place without copying. Once you allocate the space for the array and do something else, you most likely have other objects in memory right after the end of the array. At that point, it's fundamentally impossible to grow the array without copying it.
What about having fixed-size arrays stored in another array and reallocate / copy that top-level one? Would that leave the actual values in place?
You mean have an array of arrays and treat it as one large array consisting of a concatenation of the underlying arrays? Yes, that would work (the "faking it by doing indirection" approach), as in Java, Object[][]
is simply an array of pointers to Object[]
instances.
The best way to have a dynamically resizing 'array' or list of items is to use an ArrayList.
Java has already built in very efficient resizing algorithms into that data structure.
But, if you must resize your own array, it is best to use System.arraycopy()
or Arrays.copyOf()
.
Arrays.copyOf()
can most simply be used like so:
int[] oldArr;
int newArr = Arrays.copyOf(oldArr, oldArr.length * 2);
This will give you a new array with the same elements as the old array, but now with room to spare.
The Arrays class in general has lots of great methods for dealing with arrays.
Also
It is important to make sure that you aren't just growing your array by one element each time an element is added. It is best to implement some strategy where you only have to resize the array every once in a while. Resizing arrays is a costly operation.
Have you looked at GNU Trove for highly efficient java collections? Their collections store primatives directly for much better memory usage.
Have a look at System.arraycopy.