Cost analysis for implementing a stack as an array? - algorithm

Please Refer to answer 2 of the material above. I can follow the text up to that point. I always seem to loose conceptualisation when there's no illustration maybe due to the fact that I'm new to math notation.
I understand the cost for an expensive operation (double the array when the stack is full)
1 + 2 + 4 + 8 + ... + 2^i where i is the index of that sequence. So index 0 = 1, 1 = 2, 2 = 4 and 3 = 8.
I can see the sequence for costly operations but I get confused with the following explanation.
Now, in any sequence of n operations, the total cost for resizing is
1 + 2 + 4 + 8 + ... + 2^i for some 2^i < n (if all operations are pushes
then 2^i will be the largest power of 2 less than n). This sum is at
most 2n − 1. Adding in the additional cost of n for
inserting/removing, we get a total cost < 3n, and so our amortised
cost per operation is < 3
I don't understand that explanation?
the total cost for resizing is 1 + 2 + 4 + 8 + ... + 2^i for some 2^i < n
What does it mean for some 2^i < n
does it say that the number of operations n will always be larger than 2^i? and does n stand for the number of operations or the length of the array?
And the following I just don't follow:
if all operations are pushes then 2^i will be the largest power of 2
less than n. This sum is at most 2n − 1.
Could someone illustrate this please?

n is the largest stack size, intrinsic array size at this moment is the least power of two 2^(i+1)>=n, so the last operation of expansion takes 2^i<n time.
For example, if array reaches size n=11, the last expansion causes grow from 8 to 16 with 8 items moved
About the second question: sum of geometric progression
1 + 2 + 4 + 8 + ... + 2^i = 2^(i+1) - 1

Related

Find out the Complexity of algorithm?

Find out the complexity of an algorithm that measures the number of the print statements in an algorithm that considers a positive integer n and prints 1 one time, 2 two times, 3 three times, and n for n times.
That is
1
2 2
3 3 3
……………
……………
n n n n ……..n (n times)
Assuming the problem is to find the algorithmic complexity of an algorithm, which when given a number n will print every number from 1 to n, printing 1 once, 2 twice, 3 thrice, and so on...
Your algorithmic complexity has an upper bound of O(n²).
This is because for n there are n prints. Realistically, if you want the tilde approximation, it should be ~O( (n² + n) /2) because you average out the sequence.
For n = 5, you print 1 + 2 + 3 + 4 + 5 times... which is 15.
For n = 6, you print 1 + 2 + 3 + 4 + 5 + 6 times... which is 21.
For n = 10, you print 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 times... which is 55 times.
Since the actual algorithmic complexity is indeed O( (n² + n) / 2), your largest order of magnitude of complexity is n². You are better off approximating your algorithmic complexity as O(n²) because your n² will quickly outgrow your n with a large enough input size.

counting binary digit algorithm || prove big oh

Is the big oh (Log n ) ?
how can i prove it by using summation
//Input: A positive decimal integer n
//Output: The number of binary digits in n’s binary representation
count ← 1
while n > 1 do
count ← count + 1
n ← ⌊n/2⌋
return count
The n is reducing like this:
n + n / 2 + n / 4 + n / 8 + .... + 8 + 4 + 2 + 1
The summation of above series is 2^(log(n)) - 1.
Now come to the above question. The number of times the loop executed is the number of items appears in above series = time complexity of the algorithm.
The number of items appears in above series is logn. So the algorithm time complexity is O(logn).
Example:
n = 8; the corresponding series:
8 + 4 + 2 + 1 = 15(2^4 - 1) ~ 2^4 ~ 2^logn
Here, number of items in series = 4
therefore,
time complexity = O(number of iteration)
= O(number of elements in series)
= O(logn)
Just check the returned value count. As it would be closer to logN, you can state that the TC is log(N).
Just think reverse way (mathematically):
1 -> 2 -> 4 -> 8 -> ... N (xth value considering 0-indexing system)
2^x = N
x = logN
You have to consider that larger numbers use more memory and take more processing for each operation. Note: time complexity only cares what happens for the largest values not the smaller ones.
The number of iterations is log2(n) however the cost of the n > 0 and n = n / 2 is proportional to the size of the integer. i.e. 128 -bit costs twice 64-bit and 1024-bit is 16 times greater. So the cost of each operation is log(m) where m is the maximum unsigned value which the number of bits stores. If you assume there is a fixed wasted bits e.g. no more than 64-bit this means the cost is O(log(n) * log(n)) or O(log(n)^2)
If you used Java's BigInteger, that's what the time complexity would be.
Big Oh complexity can easily be calculated by counting number of times the while loop runs as the operations inside while loop take constant time.In this case N varies as-
N,N/2,N/4,N/16.... ,1
Just counting number of terms in above series will give me number of times loop runs.So,
N/2^p=1 (p is number of times loop runs)
This gives p=logN thus complexity O(logN)

Skiena the Algorithm Design Manual - Geometric Series Clarification

Picture taken from book.
That is an explanation of a geometric series from the book, which I do not understand.
Constant ratio is a right?
So let's take first term (just the sum function), for n = 5, and constant ratio = 2.
So we will have this:
2^0 + 2^1 + 2^2 + 2^3 + 2^4 + 2^5 = 1 + 2 + 4 + 8 + 16 + 32 = 63
No if I use the RHS,
a(a^n+1 - 1)/(a - 1).
So it will give this: 2(2^5+1 - 1)/(2 - 1) for n = 5 this gives 126.
How can they be equal ?
Also it says later on: 'when a > 1 the sum grows rapidly with each new term..' Is he talking about space complexity ?
Because I do not get the big-theta notation. So for n = 5 and a = 2 it will take Big-Theta(64), 64 (2^6) steps?
Here is some ruby code:
n = 5
a = 2
sum = 0
for i in 0..n do
sum = sum + a**i
end
puts sum # prints 63
I can see n+1 steps.
Any help understanding this please?
The formula in the book is wrong, there is an extra a factor (n=0 should yield 1, not a).
"The sum grows rapidly" is just about the values of the sum, it does not describe the complexity of computing it.

Computational complexity in Big-O notation

How can I specify computational complexity of an algorithm in Big-O notation whose execution follows the following pattern, according to input sizes?
Input size: 4
Number of execution steps: 4 + 3 + 2 + 1 = 10
Input size: 5
Number of execution steps: 5 + 4 + 3 + 2 + 1 = 15
Input size: 6
Number of execution steps: 6 + 5 + 4 + 3 + 2 + 1 = 21
Technically, you have not given enough information to determine the complexity. On the information so far, it could take 21 steps for all input sizes greater than 5. In that case, it would be O(1) regardless of the behavior for sizes 4 and 5. Complexity is about limiting behavior for large input sizes, not about how something behaves for three extremely small sizes.
If the number of steps for size n is, in general, the sum of the numbers from 1 through n then the formula for the number of steps is indeed n(n+1)/2 and it is O(n^2).
For any series which follows the pattern 1 + 2 + 3 + 4 + ....+n , the sum of the series is given as n(n+1)/2, which is O(n^2)..
In your case , the number of steps will never be n^2, because at each level we are doing one step less(n + n-1 + n-2),however the big Oh notation is used to specify the upper bound on the growth rate of a function thus your big O will be O(n^2) because it is more than n number of steps but less than n^2 number of steps.
I think it should be O(N), because it's just like : Given an array with N size, and iterate it (if we don't care the plus computation time).
By the way, I think the (n + 1)*n/2 is just the result of sum, not the algorithm complexity.

Big O Speed of Removing Duplicates from Linked List Without Buffer

The approach I'm referring to is the dual-pointer technique. Where the first pointer is a straightforward iterator and the second pointer goes through only all previous values relative to the first pointer.
That way, less work is done than if, for each node, we compared against every other node. Which would end up being O(n^2).
My question is what is the speed of the dual-pointer method and why?
So if you have N elements in the list, doing your de-duping on element i will require i comparisons (there are i values behind it). So, we can set up the total number of comparisons as sum[i = 0 to N] i. This summation evaluates to N(N+1)/2, which is strictly less than N^2 for N > 1.
Edit:
To solve the summation, you can approach it like this.
1 + 2 + 3 + 4 + ... + (n-2) + (n-1) + n From here, you can match up numbers from opposite sides. This can then become
2 + 3 + ... + (n-1) + (n+1) by matching up the 1 at the start with the n at the end. Do the same with 2 and (n-1).
3 + ... + (n-1+2) + (n+1) simplify to become
3 + ... + (n+1) + (n+1)
You can repeat this n/2 times, since you are matching up two number each time. This will leave us with n/2 occurances of the term (n+1). Multiplying those and simplifying, we get (n+1)(n/2) or n(n+1)/2.
See here for more description.
Also, this suggests this summation still has a big-theta of n^2.

Resources