Maintain a std::vector parallel to std::map - c++

Recently, when I need to iterate through a std::map I usually build a std::vector from the map, since the complexity to access an element is (log N) (indeed, only when I need to access elements by a custom key).
So, I end up maintaining a std::vector just for iterating all my elements, (since its complexity is constant O(1)) and a std::map for specific retrieving (since its complexity is O(log n) when iterating).
Is this a correct way to do it, or should I just go with the std::map and forget about the std::vector (you know, for this specific case).
Thank you.

You should forget about the vector unless profiling tells you you need it. Iterating in a map is NOT O(log2N) per iterator increment... it only needs to find the next element by traversing the minimum path from the current element in the balanced binary tree... that's often only following a link or two, though the worst-case step of moving from the last left-side node to the first right-side node requires 2*(log2(N)-1) movements if it just uses a generic approach.
To visualise this, consider nodes in the map below - they're always in sorted order, and here I'm assuming the data elements happen to be incrementing integers as we can then easily refer to the nodes using their values:
8
/ \
4 12
/ \ / \
2 6 10 14
/ \ / \ / \ / \
1 3 5 7 9 11 13 15
As you traverse, your iterator may have to start at the root "8" and traverse the left hand branches to "1", but then it moves up a single link to 2, then down a single link to "3", before having to pop up a couple links to "4" and down a couple to "5". Clearly - most of the time it's just following 1 or 2 links, with longer paths increasingly rare: if we list it all out:
6 links: once/x1: 7-6-4-8-12-19-9
3 links: 8-1
2 links: x4: 3-2-4, 4-6-5, 11-10-12, 12-14-13
1 link: x8: 1-2, 2-3, 5-6, 6-7, 9-10, 10-11, 13-14, 14-15
Total is 8*1 + 2*4 + 3*1 + 6*1 = 25... 25 links traversed to iterate 15 elements.
That sequence can be generalised for arbitrary N as: N/2 + 4N/8 + 6N/16 + 10N/32 + 12N/128 + 14N/256... 2iN/2i+1.... if we simplify the fractions and divide by N we get a series:
1/2, 1/2, 3/8, 1/4, 5/32, 3/32, 7/128, ...
There are lots of proofs here that it converses to 2N, i.e. the average number of links per increment of the iterator converges to 2 with large N, and as 2 is a constant factor we can still say incrementing the iterator is O(1).

Related

how to add a number to a range of elements in vector very fast

How do I add a constant k to a range of elements[a,b] in a vector, really fast!!
The code I've written works well for relatively shorter inputs for q number of queries:
long int a,b,k,n;
vector<long int> v(n+1,0);
for( long int i=0; i<q ;i++)
{
cin>>a>>b>>k;
for(int j=a-1; j<=b-1; j++)
{
v[j]+=k;
}
}
But this is clearly a very slow solution!! The code takes longer for larger values of k and range
for example [a,b]=6581237, 9872072 and k=87106 will take a comparitively longer time to compute.
So is there a faster way to get the job done with a lower time??
EDIT: My method gives a timeout for for larger number of queries(10^7) and when ranges reach of the order of 10^7.
As far as I can tell, you have Q queries and for each query, you need to add a number to each element in a range of an array. That explains why you think doing so on a vector with a few million elements will take too long, since doing it once would take less than a second.
What you need is a Fenwick tree, or a segment tree with lazy propagation, which allows you to update a range of elements or query the value of an element in logarithmic time. A segment tree can also perform range queries in logarithmic time.
A Fenwick tree by itself can perform point updates and prefix sum queries, but we can make it do range updates and point queries using the following:
//Add val to every element in [left, right]:
update(left, val);
update(right + 1, -val);
//Query the value at index x:
query(x);
For the segment tree solution, you're going to need lazy propagation to perform range updates.
I think the Wikipedia pages might be a little confusing if you're learning them for the first time, so here are some tutorials from hackerearth.com:
Fenwick tree: https://www.hackerearth.com/practice/data-structures/advanced-data-structures/fenwick-binary-indexed-trees/tutorial/
Segment tree: https://www.hackerearth.com/practice/data-structures/advanced-data-structures/segment-trees/tutorial/
How many overlapping intervals do you have/expect?
If ranges are quite large, there are quite some chances that they do overlap. For all of these overlaps, you calculate the addition multiple times. Imagine following situation:
[10; 100] + 20
[30; 50] - 10
[40; 120] + 10
You might resolve the overlaps such that you have only one addition per element (of course, you need to query the ranges before doing any calculations then, storing them in some appropriate data structure):
[ 10; 30] + 20
[ 30; 40] + 10
[ 40; 50] + 20
[ 50; 100] + 30
[100; 120] + 10
As now having independent ranges, you might additionally parallelise the additions (e. g. by placing the ranges in a queue and let each thread take one from as soon as it has finished its previous one – queue needs to be protected against race conditions).

Finding Maximum of an interval in array using binary trees

I'm studying Binary trees! and i have a problem in this Homework.
I have to use binary trees to solve this problem
here is the problem :
You are given a list of integers. You then need to answer a number of questions of the form: "What is the maximum value of the elements of the list content between the A index and the index B?".
example :
INPUT :
10
2 4 3 5 7 19 3 8 6 7
4
1 5
3 6
8 10
3 9
OUTPUT:
7
19
8
19
TIME LIMITS AND MEMORY (Language: C + +)
Time: 0.5s on a 1GHz machine.
Memory: 16000 KB
CONSTRAINTS
1 <= N <= 100000, where N is the number of elements in the list.
1 <= A, B <= N, where A, B are the limits of a range.
1 <= I <= 10 000, where I is the number of intervals.
Please do not give me the solution just a hint !
Thanks so much !
As already discussed in the comments, to make things simple, you can add entries to the array to make its size a power of two, so the binary tree has the same depth for all leaves. It doesn't really matter what elements you add to this list, as you won't use these computed values in the actual algorithm.
In the binary tree, you have to compute the maxima in a bottom-up manner. These values then tell you the maximum of the whole range these nodes are representing; this is the major idea of the tree.
What remains is splitting a query into such tree nodes, so they represent the original interval using less nodes than the size of the interval. Figure out "the pattern" of the intervals the tree nodes represent. Then figure out a way to split the input interval into as few nodes as possible. Maybe start with the trivial solution: just split the input in leave nodes, i.e. single elements. Then figure out how you can "combine" multiple elements from the interval using inner nodes from the tree. Find an algorithm doing this for you by not using the tree (since this would require a linear time in the number of elements, but the whole idea of the tree is to make it logarithmic).
Write some code which works with an interval of size 0. It will be very simple.
Then write some for a interval of size 1. It will still be simple.
Then write some for an interval of size 2. It may need a comparison. It will still be simple.
Then write some for an interval of size 3. It may involve a choice of which interval of size 2 to compare. This isn't too hard.
Once you've done this, it should be easy to make it work with any interval size.
An array would be the best data structure for this problem.
But given you need to use a binary tree, I would store (index, value) in the binary
tree and key on index.

Algorithm to find min and max in a given set

A large array array[n] of integers is given as input. Two index values are given - start,end. It is desired to find very quickly - min & max in the set [start,end] (inclusive) and max in the rest of array (excluding [start,end]).
eg-
array - 3 4 2 2 1 3 12 5 7 9 7 10 1 5 2 3 1 1
start,end - 2,7
min,max in [2,7] -- 1,12
max in rest - 10
I cannot think of anything better than linear. But this is not good enough as n is of order 10^5 and the number of such find operations is also of the same order.
Any help would be highly appreciated.
The way I understand your question is that you want to do some preprocessing on a fixed array that then makes your find max operation very fast.
This answers describes an approach that does O(nlogn) preprocessing work, followed by O(1) work for each query.
Preprocessing O(nlogn)
The idea is to prepare two 2d arrays BIG[a,k] and SMALL[a,k] where
1. BIG[a,k] is the max of the 2^k elements starting at a
2. SMALL[a,k] is the min of the 2^k elements starting at a
You can compute this arrays in a recursive way by starting at k==0 and then building up the value for each higher element by combining two previous elements together.
BIG[a,k] = max(BIG[a,k-1] , BIG[a+2^(k-1),k-1])
SMALL[a,k] = min(SMALL[a,k-1] , SMALL[a+2^(k-1),k-1])
Lookup O(1) per query
You are then able to instantly find the max and min for any range by combining 2 preprepared answers.
Suppose you want to find the max for elements from 100 to 133.
You already know the max of 32 elements 100 to 131 (in BIG[100,5]) and also the max of 32 elements from 102 to 133 (in BIG[102,5]) so you can find the largest of these to get the answer.
The same logic applies for the minimum. You can always find two overlapping prepared answers that will combine to give the answer you need.
You're asking for a data structure that will answer min and max queries for intervals on an array quickly.
You want to build two segment trees on your input array; one for answering interval minimum queries and one for answering interval maximum queries. This takes linear preprocessing, linear extra space, and allows queries to take logarithmic time.
I am afraid, that there is no faster way. Your data is completly random, and in that way, you have to go through every value.
Even sorting wont help you, because its at best O(n log n), so its slower. You cant use bisection method, because data are not sorted. If you start building data structures (like heap), it will again be O(n log n) at the best.
If the array is very large, then split it into partitions and use threads to do a linear check of each partition. Then do min/max with the results from the threads.
Searching for min and max in an unsorted array can only be optimized by taking two values at a time and comparing them to each other first:
register int min, max, i;
min = max = array[0] ;
for(i = 1; i + 1 < length; i += 2)
{
if(array[i] < array[i+1])
{
if(min > array[i]) min = array[i];
if(max < array[i+1]) max = array[i+1];
}
else
{
if(min > array[i+1]) min = array[i];
if(max < array[i]) max = array[i+1];
}
}
if(i < length)
if(min > array[i]) min = array[i];
else if(max < array[i]) max = array[i];
But I don't believe it's actually faster. Consider writing it in assembly.
EDIT:
When comparing strings, this algorithm could make the difference!
If you kinda know the min you can test from x to min if the value exists in the array. If you kinda know the max, you can test (backwards) from y to max, if the value exists in array, you found max.
For example, from your array, I will assume you have only positive integers.:
array - 3 4 2 2 1 3 12 5 7 9 7 10 1 5 2 3 1 1
You set x to be 0, test if 0 exists, doesn't, you then change it to 1, you find 1. there is your min.
You set y to be 15 (arbitrary large number): exists? no. set to 14. exists? no, set to 13. exists? no. set to 12. exists? yes! there is your max! I just made 4 comparisons.
If y exists from the first try, you might have tested a value INSIDE the array. So you test it again with y + length / 2. Assume you found the center of the array, so decal it a bit. If again you found the value from the first try, it might be within the array.
If you have negative and/or float values, this technique does not work :)
Of course it is not possible to have sub-linear algorithm (as far as I know) to search the way you want. However, you can achieve sub-linear time is some cases by storing fixed ranges of min-max and with some knowledge of the range you can improve search time.
e.g. if you know that 'most' of the time range of search will be say 10 then you can store min-max of 10/2 = 5 elements separately and index those ranges. During search you have to find the superset of ranges that can subsume search-range.
e.g. in the example
array - 3 4 2 2 1 3 12 5 7 9 7 10 1 5 2 3 1 1
start,end - 2,7
min,max in [2,7] -- 1,12
if you 'know' that most of the time search range would be 5 elements then, you can index the min-max beforehand like: since 5/2 = 2,
0-1 min-max (3,4)
2-3 min-max (2,2)
4-5 min-max (1,3)
6-7 min-max (5,12)
...
I think, this method will work better when ranges are large so that storing min-max avoids some searches.
To search min-max [2-7] you have to search the stored indexes like: 2/2 = 1 to 7/2 = 3,
then min of mins(2,1,5) will give you the minimum (1) and max of maxes (2,3,12) will give you the maximum(12). In case of overlap you will have to search only the corner indexes (linearly). Still it could avoid several searches I think.
It is possible that this algorithm is slower than linear search (because linear search has a very good locality of reference) so I would advise you to measure them first.
Linear is the best you can do, and its relatively easy to prove it.
Assume an infinite amount instantaneous memory storage and costless access, just so we can ignore them.
Furthermore, we'll assume away your task of finding min/max in a substring. We will think of them both as essentially the exact same mechanical problem. One just magically keeping track of the numbers smaller than other numbers in a comparison, and one magically keeping track of the numbers bigger than in a comparison. This action is assumed to be costless.
Lets then assume away the min/max of the sub-array problem, because its just the same problem as the min/max of any array, and we'll magically assume that it is solved and as part of our general action of finding the max in the bigger array. We can do this by assuming that the biggest number in the entire array is in fact the first number we look at by some magical fluke, and it is also the biggest number in the sub-array, and also happens to be the smallest number in the sub-array, but we just don't happen to know how lucky we are. How can we find out?
The least work we have to do is one comparison between it and every other number in the array to prove it is the biggest/smallest. This is the only action we are assuming has a cost.
How many comparisons do we have to do? We'll let N be the length of the array, and the total number of operations for any length N is N - 1. As we add elements to the array, the number of comparisons scales at the same rate even if all of our widely outrageous assumptions held true.
So we've arrived at the point where N is both the length of the array, and the determinant of the increasing cost of the best possible operation in our wildly unrealistic best case scenario.
Your operation scales with N in the best case scenario. I'm sorry.
/sorting the inputs must be more expensive than this minimal operation, so it would only be applicable if you were doing the operation multiple times, and had no way of storing the actual results, which doesn't seem likely, because 10^5 answers is not exactly taxing.
//multithreading and the like is all well and good too, just assume away any cost of doing so, and divide N by the number of threads. The best algorithm possible still scales linearly however.
///I'm guessing it would in fact have to be a particularly curious phenomenon for anything to ever scale better than linearly without assuming things about the data...stackoverflowers?

The amortized complexity of std::next_permutation?

I just read this other question about the complexity of next_permutation and while I'm satisfied with the response (O(n)), it seems like the algorithm might have a nice amortized analysis that shows a lower complexity. Does anyone know of such an analysis?
So looks like I'm going to be answering my own question in the affirmative - yes, next_permutation runs in O(1) amortized time.
Before I go into a formal proof of this, here's a quick refresher on how the algorithm works. First, it scans backwards from the end of the range toward the beginning, identifying the longest contiguous decreasing subsequence in the range that ends at the last element. For example, in 0 3 4 2 1, the algorithm would identify 4 2 1 as this subsequence. Next, it looks at the element right before this subsequence (in the above example, 3), then finds the smallest element in the subsequence larger than it (in the above example, 4). Then, it exchanges the positions of those two elements and then reverses the identified sequence. So, if we started with 0 3 4 2 1, we'd swap the 3 and 4 to yield 0 4 3 2 1, and would then reverse the last three elements to yield 0 4 1 2 3.
To show that this algorithm runs in amortized O(1), we'll use the potential method. Define Φ to be three times the length of the longest contiguously decreasing subsequence at the end of the sequence. In this analysis, we will assume that all the elements are distinct. Given this, let's think about the runtime of this algorithm. Suppose that we scan backwards from the end of the sequence and find that the last m elements are part of the decreasing sequence. This requires m + 1 comparisons. Next, we find, of the elements of that sequence, which one is the smallest larger than the element preceding this sequence. This takes in the worst case time proportional to the length of the decreasing sequence using a linear scan for another m comparisons. Swapping the elements takes, say, 1 credit's worth of time, and reversing the sequence then requires at most m more operations. Thus the real runtime of this step is roughly 3m + 1. However, we have to factor in the change in potential. After we reverse this sequence of length m, we end up reducing the length of the longest decreasing sequence at the end of the range to be length 1, because reversing the decreasing sequence at the end makes the last elements of the range sorted in ascending order. This means that our potential changed from Φ = 3m to Φ' = 3 * 1 = 3. Consequently, the net drop in potential is 3 - 3m, so our net amortized time is 3m + 1 + (3 - 3m) = 4 = O(1).
In the preceding analysis I made the simplifying assumption that all the values are unique. To the best of my knowledge, this assumption is necessary in order for this proof to work. I'm going to think this over and see if the proof can be modified to work in the case where the elements can contain duplicates, and I'll post an edit to this answer once I've worked through the details.
I am not really sure of the exact implementation of std::next_permutation, but if it is the same as Narayana Pandita's algorithm as desribed in the wiki here: http://en.wikipedia.org/wiki/Permutation#Systematic_generation_of_all_permutations,
assuming the elements are distinct, looks like it is O(1) amortized! (Of course, there might be errors in the below)
Let us count the total number of swaps done.
We get the recurrence relation
T(n+1) = (n+1)T(n) + Θ(n2)
(n+1)T(n) comes from fixing the first element and doing the swaps for the remaining n.
Θ(n2) comes from changing the first element. At the point we change the first element, we do Θ(n) swaps. Do that n times, you get Θ(n2).
Now let X(n) = T(n)/n!
Then we get
X(n+1) = X(n) + Θ(n2)/(n+1)!
i.e there is some constant C such that
X(n+1) <= X(n) + Cn2/(n+1)!
Writing down n such inequalities gives us
X(n+1) - X(n) <= Cn2/(n+1)!
X(n) - X(n-1) <= C(n-1)2/(n)!
X(n-1) - X(n-2) <= C(n-2)2/(n-1)!
...
X(2) - X(1) <= C12/(1+1)!
Adding these up gives us X(n+1) - X(1) <= C(\sum j = 1 to n (j^2)/(j+1)!).
Since the infinite series \sum j = 1 to infinity j^2/(j+1)! converges to C', say, we get X(n+1) - X(1) <= CC'
Remember that X(n) counts the average number of swaps needed (T(n)/n!)
Thus the average number of swaps is O(1).
Since finding the elements to swap is linear with the number of swaps, it is O(1) amortized even if you take other operations into consideration.
Here n stands for the count of elements in the container, not the total count of possible permutations. The algorithm must iterate through an order of all elements at each call; it takes a pair of bidirectional iterators, which implies that to get to one element the algorithm must first visit the one before it (unless its the first or last element). A bidirectional iterator allows iterating backwards, so the algorithm can (must, in fact) perform half as many swaps as there are elements. I believe the standard could offer an overload for a forward iterator, which would support dumber iterators at the cost of n swaps rather than half n swaps. But alas, it didn't.
Of course, for n possible permutations the algorithm operates in O(1).

Ideas for specific data structure in c++

I need to do some task.
There are numbers give in two rows and they act like pairs of integers (a, b). I have to find the maximum 5 numbers of the a-row and then select the max of those 5 but this time from the b-row. Ex:
1 4
5 2
3 3
7 5
6 6
2 9
3 1
In this example, the pair i need is (6,6) because 6 (a) is in the top 5 of the a[i] numbers and 6 (b) is the maximum in the b section of those 5 pairs.
I was thinking of doing this with vectors and my own defined structures, also use some temp arrays but i don't know if that's the right thing to do maybe there is simpler way to do this.
Any ideas ?
EDIT: I also need the index number of the pair (in the case that is 5, it's the fifth pair i.e).
A priority queue holding pairs that does its order evaluations based on the first element of the pair would be appropriate. You could insert all the pairs and then extract the top 5. Then just iterate on that list of pairs looking for the max of the second element of each pair.
edit
I should say that it is a decent solution only if you can accept a runtime on the order of O(n * lg n)
Alternate approaches:
Push triples (first, second, index) into a vector and then std::partial_sort the first 5 items using a descending order functor on the first element. Then use std::max_element with a second functor to find the max of the second element, and grab its index. If I'm reading the complexity of partial_sort correctly this should run in linear time (O(n)) because we're always sorting a max of 5 elements rather than O(n*log n).
Similarly, have the vector only contain pairs and sort a second vector containing indexes into the first one.