Maximum number of primitive operations occurring in a program - c

I am trying to count the maximum number of operations in a program, given the pseudocode. I am given the pseudocode for finding the maximum number in an array (provided in our class slides by our professor). Now I need to count maximum possible number of primitive operations (I know usually order is the only thing we need to care about, but nonetheless I want to try this out.)
Some examples of primitive operations considered are:
Evaluating an expression
Assigning a value to a variable
Indexing into an array
Calling a method
Returning from a method, etc...
Now I understand why the first line takes 2 operations, we are indexing into the array A and assigning the value to the variable currentMax, thus there are 2 operations in total being carried out in the first line. I understand that the maximum number of primitive operations (that is the worst case) is going to be 2(n-1) for the 3 lines inside the for loop, but I am having trouble with the line that is labelled as having 2n operations.
In my mind, what is happening is the first time, i=1 is getting assigned and checked against n-1, thus 2 operations, and then the only thing occurring is the checking of i each time against n-1. The incrementing is happening in line where it says {increment counter i}. We aren't assigning any value to i in the for loop line. Thus I think the for loop line should have 2 + n operations instead of 2n.
I found another slide on the internet after a bit of searching that has the same structure, but it says 2+n instead of 2n and the total number of operations is then 7n-1 instead of 8n-2. This is shown here:
Which one is the correct one here?

Related

Checking if an array is unimodal

An array of integers is unimodal, if:
it is strictly increasing in the beginning;
after that it is constant;
after that, it is strictly decreasing.
The first block (increasing) and the last block (decreasing) may be absent. It is allowed that both of this blocks are absent.
For example, the following three arrays are unimodal: [5, 7, 11, 11, 2, 1], [4, 4, 2], [7], but the following three are not unimodal: [5, 5, 6, 6, 1], [1, 2, 1, 2], [4, 5, 5, 6].
Write a C program that checks if an array is unimodal.
restrictions: The function should run in the order of n.
No more than n-1 comparison operations should be performed between the array elements.
Can I use 3 while loops (not nested) and check 3 parts of the array if part number1 increasing then part number 2 is constant and part3 decreasing?
While it is possible to code this in three loops for each possible stage in the unimodal curve, such a "stateful" algorithm is not particularly mathematical. Note that an equivalent stateful algorithm is possible in a single loop by retaining state in a variable rather then in the code control flow.
It is perhaps both mathematically more robust (or at least demonstrates understanding of the mathematics of such a curve), and simpler, to test for a single common-denominator - i.e. a common relationship that holds true for every point on a unimodal curve, but not for any non-unimodal curve. In that way you can perform the test arithmetically in a single loop rather then by control flow or state transition.
That single common-denominator in this case - one that mathematically defines the curve is this: The signum of the gradient of the curve is decreasing-monotonic.
Signum is a function such that signum(a) is:
0 if a == 0,
1 if a > 0,
-1 if a < 0
While decreasing-monotonic means the value either falls or remains the same, but never rises - its all down-hill or plateau.
The gradient at any point is simply d[n+1] - d[n]. So the loop subtracts one element from the other, determines the signum, and compares it with the previous signum. The curve is not unimodal if the signum increases. That is it can rise only, be flat only or fall only, or it can rise and fall, but never rise again, with any number of level plateaus.
Note that this solution will work for the mathematical definition of a unimodal curve; the definition in your question is somewhat ambiguous and does not appear to allow for multiple plateaus. That is to say it allows:
_________
/ \
/ \
/ \
but excludes for example:
___
/ \
___/ \____
/ \
I think however that the second is clearly unimodal.
From: https://en.wikipedia.org/wiki/Unimodality:
The last part being key - zeroes don't count as a sign change. Regardless of that subtlety however, it works for all your test cases.

Optimal way for storing compressed sets

As title says, I am searching for the optimal way of storing sets in memory. I am only interested in sets of bytes (array of integers from 0 to 255 where order is not important). It is not required that encoding/decoding be fast. The only necessary thing is that sets should require as little memory as possible.
The first method I came up with is to allocate array of 256 bits (32 bytes) for each set and the bit at position n tells if there is n in the set or not. The problem with this approach is because it requires the same amount of memory even if the set are mostly empty (has only few elements).
The second approach I tried is to store sets as regular arrays. So, if a set contains n elements, then it will require n + 1 bytes to be stored. The first byte represents the number of elements and other bytes represents elements. But, as we know, order in sets are not important, so something strongly tells me that there must be a way to impove this.
My third attempt is to enumerate all possible sets and the just store the index of set (integer representing its index in list of all possible sets of bytes). But, it turned out that it is absolutelly equivalent as the first approach. Basically, I will still need 32 bytes to store any set, so it is not very useful.
Fourth attempt I made is based on my second approach. I noticed that is the set contains n elements it will, of course, require n + 1 bytes (if I use my second method). But, if, for example, element k appeared in set (actually in array, because in my second attempt I store sets as arrays), then it cannot appear again. Basically, if k appears again, then it must mean something different (maybe k - 1). So, I did some optimizations and I noticed that I can save some bytes if I differently encode each next element (for examle [3, 3, 5, 7] is interpreted as set of 3 elements whose elements are {3, 4, 5} (every next element is decreased by its index) and [3, 3, 5, 6] is interpreted as {3, 4, 2} (notice that 3 and 4 already exists, so 6 is decreased by 2 and it becomes 4, but 4 exists and 3 exists, so it must be 2)). But how can this approach can actually save bytes? I experimented and realized that I can order elements in the array to make it possible, for some cases, to avoid using high bit to encode element, so I saved 1 bit per element, which is about n / 16 bytes saved (which is n / 2 * 1 / 8).
Fifth approach I made is similar to my second approach, but it differently interpret number fo elements. If number of elements are less than 128 then it normally read all the lements from the following array in the memory. But, if the number fo ellements is greater than 128 then it creates a full set and then just remove elements from the following array in memory. On average, is saves a lot of bytes, but it is still far away from optimal.
My last attempt (sixth attempt) is to enumerate just some sets (for example create a list of sets which will contain: full set, set with only even numbers, set with only odd numbers, set with elements less than 128, set with elements greater than 128, etc) and then to use elements from that list and basic set operations (union, intersection, etc) to reconstruct original set. It will require few bytes for each base set we use from the list and it will require a few bits for union or intersection operations, and of course one byte for length of our sequence. It very depends on number of elements in the base set list which should be hardcoded, but it seems hard to preoperly create and properly chose elements which are in that list. Anyway, something tells me that this is not very clever approach.
But hat is actually the most optimal way? Something tells me that my fourth attempt is not so bad, but can we do better? The sets I opereate with have random number of elements, so on average 128 elements per set, so I am looking for a way to allocate 128 bits (16 bytes) per set. The best I did so far is using my fourth approach which is far away from my goal.
Just to mention again, speed is not important. Encoding/decoding may be extremelly slow, the only important thing is that sets require as little amount of memory as possible. When I said "in memory" I meant encoded in memory (compressed). Also, I am interested in as little bits as possible (not only bytes) because I want to store billions of sets compressed on my HDD, so it is important to calculate average amount of bits I need for each set so I know how many resources are available to what I want to achieve.
P.S. If you want some code (but I really don't see why would you) I can post here my solutions I made in C for all of these approaches. Anyway, I am not asking for code or technical details how to implement this in specific programming language, I am just asking for method/algorithm for compressing sets.
Thank you in advance.
Your first method (and the third method, which is equivalent) is already optimal. It cannot be improved.
There are 2256 possible sets of numbers you're working with. By the pigeonhole principle, you need 2256 numbers to identify them all, and you'll need 256 bits to represent those numbers. Any method of identifying the sets which used fewer than 256 bits would leave at least one pair (and probably many pairs) of sets sharing the same identifier.
There are 2^256 possible sets of bytes.
If all sets are equally likely, then the best you can do is to use a constant 256 bits (32 bytes) to indicate which of the 2^256 possibilities you have.
You seem not to like this idea, because you think that sets with only a few elements should take fewer bits. But if they are no more likely to occur than any other sets, then that would not be optimal.
If sets with fewer elements are more likely, then using a constant 32-bytes is not optimal, but the optimal encoding depends on the precise probability distribution of possible sets, which you haven't given. The relevant concept from information theory is "entropy": https://en.wikipedia.org/wiki/Entropy_(information_theory)
Succinctly, in an optimal encoding, the average number of bits required will be the Sum_of_all Pᵢ * -log₂(Pᵢ) over all 2^256 possible sets, where each Pᵢ is the probability of having to encode a particular set (all the Pᵢ must sum to 1)
If the number of elements is the only thing that you think should affect the size of the encoding, then you can't go too far wrong with something like this:
1) Use 1 byte to write out the number of elements in the set. There are 257 possible set sizes, but you can use 0 for both 0 and 256 elements.
2) Write out the index of the set in an enumeration of all sets with that length. (If you wrote a 0 then you need 1 bit to indicate the empty or full set). If the set is known to have N elements, then the number of bits required for this number will be log₂(256!/(N!*(256-N)!)

Assembly language program (sum the differences of a number in an array)

I have been tasked, with a homework assignment (I'm not going to sugar-coat it), writing a 32-bit assembly program that uses a loop and indexed addressing to calculate the sum of the gaps between successive array elements, which are in non-decreasing order. (Ex: dwarray dword 0,2,5,9,10)
What I don't know how to do is subtract the nth element of an array from the nth-1 element in the array using a loop. If I did, then I would store the result in a different register and keep adding the results into that register until the last element has been reached. I'm only looking to be pointed in the right direction (I'm not looking for the answer). Does anyone have any suggestions?
Since you will be using a loop you'll need a loop counter equal to the number of elements in the array minus 1.
Convenient instructions would be add eax,[ebx+ecx*4] and sub eax,[ebx+ecx*4-4]

Determine if two arrays are identical up to permutation? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Check if array B is a permutation of A
Is there a way to tell if two arrays of numbers (which can contain positives, negatives or repeats) are permutations of each other in O(n) time complexity and O(1) space complexity? I could not solve it because of tight space constraints.
If the numbers are integers - in-place radix sort can give you O(nlogk) time, where k is the range of the numbers, and n is the number of elements.
Note that the algorithm requires O(logk) space, for the stack trace of recursive calls.
If you can bound k to a constant (2^64 for example) - you get O(n) time with O(1) space.
After sorting - you can simply iterate on both arrays and check if they are identical.
It can be done if you have a hard limit on the range of the numbers themselves.
Say for example you know that you have two arrays A and B and that the numbers are bound between -128 and +127(8bit signed). You simply have an array of 256 locations. Each number n would map to the location n + 128.
You iterate over both arrays, for array A you would increment the corresponding location, for array B you decrement. Then you check if all locations are 0 or not. If they are, the arrays are permutations, if not, they aren't.
The time complexity is O(n+k). The space complexity is O(k) where k is the range of the numbers. Since k is independent of n, so that's O(n) and O(1) as far as n is concerned and as long as you have a bound on k.
Note also that the time complexity can be further reduced to simply O(n) instead of O(n+k). You simply keep a running total of numbers that have non-zero counts. Every time an increment/decrement would push a count from to something else, you increment the running total. Every time it would be pushed to zero, you decrement the total. At the end, if the total is 0, then all counts are 0.
Edit: Amit's answer probably has a better space complexity though :)
PS: However, this algorithm can be applied if the arrays of numbers are streamed in, so they never actually have to be all kept in memory. So it might have a smaller space complexity than outright sorting if the conditions are right

How to find 0 in an integer array of size 100 ,having 99 elements as 1 and only one element 0 in most efficient way

I need to find the position( or index ) say i of an integer array A of size 100, such that A[i]=0. 99 elements of array A are 1 and only one element is 0. I want the most efficient way solving this problem.(So no one by one element comparison).
Others have already answered the fundamental question - you will have to check all entries, or at least, up until the point where you find the zero. This would be a worst case of 99 comparisons. (Because if the first 99 are ones then you already know that the last entry must be the zero, so you don't need to check it)
The possible flaw in these answers is the assumption that you can only check one entry at a time.
In reality we would probably use direct memory access to compare several integers at once. (e.g. if your "integer" is 32 bits, then processors with SIMD instructions could compare 128 bits at once to see if any entry in a group of 4 values contains the zero - this would make your brute force scan just under 4 times faster. Obviously the smaller the integer, the more entries you could compare at once).
But that isn't the optimal solution. If you can dictate the storage of these values, then you could store the entire "array" as binary bits (0/1 values) in just 100 bits (the easiest would be to use two 64-bit integers (128 bits) and fill the spare 28 bits with 1's) and then you could do a "binary chop" to find the data.
Essentially a "binary chop" works by chopping the data in half. One half will be all 1's, and the other half will have the zero in it. So a single comparison allows you to reject half of the values at once. (You can do a single comparison because half of your array will fit into a 64-bit long, so you can just compare it to 0xffffffffffffffff to see if it is all 1's). You then repeat on the half that contains the zero, chopping it in two again and determining which half holds the zero... and so on. This will always find the zero value in 7 comparisons - much better than comparing all 100 elements individually.
This could be further optimised because once you get down to the level of one or two bytes you could simply look up the byte/word value in a precalculated look-up table to tell you which bit is the zero. This would bring the algorithm down to 4 comparisons and one look-up (in a 64kB table), or 5 comparisons and one look-up (in a 256-byte table).
So we're down to about 5 operations in the worst case.
But if you could dictate the storage of the array, you could just "store" the array by noting down the index of the zero entry. There is no need at all to store all the individual values. This would only take 1 byte of memory to store the state, and this byte would already contain the answer, giving you a cost of just 1 operation (reading the stored value).
You cannot do it better then linear scan - unless the data is sorted or you have some extra data on it. At the very least you need to read all data, since you have no clue where this 0 is hiding.
If it is [sorted] - just access the relevant [minimum] location.
Something tells me that the expected answer is "compare pairs":
while (a[i] == a[i+1]) i += 2;
Although it looks better that the obvious approach, it's still O(n),
Keep track of it as you insert to build the array. Then just access the stored value directly. O(1) with a very small set of constants.
Imagine 100 sea shells, under one is a pearl. There is no more information.
There is really no way to find it faster than trying to turn them all over. The computer can't do any better with the same knowledge. In other words, a linear scan is the best you can do unless you save the position of the zero earlier in the process and just use that.
More trivia than anything else, but if you happen to have a quantum computer this can be done faster than linear.
Grover's algortithm

Resources