Is ArrayList indexOf complexity N? - java

I have N numbers in arraylist. To get the indexOf, arraylist will have to iterate maximum N times, so complexity is O(N), is that correct?

Source Java API
Yes,Complexity is O(N).
The size, isEmpty, get, set, iterator, and listIterator operations run in constant time. The add operation runs in amortized constant time, that is, adding n elements requires O(n) time. All of the other operations run in linear time (roughly speaking). The constant factor is low compared to that for the LinkedList implementation.

Yes it's O(n) as it needs to iterate through every item in the list in the worst case.
The only way to achieve better than this is to have some sort of structure to the list. The most typical example being looking through a sorted list using binary search in O(log n) time.

Yes, that is correct. The order is based off the worst case.

100%, it needs to iterate through the list to find the correct index.

It is true. Best Case is 1 so O(1), Average Case is N/2 so O(N) and Worst Case is N so O(N)

In the worst case you find the element at the very last position, which takes N steps, that is, O(N). In the best case the item you are searching for is the very first one, so the complexity is O(1). The average length is of the average number of steps. If we do not have further context, then this is how one can make the calculations:
avg = (1 + 2 + ... n) / n = (n * (n + 1) / 2) / n = (n + 1) / 2
If n -> infinity, then adding a positive constant and dividing by a positive constant has no effect, we still have infinity, so it is O(n).
However if you have a large finite data to work with, then you might want to calculate the exact average value as above.
Also, you might have a context there which could aid you to get further accuracy in your calculations.
Example:
Let's consider the example when your array is ordered by usage frequency descendingly. In case that your call of indexOf is a usage, then the most probable item is the first one, then the second and so on. If you have exact usage frequency for each item, then you will be able to calculate a probable wait time.

An ArrayList is an Array with more features. So the order of complexity for operations done to an ArrayList is the same as for an Array.

Related

Does the time complexity of code depend on loops or number of operations?

I was making a code in which I needed to compare elements of my array with another array.
But I was thinking that this would increase my time complexity from O(n) to O(n^2) as it was already inside one for loop, for the first array.
So I came up with a code like this, inside the parent for loop (with parameter i):
int m = 0;
int ele = array2[m];
if(array1[i] == ele)
count++;
m++;
But since the thing that is being done is same, only I have emitted a for loop, I was wondering that the time complexity indeed was O(n) or became O(n^2).
I also understand that this would only compare the same indexed elements and not all. I would appreciate if someone can part more information about this.
Yes Time complexity depends on Loop and number of operations done within it.
In your case there is one assignment int ele = array2[m] and one conditional checking if(array1[i] == ele) along with 2 increments of m and count.
All the operations will take constant time and will depend on the number of time the loop is executing.
The time complexity of an algorithm depends on the way you write your loops and also the time complexity of the operation you do in the algorithm.
If your algorithm consists of any number of O(1) operations, your algorithm is O(1).
If your algorithm consists of one or more loops (not nested) from a constant to n, the time complexity is O(n * the_time_complexity_of_the_operation_in_the_loop)
Every statement below takes O(1) time:
int m = 0;
int ele = array2[m];
if(array1[i] == ele)
count++;
m++;
so the whole thing is O(1). This block is inside a for loop that loops through your array, so the time complexity is O(n * 1) = O(n), where n is the array's length.
Here's an intuitive way to think about why the time complexity became less complex when you compare only the elements at the same index.
If you want to compare every possible pair of the two arrays, how many pairs are there? The first element of first array can form a pair with n other elements from the second array, The second element of the first array can form a pair with n elements from the second array, and so on. In general, for each element in the first array, n pairs can be formed. Assuming the two arrays are of the same length, the total number of pairs is n^2. Therefore, that many comparisons needs to be made, which means the time complexity is O(n^2).
If you want to compare the pairs elements at the same index, how many pairs can you have? n pairs, because each index correspond to exactly 1 pair. Therefore you need to make n comparisons, which means the time complexity is O(n).
In this case, you are always comparing the array[m] (in your case array[0]) element with i^th index of array1 array. So this is actually same as traversing one array and count the number of elements matching given specific number
Comparing one array to another usually takes O(n^2) time, though there are ways to do in lesser time complexity. Once such solution could be of O(n+m) time complexity and O(min(n,m)) space complexity. Where you Traverse the lesser sized array and store the elements in one hash table, then you traverse the second array to match the elements from hash table.

Search the different number in array, when all the other numbers are same , can this be done in O(logn) using divide and conquer

Lets say we have a very large array and we need to find the only different number in the array, all the other numbers are the same in the array, can we find it in O(log n) using divide and conquer, just like mergeSort, please provide an implementation.
This cannot be done in better time complexity than O(n) unless that array is special. With the constraints you have given, even if you apply an algorithm like divide and conquer you have to visit every array element at least once.
As dividing the array will be O(log n) and comparing 2 elements when array is reduced to size 2 will be O(1)
This is wrongly put. Dividing the array is not O(log n). The reason why something like a binary search works in O(log n) is because the array is sorted and that way you can discard the other half of the array at every step even without looking at what elements they have, thereby halving the size of original problem.
Intuitively, you can think this as follows : Even if you keep on dividing the array into halves, the leaf nodes of the tree formed are n/2 (Considering you compare 2 elements at leaf). You will have to make n/2 comparisons, which leads to asymptotic complexity of O(n).

Trying to understand complexity of quick sort

I understand worst case happens when the pivot is the smallest or the largest element. Then one of the partition is empty and we repeat the recursion for N-1 elements
But how it is calculated to O(N^2)
I have read couple of articles still not able to understand it fully.
Similarly, best case is when the pivot is the median of the array and the left and right part are of the same size. But, then how the value O(NlogN) is calculated
I understand worst case happens when the pivot is the smallest or the largest element. Then one of the partition is empty and we repeat the recursion for N-1 elements.
So, imagine that you repeatedly pick the worst pivot; i.e. in the N-1 case one partition is empty and you recurse with N-2 elements, then N-3, and so on until you get to 1.
The sum of N-1 + N-2 + ... + 1 is (N * (N - 1)) / 2. (Students typically learn this in high-school maths these days ...)
O(N(N-1)/2) is the same as O(N^2). You can deduce this from first principles from the mathematical definition of Big-O notation.
Similarly, best case is when the pivot is the median of the array and the left and right part are of the same size. But, then how the value O(NlogN) is calculated.
That is a bit more complicated.
Think of the problem as a tree:
At the top level, you split the problem into two equal-sized sub problems, and move N objects into their correct partitions.
At the 2nd level. you split the two sub-problems into four sub-sub-problems, and in 2 problems you move N/2 objects into their correct partitions, for a total of N objects moved.
At the bottom level you have N/2 sub-problems of size 2 which you (notionally) split into N problems of size 1, again copying N objects.
Clearly, at each level you move N objects. The height of the tree for a problem of size N is log2N. So ... there are N * log2N object moves; i.e. O(N * log2)
But log2N is logeN * loge2. (High-school maths, again.)
So O(Nlog2N) is O(NlogN)
Little correction to your statement:
I understand worst case happens when the pivot is the smallest or the largest element.
Actually, the worst case happens when each successive pivots are the smallest or the largest element of remaining partitioned array.
To better understand the worst case: Think about an already sorted array, which you may be trying to sort.
You select first element as first pivot. After comparing the rest of the array, you would find that the n-1 elements still are on the other end (rightside) and the first element remains at the same position, which actually totally beats the purpose of partitioning. These steps you would keep repeating till the last element with the same effect, which in turn would account for (n-1 + n-2 + n-3 + ... + 1) comparisons, and that sums up to (n*(n-1))/2 comparisons. So,
O(n*(n-1)/2) = O(n^2) for worst case.
To overcome this problem, it is always recommended to pick up each successive pivots randomly.
I would try to add explanation for average case as well.
The best case can derived from the Master theorem. See https://en.wikipedia.org/wiki/Master_theorem for instance, or Cormen, Leiserson, Rivest, and Stein: Introduction to Algorithms for a proof of the theorem.
One way to think of it is the following.
If quicksort makes a poor choice for a pivot, then the pivot induces an unbalanced partition, with most of the elements being on one side of the pivot (either below or above). In an extreme case, you could have, as you suggest, that all elements are below or above the pivot. In that case we can model the time complexity of quicksort with the recurrence T(n)=T(1)+T(n-1)+O(n). However, T(1)=O(1), and we can write out the recurrence T(n)=O(n)+O(n-1)+...+O(1) = O(n^2). (One has to take care to understand what it means to sum Big-Oh terms.)
On the other hand, if quicksort repeatedly makes good pivot choices, then those pivots induce balanced partitions. In the best case, about half the elements will be below the pivot, and about half the elements above the pivot. This means we recurse on two subarrays of roughly equal sizes. The recurrence then becomes T(n)=T(n/2)+T(n/2)+O(n) = 2T(n/2)+O(n). (Here, too, one must take care about rounding the n/2 if one wants to be formal.) This solves to T(n)=O(n log n).
The intuition for the last paragraph is that we compute the relative position of the pivot in the sorted order without actually sorting the whole array. We can then compute the relative position of the pivot in the below subarray without having to worry about the elements from the above subarray; similarly for the above subarray.
Firstly, paste a pseudo-code here:
In my opinion, you need understand the two cases: the worst case & the best case.
The worst case:
The most unbalanced partition occurs when the pivot divides the list into two sublists of sizes 0 and n−1. The complexity in recursively is T(n)=O(n)+T(0)+T(n-1)=O(n)+T(n-1). The master theorem tells that
T(n)=O(n²).
The best case:
In the most balanced case, each time we perform a partition we divide the list into two nearly equal pieces. The same as the worst, the recurrence relation is T(n)=O(n)+2T(n/2). And it can transform to T(n)=O(n logn).

Complexity of calling get() on a LinkedList in a for loop using O notation

I've a uni practical to determine the complexity of a small section of code using the O() notation.
The code is:
for (int i = 0; i < list.size(); i++)
System.out.println(list.get(i));
The list in question is a linked list. For our practical, we were given a ready made LinkedList class, although we had to write our own size() and get() methods.
What is confusing me about this question is what to count in the final calculation. The question asks:
How many lookups would it make if there 100 elements in the list? Based on this, calculate the complexity of the program using O() notation.
If I am just counting the get() method, it will make an average of n/2 lookups, resulting in a big O notation of O(n). However, each iteration of the for loop requires recalculating the size(), which involves a lookup (to determine how many nodes are in the linked list).
When calculating the complexity of this code, should this be taken into consideration? Or does calculating the size not count as a lookup?
I might be bit late to answer, but I think this for loop would actually be
Explanation
Each loop iteration you would be accessing the ith index of the list. Your call sequence would therefore be:
This is because each iteration i is incremented, and you are looping n times.
Therefore, the total number of method calls can be evaluated using the following sum:
In Java LinkedList, get(int) operation is O(N), and size() operation is O(1) complexity.
Since it is a linked list, to determine the size will be an O(N) operation, since you must traverse the whole list.
Also, you miscalculated the time complexity for .get(). For big-O, what matters is the worst case computation. For a linked list, the worst case of retrieval is that the element is at the end of the list, so that is also O(N).
All told, your algorithm will take O(2N) = O(N) time per iteration. I hope you can go from there to figure out what the time complexity of the whole loop will be.
By the way, in the real world you would want to compute the size just once, before the loop, precisely because it can be inefficient like this. Obviously, that's not an option if the size of the list can change during the loop, but it doesn't look like that's the case for this non-mutating algorithm.
Short answer: It depends on the interpretation of the question.
If the question is asking how many times I will have to jump the list if I want to find 100th position (like calling .get(100)), the complexity would be O(N) since I need to go through the entire list once.
If the question is asking for the complexity of finding an ith variable by checking each index ( like .get(1), .get(2), ..., .get(100)), the complexity would be O(N²) as explained by michael.
Long answer:
The complexity of calculating the size depends on your implementation. If you traverse the entire list to find the size, the complexity would be O(N) for the size calculation (and O(2N) in the first case, O(N² + N) in the second) <- this last part also depends on your implementation as I'm thinking you're calculating the size out of the for-loop.
if you have the size saved as an instance variable that gets bigger every time an element is added, you'll have O(1) for the size and the same complexity for first and second case.
The reason why we round O(2N) (or any case of O(aN + b)) to O(N) is because we care only about the growth of time spent to process the data. If N is small, the code would run fast anyways. If N is big, the code might run in a lot more time depending of the complexity but the constants a and b wouldn't be of much effect when compared with a worse complexity implementation.
Suppose a code runs in 2 seconds for a small input N in O(N) complexity.
as the value gets bigger: N, 2N, 3N, 4N, ..., kN
if the code has complexity O(N) the time would be: 2, 4, 6, 8, ..., 2k
if the code has complexity O(2N) the time would be: 4, 8, 12, 16, ..., 2k * 2
if the code has complexity O(N²) the time would be: 4, 16, 36, 64, ..., (2k)²
As you can see the last implementation is getting out of hand really fast while the second is only two times slower than a simple linear. So O(2N) is slower but it's almost nothing compared to a O(N²) solution.

about the usage of modulus operator

this a part of code for Quick Sort algorithm but realy I do not know that why it uses rand() %n please help me thanks
Swap(V,0,rand() %n) // move pivot elem to V[0]
It is used for randomizing the Quick Sort to achieve an average of nlgn time complexity.
To Quote from Wikipedia:
What makes random pivots a good choice?
Suppose we sort the list and then
divide it into four parts. The two
parts in the middle will contain the
best pivots; each of them is larger
than at least 25% of the elements and
smaller than at least 25% of the
elements. If we could consistently
choose an element from these two
middle parts, we would only have to
split the list at most 2log2n times
before reaching lists of size 1,
yielding an algorithm.
Quick sort has its average time complexity O(nlog(n)) but worst case complexity is n^2 (when array is already sorted). So to make it O(nlog(n)) pivot is chosen randomly so rand()%n is generating a random index between 0 to n-1.

Categories

Resources