Java: Are generic ArrayLists faster than LinkedLists for iteration? - java

For an ArrayList of a particular type, we can find the size of object (of a particular type) in the ArrayList, and directly access the object at any index in O(1). This is because object references are stored in contiguous chunk of memory in ArrayList, and hence by skipping object_size * index memory locations, we access the memory location where the reference of desired object is residing.
Whereas, in LinkedList, we would have to iterate through each object till we reach the desired object.
For a generic ArrayList, containing different types of objects (with varying sizes), is get(index i) done in O(1)? If so, how?

You working under a misconception. Objects are not stored in arrays, only references (i.e. pointers) to objects are stored in the array. Objects themselves are on the heap. Therefore finding a specific object in an ArrayList by index will always be O(1) regardless of what it contains, and a LinkedList will be O(n).

Not directly an answer to your question, but it might be useful to consider the Apache commons-collection: FastArrayList
Giving it an initial capacity:
List<Integer> listOfLength = new FastArrayList(256);
for (String block : arrayOfBlocks) {
listOfLength.add(block.length());
}

Related

Space complexity of adding n nodes of a tree / graph in an ArrayList or Map

Suppose we have a binary tree where we have
class node {
int data;
node left;
node right;
}
Now suppose I create an ArrayList<node> and add all n nodes in it, will it be in constant space complexity or in n?
My confusion was, since node is not a primitive data structure but an object, it must use CALL BY REFERENCE, hence it should not be using extra space as changing some data in a class instance of node, makes the change in the ArrayList<> as well.
Also, I presumed ArrayList<type> abc = xyz; //another arraylist of same type uses CALL BY REFERENCE hence it uses constant space, but ArrayList<type> abc = new ArrayList<>(xyz) creates a new instance hence it should be using extra space.
Now, when I am adding class instances in ArrayList<node> I do have to initialize the array list with new keyword, ArrayList<node> abc = new ArrayList<>(); before I add instances to the list. So it should use extra space but since we are using class instances which were already defined in the tree and any changes in the tree would reflect on the list as well, hence it should be using constant space. Which of the above is correct and where am I wrong?
EDIT : I understand that even references will take up some space, but would it not be much less than the actual memory space taken by objects originally?
node is not a primitive data structure but an object
There is no object variables/fields in Java. Only primitive and reference variable.
it must use CALL BY REFERENCE
Java is call by value only. Primitives are passed by value and references are passed by value.
when I am adding class instances in ArrayList
This is not supported in Java. You can only add references.
So it should use extra space
Only the references added use extra space. The objects are not copied.
The space complexity will of course be a function of n and not constant. This is because even though the ArrayList only contains references to the tree objects, those references themselves take up space (I'm not a JVM expert so I'm not sure the exact amount, but it's just a few bytes). Of course the space taken up by the reference will be significantly smaller than that taken up by the object itself, but it still takes up space.
EDIT:
To be clear, if you are asking whether the ArrayList takes up less space than the objects themselves, then yes it does, but that is not what space complexity means. Space complexity is not about how much space is required to store data, its about how that space requirement multiplies as the data grows. When I say space complexity is O(n) or linear, I mean that the ArrayList size increases proportionally with the number of objects. Twice as many objects make the ArrayList twice the size, five times as many makes the ArrayList five times as large, and so on. Constant or O(1) complexity means that, even if you might need extra space, the amount of space you need stays the same and does not increase as you add items.
I believe what you are really asking is "Will adding an ArrayList double my space requirements, or will it require no extra space?" and my answer to both is no. It will not double the space requirements, because it only uses references, but it will require some extra space to store those references. That has nothing to do with space complexity.
TLDR: Space requirements ≠ Space complexity.

Instantiating an ArrayList of ArrayLists

I want to instantiate an ArrayList of ArrayLists (of a generic type). I have this code:
private ArrayList<ArrayList<GameObject>> toDoFlags;
toDoFlags = new ArrayList<ArrayList<GameObject>>(2);
Am I doing this right? It compiles, but when I look at the ArrayList, it has a size of 0.
You're doing it right. The reason it has zero length is because you haven't added anything to it yet.
The "2" you pass is the initial capacity of the array that backs the ArrayList. But the size() method of the ArrayList doesn't return the initial capacity of its backing array... it returns the number of actual elements in the list.
Customarily, you shouldn't be using the initialCapacity parameter. It's a performance optimization when you have large ArrayLists. By allocating a lot of space explicitly, you save the time it would take to re-allocate as you add more and more items to the list. But in this case you probably don't have an extremely large list.
Also, instead of using an ArrayList of ArrayLists, you should consider writing a class to store your data.
ArrayLists expand as you add to them. The integer capacity argument just sets the initial size of the backing array. Setting the capacity to two doesn't mean that there are two elements in the ArrayList, but rather that two elements can be added to the ArrayList before it has to declare a larger internal array.

Can array of int pointers in C++ be done as ArrayList of Integer references in Java?

I have an array int[] A = new int[100000] in Java and I want to create millions of subarrays of A. In C++ I would use arrays of pointers. Can I create ArrayList<Integer> subA and store references to elements of A such that I will not consume too much memory.
Right at the moment, I do create int[] subA = new int[some value less than A.length] objects which is very expensive and goes out of memory.
List.subList() does that : it creates a view over the original list. You would probably save memory by using that, since a sublist has only these 4 fields:
reference to the outer list
offset
size
modCount
Each sublist would thus consume something like 20 bytes.
Java has no concept of pointers, therefore you cannot use a list of Integers to refer to other objects, but what you can do is this:
List<List<Integer>> l = new ArrayList<List<Integer>>();
l.add(new ArrayList<Integer>()) // add a list which will hold integers as a reference in your main list.
If you're running out of memory, you need to allocate more heap memory to the JVM. Read up on the -Xmx startup parameters you can pass to the JVM.

java linkedlist slower than arraylist when adding elements?

i thought linkedlists were supposed to be faster than an arraylist when adding elements? i just did a test of how long it takes to add, sort, and search for elements (arraylist vs linkedlist vs hashset). i was just using the java.util classes for arraylist and linkedlist...using both of the add(object) methods available to each class.
arraylist out performed linkedlist in filling the list...and in a linear search of the list.
is this right? did i do something wrong in the implementation maybe?
***************EDIT*****************
i just want to make sure i'm using these things right. here's what i'm doing:
public class LinkedListTest {
private List<String> Names;
public LinkedListTest(){
Names = new LinkedList<String>();
}
Then I just using linkedlist methods ie "Names.add(strings)". And when I tested arraylists, it's nearly identical:
public class ArrayListTest {
private List<String> Names;
public ArrayListTest(){
Names = new ArrayList<String>();
}
Am I doing it right?
Yes, that's right. LinkedList will have to do a memory allocation on each insertion, while ArrayList is permitted to do fewer of them, giving it amortized O(1) insertion. Memory allocation looks cheap, but may be actually be very expensive.
The linear search time is likely slower in LinkedList due to locality of reference: the ArrayList elements are closer together, so there are fewer cache misses.
When you plan to insert only at the end of a List, ArrayList is the implementation of choice.
Remember that:
there's a difference in "raw" performance for a given number of elements, and in how different structures scale;
different structures perform differently at different operations, and that's essentially part of what you need to take into account in choosing which structure to use.
So, for example, a linked list has more to do in adding to the end, because it has an additional object to allocate and initialise per item added, but whatever that "intrinsic" cost per item, both structures will have O(1) performance for adding to the end of the list, i.e. have an effectively "constant" time per addition whatever the size of the list, but that constant will be different between ArrayList vs LinkedList and likely to be greater for the latter.
On the other hand, a linked list has constant time for adding to the beginning of the list, whereas in the case of an ArrayList, the elements must be "shuftied" along, an operation that takes some time proportional to the number of elements. But, for a given list size, say, 100 elements, it may still be quicker to "shufty" 100 elements than it is to allocate and initialise a single placeholder object of the linked list (but by the time you get to, say, a thousand or a million objects or whatever the threshold is, it won't be).
So in your testing, you probably want to consider both the "raw" time of the operations at a given size and how these operations scale as the list size grows.
Why did you think LinkedList would be faster? In the general case, an insert into an array list is simply a case of updating the pointer for a single array cell (with O(1) random access). The LinkedList insert is also random access, but must allocate an "cell" object to hold the entry, and update a pair of pointers, as well as ultimately setting the reference to the object being inserted.
Of course, periodically the ArrayList's backing array may need to be resized (which won't be the case if it was chosen with a large enough initial capacity), but since the array grows exponentially the amortized cost will be low, and is bounded by O(lg n) complexity.
Simply put - inserts into array lists are much simpler and therefore much faster overall.
Linked list may be slower than array list in these cases for a few reasons. If you are inserting into the end of the list, it is likely that the array list has this space already allocated. The underlying array is usually increased in large chunks, because this is a very time-consuming process. So, in most cases, to add an element in the back requires only sticking in a reference, whereas the linked list needs the creation of a node. Adding in the front and the middle should give different performance in for both types of list.
Linear traversal of the list will always be faster in an array based list because it must only traverse the array normally. This requires one dereferencing operation per cell. In the linked list, the nodes of the list must also be dereferenced, taking double the amount of time.
When adding an element to the back of a LinkedList (in Java LinkedList is actually a doubly linked list) it is an O(1) operation as is adding an element to the front of it. Adding an element on the ith position is roughly an O(i) operation.
So, if you were adding to the front of the list, a LinkedList would be significantly faster.
ArrayList is faster in accessing random index data, but slower when inserting elements in the middle of the list, because using linked list you just have to change reference values. But in an array list you have to copy all elements after the inserted index, one index behind.
EDIT: Is not there a linkedlist implementation which keeps the last element in mind? Doing it this way would speed up inserting at the end using linked list.

Storing & lookup double array

I have a fairly expensive array calculation (SpectralResponse) which I like to keep to a minimum. I figured the best way is to store them and bring it back up when same array is needed again in the future. The decision is made using BasicParameters.
So right now, I use a LinkedList of object for the arrays of SpectralResponse, and another LinkedList for the BasicParameter. And the BasicParameters has a isParamsEqualTo(BasicParameters) method to compare the parameter set.
LinkedList<SpectralResponse> responses
LinkedList<BasicParameters> fitParams
LinkedList<Integer> responseNumbers
So to look up, I just go through the list of BasicParameters, check for match, if matched, return the SpectralResponse. If no match, then calculate the SpectralResponse.
Here's is the for loop I used to lookup.
size: LinkedList size, limited to a reasonable value
responseNumber: just another variable to distinguish the SpectralResponse.
for ( i = size-1; i > 0 ; i--) {
if (responseNumbers.get(i) == responseNum)
{
tempFit = fitParams.get(i);
if (tempFit.isParamsEqualTo(fit))
{
return responses.get(i);
}
}
}
But somehow, doing it this way no only take out lots of memory, it's actually slower than just calculating SpectralResponse straight. Much slower.
So it is my implementation that's wrong, or I was mistaken that precalculating and lookup is faster?
You are accessing a LinkedList by index, this is the worst possible way to access it ;)
You should use ArrayList instead, or use iterators for all your lists.
Possibly you should merge the three objects into one, and keep them in a map with responseNum as key.
Hope this helps!
You probably should use an array type (an actual array, like Vector, ArrayList), not Linked lists. Linked lists is best for stack or queue operation, not indexing (since you have to traverse it from one end). Vector is a auto resizing array, wich has less overhead in accessing inexes.
The get(i) methods of LinkedList require that to fetch each item it has to go further and further along the list. Consider using an ArrayList, the iterator() method, or just an array.
The second line, 'if (responseNumbers.get(i) == responseNum)' will also be inefficient as the responseNumbers.get(i) is an Integer, and has to be unboxed to an int (Java 5 onwards does this automatically; your code would not compile on Java 1.4 or earlier if responseNum is declared as an an int). See this for more information on boxing.
To remove this unboxing overhead, use an IntList from the apache primitives library. This library contains collections that store the underlying objects (ints in your case) as a primitive array (e.g. int[]) instead of an Object array. This means no boxing is required as the IntList's methods return primitive types, not Integers.

Categories

Resources