This question already has answers here:
Java: what's the big-O time of declaring an array of size n?
(4 answers)
Closed 3 years ago.
boolean[] arr = new boolean[n];
What is the time complexity of above initialization? Is it O(1) ir O(n)? I think it is O(1) because the program simply asks JVM for a block of memory of size n. How does JVM(hotspot) actually allocate memory in this case?
I have looked up following links so far, however the answer is not clear to me:
Thread-1
Thread-2
I think that in general it is O(n), since the declared array need to be zeroes with default values, in your case with false.
But a VM can also prove that this array is not read immediately, that is someone first writes all the elements to it and only after that, reads them. In such a condition the complexity would be O(1), because you are not really doing anything (no default values are placed inside the array itself) - thus constant.
This, for example, is what happens in java-11 with Collection::toArray sort of, via :
default <T> T[] toArray(IntFunction<T[]> generator) {
return toArray(generator.apply(0));
}
So when you have something like:
List.of(1, 2, 3, 4)
.toArray(x -> new Integer[x]);
The implementation will actually do new Integer[0] and use that coupled with some System.arrayCopy, instead of the inferred new Integer[4]. This is done because the VM can prove that zeroing is not needed, thus skip it entirely.
Related
This question already has answers here:
Performance differences between ArrayList and LinkedList [duplicate]
(11 answers)
When to use LinkedList over ArrayList in Java?
(33 answers)
Closed 1 year ago.
This post was edited and submitted for review 4 months ago and failed to reopen the post:
Original close reason(s) were not resolved
Yesterday I ran a benchmark in Java 17 where I repeatedly created a new Arraylist and Linkedlist and added 10.000.000 Elements to it.
By the nature of a LinkedList adding elements (creating a LinkedObject an putting it at the end) should be much faster than adding to an ArrayList. (Copying whole array in anotherone that is slightly larger.)
Are native functions like arraycopy() really that much faster? The only thing the LinkedList was better at was merging two LinkedLists together.
Most of the time, adding to an ArrayList won't allocate a new array, since the implementation increases the size of the backing array by 50% when it needs to grow.
This may sound wasteful from a memory perspective, but even a worst-case scenario for a growing ArrayList uses less memory than LinkedList - each entry in a linked list costs an object header + 3 references (prev/value/next), whereas a worst-case growing ArrayList has only 1.5 references per entry (i.e., the array cells used, plus 50% which are as-yet unused).
Anywho, according to my calculations, this means that adding 10 million entries to a default-initiated ArrayList will result in some 35 array-copying actions, which isn't very much. (And yes, System.arraycopy is fast.)
Finally, if you give your array an initial capacity of 10_000_000, there will be zero array copies made. You can try that to see how much the copying really costs.
This question already has answers here:
Arrays.asList() not working as it should?
(12 answers)
Java Arrays.asList on primitive array type produces unexpected List type [duplicate]
(2 answers)
Arrays.asList() of an array
(9 answers)
Closed 1 year ago.
I expect that this code prints "0" since the starting size of the array is 0, but what it does is printing "1". Can someone explain me why, using Arrays.asList on an empty collection alter the size of the resulting collection? I know that "asList" gives back a fixed-size array but still I cannot imagine what's the reason behind that.
#Test
public void checkEmptinessTest() {
byte[] arrayOfTest = new byte[0];
System.out.println(Arrays.asList(arrayOfTest).size());
}
I tried to initialize the array with no items like this:
byte[] arrayOfTest = new byte[] = {};
but the result is the same.
Thanks for the help.
Because you've made a list of byte arrays. Not a list of bytes.
In other words, your list contains 1 item: An empty byte array.
You can't easily turn a byte[] into a List<Byte>. There are slightly less trivial ways to do it (just do the obvious thing: Write a for loop), but note that a List<Byte> is about 10x more wasteful than a byte[]. Generally, you don't 'want' a List<Byte>, unless you are really very sure you do. Just about every byte-stream related API takes a byte[], In/OutputStream, or ByteBuffer, and rarely if ever a List<Byte>, for example.
EDIT: To be clear, if the component type is not a primitive, then lists are just as efficient as arrays are, in practice more efficient (because it is cleaner code, and that is the only feasible road to a non-trivially-sized project that performs well). It's just collections-of-primitives that are, and it's the worst, by far, when we're talking about byte[].
NOTE: As the title already hints, this question is not about the specific java.util.ArrayList implementation of an array-based list, but rather about the raw arrays themselves and how they might behave in a "pure" (meaning completely unoptimized) array-based list implementation. I chose to mention java.util.ArrayList because it is the most prominent example of an array-based list in Java, although it is technically not "pure", as it utilizes preallocation to reduce the operation time of add(). If you want to know why I am asking this specific question without being interested in the java.util.ArrayList() preallocation optimization, I added a little explanation of my use case below.
It is generally known that you can access elements in array-based lists (like Java's ArrayList<E>) with a time complexity of O(1), while adding elements to that list will take O(n). With linked lists, it is the other way round (for a doubly linked list, you could optimize the access to half the execution time).
The reason why adding elements to an array-based list takes O(n) is that an array cannot simply be resized, but has to be reallocated and re-filled. The easiest way to do this would be:
String arr[] = new String[n];
//...
String newElem = "foo";
String[] newArr = new String[n + 1];
int i = 0;
for (String elem : arr) {
newArr[i] = arr[i++];
}
newArr[i] = newElem;
arr = newArr;
The time complexity O(n) is clearly visible thanks to the for loop. But there are other ways to copy arrays in Java, for example System.arraycopy().
Sticking to the vanilla for loop solution, even shrinking an array will take O(n), because an array has a fixed size and in order to "shrink" it, you'd have to copy all elements to be retained to a new, smaller array.
So, here are my questions concerning such array operations and their time complexity:
While the vanilla for loop will always take O(n), is it possible that System.arraycopy() optimizes the "add" operation if there is enough space in the memory to expand the array in place, meaning that it would leave the original array at its place and just add the new element at the end of it?
As the shrinking operation could always be executed with O(1) in theory, does System.arraycopy() always optimize this operation to O(1)?
If System.arraycopy() is not capable of using those optimizations, is there any other way in Java to actually utilize those optimizations which are possible in theory OR will array "resizing" always take O(n), no matter under which circumstances?
TL;DR is there any situation in which the "resizing" of an array in Java will take less than O(n)?
Additional information:
I am using openJDK11 (newest release), but if the answer turns out to be JVM-dependent, I'd like to know how other JVMs would behave in comparison.
For the curious ones
who want to know what I want to do with this information:
I am working on a new java.util.List implementation, namely a hybrid list that can store data in an array and in a linked buffer. On certain occasions, the buffer will be flushed into the array, which of course requires that the existing array is resized. But apart from this idea, I want to utilize as many other optimizations on the array part as possible. To avoid array resizing in general, I experimented with the idea of letting the array persist in a constant size, but managing the "valid" range of it with some other fields. Meaning that if you were to pop the last element of the array, it would not shrink the array but rather the range of valid elements. Then, when inserting new elements in the array part, the former invalid section can be used to shift values into, basically reusing the space that was formerly used by a now deleted element. If the inserting operations exceed the actual array size, elements can still be transferred to the linked buffer to avoid resizing. To further optimize this, I chose to use the middle of the array as a pivot when deleting certain elements. Now the valid range might not start at the beginning of the array anymore. Basically this means if you delete an element to the left of the pivot, all elements between the start of the valid range and the deleted element get shifted towards the pivot, to the right. Removing element to the right of the pivot works accordingly. So, after some removals, the array could look like this:
[null null|elem0 elem1 elem2||elem3 elem4 elem5|null null null]
(Where the | at the beginning and at the end mark the valid range and the || marks the pivot)
So, how is this all related to my question?
All of those optimizations build up upon the claim that array resizing is expensive in time, namely O(n). Therefore array resizing is avoided whenever possible. Those optimizations might sound neat, but the code implementing them can get quite messy, especially when implementing the batch operations (addAll(), removeAll(), retainAll()...). So, if it turns out that the array resizing operation itself can be less expensive in some cases (especially shrinking), I would cut out a lot of those optimizations which are then rendered useless, making the code a lot easier in the process.
So, before sticking to my optimization ideas and experiments, I'd like to know whether they are even needed.
Hello I am research about that, but I cannot found anything in the oracle website.
The question is the next.
If you are using an static Array like this
int[] foo = new int[10];
And you want add some value to the 4 position of this ways
foor[4] = 4;
That don't shift the elements of the array so the time complexity will be O(1) because if you array start at 0x000001, and have 10 spaces, and you want put some in the x position you can access by (x*sizeOf(int))+initialMemoryPosition (this is a pseudocode)
Is this right, is this the way of that this type of array works in java, and if its time complexity O(1)
Thanks
The question is based on a misconception: in Java, you can't add elements to an array.
An array gets allocated once, initially, with a predefined number of entries. It is not possible to change that number later on.
In other words:
int a[] = new int[5];
a[4] = 5;
doesn't add anything. It just sets a value in memory.
So, if at all, we could say that we have somehow "O(1)" for accessing an address in memory, as nothing related to arrays depends on the number of entries.
Note: if you ask about ArrayList, things are different, as here adding to the end of the array can cause the creation of a new, larger (underlying) array, and moving of data.
An array is somewhere in memory. You don’t have control where, and you should not care where it is. The array is initialized when using the new type[size] syntax is used.
Accessing the array is done using the [] index operator. It will never modify size or order. Just the indexed location if you assign to it.
See also https://www.w3schools.com/java/java_arrays.asp
The time complexity is already correctly commented on. But that is the concern after getting the syntax right.
An old post regarding time complexity of collections can be found here.
Yes, it takes O(1) time. When you initialize an array, lets say, int[] foo = new int[10],
then it will create a new array with 0s. Since int has 4 bytes, which is 32 bits, every time assign a value to one element, i.e., foo[4] = 5, it will do foo[32 x input(which is 4)] = value(5); That's why array is 0-indexed, and how they assign values in O(1) time.
This question already has answers here:
Why does the foreach statement not change the element value?
(6 answers)
Closed 7 years ago.
I have a int[] a, and trying to set every element in the a to be 1. So when I did following code, and printed every element, it shows they are still 0s.
for(int num:a)
num=1;
But if I try below, every element is 1 now. I'm confused. I always thought the 2 for loop have the same functionality. Can anyone tell me why my first try failed? And why it works when i print them? Thanks~~~
for(int num=0;num<a.length;num++)
a[num]=1;
for(int n:a)
System.out.println(n);
Your first loop declares a local variable which only exists inside that loop. Its value iterates over every value in the array. A new memory location is reserved temporarily and given the name "num". Changing contents of that memory location does not modify the values in the "a" array.
Your second loop explicitly accesses memory allocated for the array "a" and changes their contents.
These loops are different. Both in functionality and operations.
The first one - an enhanced-for loop - is giving you each element in the array referenced by the variable a. It is not exposing anything for you to mutate, so assignments to a have no effect on the actual value in the array.
The second loop is simply going through all of the elements in the array, but you are directly working with the array itself at all times, so mutating the values is perfectly possible.
To put this in other terms:
The enhanced-for is going through the array, and providing you a value to use. That value, while originally provided by the array, has no connection to the array otherwise. Any modifications made to the value would not propagate to the array.
The alternative loop is only ever accessing the array contents directly, where it is perfectly possible to make modifications and reassignments to the array.
Thus, if you ever want to set the values of an array to anything other than their default value, then using the second approach is the way to go.
Or...you could use Java 8's Stream API and come up with something like this:
IntStream.iterate(1, (x) -> 1).limit(100).toArray()