Running time(big O)) of an algorithm - algorithm

i m calculating running time for this algorithm?
Cost No Of Times
for(j=1;j<=n-1;j++){ c1 n(loop will run for n-1 times +1 for failed cond
for(i=0;i<=n-2;i++){ c2 n*(n-1) (n-1 from outer loop and n for inner
if(a[i]>a[i+1]){ c3 (n-1)*(n-1)
Swap c4 (n-1)*(n-1) {in worst case }
}
}
in worst case
T(n)= c1*n + c2*(n-1)n + c3(n-1)(n-1) + c4*(n-1)(n-1)
which is O(n^2)
In Best case:
T(n)=c1*n + c2*(n-1)n + c3(n-1)(n-1)
which is O(n^2).
BUT actually in best case bubble sort has time complexity O(n).
Can anyone explain?

Bubble Sort has O(n) time complexity in the best case because it is possible to pass an already sorted list to it.
You have to check if you did any swaps after the second nested loop. If no swaps were done, the list is sorted and there's no need to continue, so you can break the loop.
For an already-sorted list, you'd have iterated over all n elements once in this case.

your algo for implementing bubble sort is correct but not efficient,
// n is the total number of elments
do{
swp = false // swp checks whether or not any variable has been swapped
in the inner loop
for(i=0;i<=n-2;i++){
if(a[i]>a[i+1])
{
swap(a[i],a[i+1])
sw = true
}
n = n-1
}while(sw == true && n>0)
swp is a variable which checks whether there has been any swap in the inner loop or not,
if there has not been any swap this means that our array is sorted.
The best case for bubble sort is when the elements are already sorted in ascending order(in this case)
for which the inner loop just runs once but the if condition(in the inner loop) is never satisfied and swp remains false and thus we exit from the outer loop after one iteration which gives bubble sort O(n) complexity.

You can compute the number of iterations (what's inside the loop is irrelevant because it's of constant time) using Sigma Notation:
Bubble Sort with a best case running time is actually an enhanced version of this sorting algorithm.
During the first parse (outer loop), if no swap was performed, that is a decisive information that the array is sorted, and it is pointless to cover all cases.
Therefore, the outer loop would iterate once, and the inner loop would iterate n times: that's n + 1 iterations overall ==> O(n).

Related

calculating time complexity for insertion sort

I'm trying to understand the time complexity of insertion sort. I got stuck at while loop. I'm unable to understand how many times while loop executes
InsertionSort(A)
for j = 2 to A.length
key = A[j]
i = j - 1
while i>0 and A[i]>key
A[i+1] = A[i]
i = i - 1
A[i+1] = key
I know that for loop executes n+1 times and every statement in the loop execute n times
while loop also executes n times
But, what I don't understand is "How many times statements under while loop executes for both worst and best cases?"
In the worst case, A is sorted in descending order, which means that for the j'th entry, the inner loop will run j times (give or take a "+1" or "-1"...). Happily, there is a formula for that: as Gauss famously found out spontaneously and under duress, summing up all numbers from 1 to n yields a result of n*(n+1)/2.
As we only care about complexity and not actual values, we can leave the constant and multiplicative factors off and end up with O(n^2).
Tongue-in-cheek aside, the fact that there is a loop within a loop is a strong indication for O(n^2) when the inner loop count is bounded linearly - which it is here.
Best case, with A already sorted in ascending order, the inner loop will be entered not at all, and overall complexity will be O(n).
The average case depends heavily on what your expected "unorderedness" looks like. For example, the sort will behave greatly if your list is basically always sorted already, and there are only very few, very local switchups.

Analysing running time, Big O

I am having problems with anyalysing the time complexity of an algorithm.
For example the following Haskell code, which will sort a list.
sort xs
|isSorted xs= xs
|otherwise= sort (check xs)
where
isSorted xs=all (==True) (zipWith (<=) xs ( drop 1 xs))
check [] =[]
check [x]=[x]
check (x:y:xs)
|x<=y = x:check (y:xs)
|otherwise=y:check (x:xs)
So for n being the length of the list and t_isSorted(n) the running time function: there is an constant t_drop(n) =c and t_all(n)=n, t_zipWith(n)=n :
t_isSorted(n)= c + n +n
For t_check:
t_check(1)=c1
t_check(n)=c2 + t_check(n-1), c2= for comparing and changing an element
.
.
.
t_check(n)=i*c2 + tcheck_(n-i), with i=n-1
=(n-1)*c2 + t_check(1)
=n*c2 - c2 + c1
And how exactly do I have to combine those to get t_sort(n)? I guess in the worst- case, sort xs has to run n-1 times.
isSorted is indeed O(n), since it's dominated by zipWith which in turn is O(n) since it does a linear pass over its argument.
check itself is O(n), since it only calls itself once per execution, and it always removes a constant number of elements from the list. The fastest sorting algorithm (without knowing something more about the list) runs in O(n*log(n)) (equivalent to O(log(n!)) time). There's a mathematical proof of this, and this algorithm is faster, so it cannot possibly be sorting the whole list.
check only moves things one step; it's effectively a single pass of bubble sort.
Consider sorting this list: [3,2,1]
check [3,2,1] = 2:(check [3,1]) -- since 3 > 2
check [3,1] = 1:(check [3]) -- since 3 > 1
check [3] = [3]
which would return the "sorted" list [2,1,3].
Then, as long as the list is not sorted, we loop. Since we might only put one element in its correct position (as 3 did in the example above), we might need O(n) loop iterations.
This totals at a time complexity of O(n) * O(n) = O(n^2)
The time complexity is O(n^2).
You're right, one step takes O(n) time (for both isSorted and check functions). It is called no more than n times (maybe even n - 1, it doesn't really matter for time complexity) (after the first call the largest element is guaranteed to be the last one, the same is the case for the second largest after the second call. We can prove that the last k elements are the largest and sorted properly after k calls). It swaps only adjacent elements, so it removes at most one inversion per step. As the number of inversions is O(n^2) in the worst case (namely, n * (n - 1) / 2), the time complexity is O(n^2).

Big O of BubbleSort on a simple list of 5 values

I believe that a BubbleSort is of the order O(n^2). As I read previous postings, this has to do with nested iteration. But when I dry run a simple unsorted list, (see below), I have the list sorted in 10 comparisons.
In my example, here is my list of integer values:
5 4 3 2 1
To get 5 into position, I did n-1 swap operations. (4)
To get 4 into position, I did n-2 swap operations. (3)
To get 3 into position, I did n-3 swap operations. (2)
To get 2 into position, I did n-4 swap operations. (1)
I can't see where (n^2) comes from, as when I have a list of n=5 items, I only need 10 swap operations.
BTW, I've seen (n-1).(n-1) which doesn't make sense to me, as this would give 16 swap operations.
I'm only concerned with basic BubbleSort...a simple nested FOR loop, in the interest of simplicity and clarity.
You don't seem to understand the concept of big O notation very
well. It refers to how the number of operations or the time grows in
relation to the size of the input, asymptotically, considering only the
fastest-growing term, and without considering the constant of
proportionality.
A single measurement like your 5:10 result is completely meaningless.
Imagine looking for a function that maps 5 to 10. Is it 2N? N + 5? 4N –
10? 0.4N2? N2 – 15? 4 log5N + 6? The
possibilities are limitless.
Instead, you have to analyze the algorithm to see how the number of
operations grows as N does, or measure the operations or time over many
runs, using various values of N and the most general datasets you can
devise. Note that your test case is not general at all: when checking
the average performance of a sorting algorithm, you want the input to be
in random order (the most likely case), not sorted or reverse-sorted.
If you wan to precise there are (n)*(n-1)/2 operations because you are actually computing n+(n-1)+(n-2)+...+1 as the first element needs n swaps, second element need n-1 swaps and so on. So the algorithm is of O(1/2 * (n^2) - n) which in asymptotic notations is equal to O(n^2). But what actually is happening in bubble sort is different. In bubble sort you perform a pass on array and swap the misplaced neighbors place, until there is no misplacement which means the array has become sorted. As each pass on array takes O(n) time and in the worst case you have to perform n passes so the algorithm is of O(n^2). Note that we are counting the number of comparisons not the number of swaps.
There are two version of bubble sort mentioned in wikipedia:
procedure bubbleSort( A : list of sortable items )
n = length(A)
repeat
swapped = false
for i = 1 to n-1 inclusive do
/* if this pair is out of order */
if A[i-1] > A[i] then
/* swap them and remember something changed */
swap( A[i-1], A[i] )
swapped = true
end if
end for
until not swapped
end procedure
This version perform (n-1)*(n-1) comparison -> O(n^2)
Optimizing bubble sort
The bubble sort algorithm can be easily
optimized by observing that the n-th pass finds the n-th largest
element and puts it into its final place. So, the inner loop can avoid
looking at the last n-1 items when running for the n-th time:
procedure bubbleSort( A : list of sortable items )
n = length(A)
repeat
swapped = false
for i = 1 to n-1 inclusive do
if A[i-1] > A[i] then
swap(A[i-1], A[i])
swapped = true
end if
end for
n = n - 1
until not swapped
end procedure
This version performs (n-1)+(n-2)+(n-3)+...+1 operations which is (n-1)(n-2)/2 comparisons -> O(n^2)

Algorithm for better Big O complexity [duplicate]

This question already has answers here:
Best case Big O complexity
(2 answers)
Closed 8 years ago.
Could someone please help me with this question?:
how can you limit the input data to achieve a better Big O complexity? Describe an algorithm for handling this limited data to find if there are any duplicates. What is the Big O complexity?
By limit the input data, we mean the array size e.g. n=100 (array contains 100 integers) and also; the array is unsorted by default but could be implemented in the algorithm.
The worst case complexity which i got is O (N^2) = N * ((N + 1)/2) in the case of an unsorted array of size n.
I got that by using nested loops (outer loop used for n-1 iterations- used to iterate on each value in the array- and the inner loop used for comparison to check to see if duplicates exist) and repeated the process until the outer loop terminates.
You have the solution right in front of you. As you state, if the array is unsorted, finding duplicates is O(N^2). But if the array is sorted, you can do it in O(N). So sort the array first, which can be done in O(N.Log(N)).
An algorithm that first sorts and then find the duplicates can thus be done in O(N.Log(N) + N), which is O(N.Log(N)).
UPDATE:
As Amir points out: you can use a hash table. Since inserting and searching in a hash table is O(1), you can do this in a single loop, yielding O(N) time complexity.
However, your question is about "limited input data". So if you limit your input data to sorted arrays, you can reduce the complexity to O(N). To be precise, if you know that the array is sorted (this is your limitation), than a single loop that compares every element to its successor(s) will find the duplicates.
If the array is not sorted, you need an outer loop over all elements but the last, and an inner loop over all the remaining elements. If the array is sorted, you don't need the inner loop, just compare to the next element. That is the "reduction" of the algorithm, resulting in a "reduction" of O(N^2) to O(N).
one way is to sort and then remove duplicates, but you need an additional memory
Pseudocode:
remDups(arr,arr2)
Sort(arr); // O(nlogn)
arr2[0] = arr[0];
j=1;
foreach(i+1 to arr.len : i++) //O(n)
{
if(arr[i-1] == arr[i]) continue;
arr1[j++] = arr[i];
}
O(nlogn)
You can use, HashTablemethod

Run time of 2 nested while loops

I had another question regarding loops. I know 2 for loops make the run time O(n^2) since you iterate through the list n * n times.
But what about two while loops?
While (array1 is not empty)
if(~~~)
do ~~~
else(~~~)
do ~~~
while (array2 is not empty)
if(~~~)
do ~~~
else(~~~)
do ~~~
so a while loop is nested inside another while loop. Does this make the run time n^2 also since we iterate though the first loop n times and second loop n times? Any help would be apreciated.
Thanks!
In this case, it doesn't look like they are nested. There are 2 loops, separated by an if/else. In this case, it would be O(n).
If the while loops were nested and based on input size, it would indeed be O(n^2). It's not important what 'type' of loop you are using, but rather the fact that you're looping over the input of size n.
A nested for loop runs at O(n²), as you said. The notation for determining how fast two of these in sequence will run is O(2n²). The notation for running two while loops n times each is O(2n).
while (array1 isn't empty){
while (array2 isn't empty){
//code goes here
}
}
If the first array has n elements and the 2nd array has m elements then the runtime is O( n * m )
In the special case where n and m are the same, then it is O( n * n )
while (array1 isn't empty){
//code
}
while (array2 isn't empty){
//code
}
In this case the runtime is O(n) + O(m) which is O(n) if n is greater than or equal to m and O(m) if m is greater than or equal to n.

Resources