Number of times the custom sort function is called - c++

I have a vector of objects v which is sorted with a custom function sortproc:
std::sort(v.begin(), v.end(), sortproc);
Before sorting the array, I would like to know in advance how many times sortproc will be called.
What have I tried? I tried cloning the vector, then sorting the copy and count how many times sortproc is called. I do this by incrementing a counter. Then, after sorting the copy I read the value of the counter and sort the original vector again. This works but is very inefficient because it's doing the whole job twice. Is it possible to do this in a more efficient way?

Almost certainly not. Two obstacles that spring to mind are:
1) the standard doesn't define what algorithm std::sort uses, so portable code cannot know exactly how many comparisons are performed other than just trying it.
2) even if you did know the algorithm, I think that for sensible sorting algorithms figuring out the number of comparisons required can't be any easier than figuring out the number of inversions, which itself has the same complexity as sorting. So you aren't going to get a massively more efficient solution.
The workaround for 2 would be if the sort algorithm was such that the number of comparisons doesn't depend on how close to ordered the data is, only on the size of the data. It's not too difficult to design a sort algorithm with that property. It would probably be less efficient than a "real" sort algorithm, but could well be more efficient than sorting twice.
So just for example in a merge sort, normally when one side of the merge is exhausted you copy the remainder of the other side straight into the destination. If at that point you did a bunch of extra redundant comparisons solely to make up the numbers, then the number of comparisons wouldn't depend on the order of the input. And the number of pointless comparisons would be worst case half the total, so it shouldn't be any worse than sorting twice. This isn't a "fair" comparison with std::sort, though, because merge sort isn't a valid algorithm for std::sort anyway: it uses too much extra memory.
Sorting networks use a fixed number of comparisons too, but are also no good for std::sort because you need to know the number of items to design the network...

Related

Does it matter that the insert hint place which is close the final place is before or after the final place?

I am using the function insert with hint (emplace_hint) in the set/map.
The api doc said that when using hint place it will "begin search the final place from the hint palce and speeding up the process considerably when the actual insertion point is either position or close to it."
I want to know does the close here means before, after or both, and how to effectivly use this feature?
If use lower_bound or upper_bound to find the close place handbefore, it seems not speedup the process.
The bad news...
We call these types map/set, but what we really mean is tree<pair>/tree. The insert operation on a tree is a lower_bound O(log(N)), followed by the operation to actually add the new value. (Normally the tree is an RB tree so adding may involve a "rotation")
By calling lower_bound then inserting, you are simply implementing insert function the hard way. There is no way this could ever be faster. If it was, we would be asking why this wasn't the default implementation.
The good news...
If what you are really asking is ... "How do I go faster than a map". This is easy. There are a couple of choices, depending upon what is slower - access or insertion/deletion, how many elements are stored, how big the key/value types are, or if there are special reasons why key/value are expensive to move, etc.
1) Hash map, implementation in std as unordered_map
This is a technique sometimes called bucket sorting. What you do is supply a function that turns the key into a number. Then you mod the number and use it to look-up into an array of maps. A lot of people mistaken believe means it gives linear access, it doesn't, it is still O(log(N)), just with a smaller N.
The downside is it uses more memory. Obviously the hash function needs to be fast too.
2)
For faster lookup, consider a sorted-vector (sometimes called a flat-map, see boost::flatmap). It is simply a std::vector<pair<key,value>>, just sort'ed. Gloriously simple this structure is much faster than map for lookups. It works because the lower_bound function is also a general algorithm, and is still log(N), but vectors are much more cache friendly. Expect it to go around 4 times faster.
Insertion/deletion are O(N) because you have to memcpy memory around....but, as stated above, insertion requires a lower_bound call, or equivalent, and this is faster with sorted-vectors. By experimentation, I have found that vector is faster than set/map for insertion/deletion for structures of less than 4K, but after that it becomes slower, but this is obviously H/W dependent.
3) Don't insert/delete, use a sorted vector as above, but do not call insert/erase, instead simply push_back to insert. To remove, swap the item with back() and resize. This means the sorting will break everytime you insert/erase, so you need a dirty flag. When you do a look-up, you check the dirty flag and if its set, you sort. The std::sort algorithm is real piece of science, it's awesomely fast. I mean really FAST... The only downside is that it is N*log(N), so for large data sets (1000's of elements, or more) you need multiple inserts/erase to pay off, although not as many as people suspect.
It's also getting complex enough that you probably need a class/template to abstract it.
For fastest insert/delete...
4) The king of all sorting algorithms, is a radix sort. Implementing 3) with a radix-sort gives you O(N) sorting time.
Downside, radix algorithms generally need very large datasets to be worth while, (>10,000 elements typically), which is why they are not normally used. For smaller data-sets you normally find std:sort wins.
Plus, I do not know a standard radix sort implementation, so it means writing your own, or a lot of googling. Typically, radix sorting only supports integer keys (although there is no inherent reason why it can't be extended).
For the hackers...
5) set<float&ft; or map<float,X> implies floating point comparisons. Now a real hack is to use an integer compare on floating-point data (as in alias-cast, cast a float* to int* in the compare function). This works because floating point numbers store the exponent in the MSB, so a larger number has a larger exponent. The only problem is the sign flag, it's the wrong way around, so be aware if you ever iterate over the structure, the positive values are sorted low to high. Negative numbers are sorted high to low, meaning that the map isn't really sorted. If you only have either +ve or -ve numbers this doesn't matter. If you only insert/erase/lookup then the absolute storage order isn't important.
(If you want to know why integer comparison is faster, it's because its more complicated, also often CPU's have separate registers for floating point, and access to those registers is slower).
Also note, that alias-cast'ing sometimes breaks compiler optimisations, depending on compiler you might need to tell the compiler what your doing. You do this using a compiler flag. On GCC this is no_strict_aliasing, Visual Studio on the other hand doesn't care, and should be fine without)
...
and so on, the point is there are lots of ways to beat the "standard" algorithms, because the standard algorithms involve trading-off pro-and-cons, to balance all cases. If you only have one, known case, you can often beat them. But... if you don't have specific knowledge of what it is you are storing, or how many, then trying to beat the std::XXXXX is a suckers game. The standard algorithms are implemented by people who have been doing this for decades, and know what they are doing.
That is why what you trying is silly, if it was that easy, the std::XXXX version would already do it.
This seems to be implementation dependent. So you need to check your library implementation. (I have not checked other revisions).
n3797 Table 102. § 23.2.4.
logarithmic in general, but amortized constant if it
is inserted right before p
The standard says that if you provide the exact insertion point (as given by lower_bound for instance) the map/set will use this and no extra work needs to be done to do the insert, unless special circumstances are met. If you do not provide the precise insertion point it can behave like a regular insert. If you provide an incorrect insertion point it is not allowed to behave worse than a regular insert.
A regular insert finds the insertion point in the map in a very similar fashion to lower_bound. lower_boundis also logarithmic. So if you do lower_bound + insert(hint, element) you are doing the same work as just insert(element).

Efficient way to search and find elements in one vector from the other vector?

I have two std::vector<long>s. One has 5 elements and the other has 100 elements. I want to compare elements from the smaller vector with the larger vector, and if an element is not found in the larger vector I want to push it back into the larger vector. I have my code here:
vector<long> Matvec, MatTempVec;
//assume Matvec has 5 elements and MatTempvec has 100 elements.
vector<long>::iterator It1;
for (auto it = Matvec.begin(); it != Matvec.end(); it++)
{
It1 = find(MatTempVec.begin(), MatTempVec.end(), it);
if (It1 != MatTempVec.end())
MatTempVec.push_back(*it);
}
Suggest me an efficient way for this search and find, other than what I have done above.
First, I hope you either, asking it just hypothetically, to find the "best algorithm" for a problem, or, you are talking about much larger data-sets.
For the amount of data you have, it is not worth thinking about optimizations like this.
In answer to your question:
This really depends of how many constraints you have on your vectors.
If you know they are sorted, this is easy to solve with one iteration over the two vectors.
If you know they are unique, you probably want to use set.
if you know nothing, you may be tempted to still use set, just as temporary data structure, for faster lookup. This may, or may not be faster in real-world, due to locality
As others have commented, I think you're using the wrong tool for the job. It would be better to use a structure that supported uniqueness inherently, like a std::set. Using a vector means the complexity of checking for the existence of a value in your list is O(n) (linearly proportional to the size of the list), while using a std::set would get you O(log(n)) complexity - which is much better - as std::sets are usually based on red/black trees.
If you really insist on doing it with vectors, and they're not sorted, then you're in the worst of all worlds and you'll end up doing a "Cartesian-Product Join" where the number of comparisons you're doing is the product of the number of rows in each set (i.e. 5x100 = 500 in this case). When the vectors are small, that may be acceptable, but as they grow it will quickly kill your performance.
So, one way out of this is to:
Sort your vectors
Perform a sort merge join on the result.
However, be careful in your choice of sorting algorithm too as that can also be expensive and ideally store the sorted result and maintain the vectors in sorted order. If you're re-sorting all the time, that will also kill performance.
(Or, go back to the top of this answer and reconsider your decision to stick with a vector...)

keep std vector/list sorted while insert, or sort all

Lets say I have 30000 objects in my vector/list. Which I add one by one.
I need them sorted.
Is it faster to sort all at once (like std::sort), or keep vector/list sorted while I add object one by one?
vector/list WILL NOT be modified later.
When you are keeping your vector list sorted while inserting elements one by one , you are basically performing an insertion sort, that theoretically runs O(n^2) in worst case. The average case is also quadratic, which makes insertion sort impractical for sorting large arrays.
With your input of ~30000 , it will be better to take all inputs and then sort it with a faster sorting algorithm.
EDIT:
As #Veritas pointed out, We can use faster algorithm to search the position for the element (like binary search). So the whole process will take O(nlg(n)) time.
Though , It may also be pointed that here inserting the elements is also a factor to be taken into account. The worst case for inserting elements takes O(n^2) that is still the overall running time if we want to keep the array sorted.
Sorting after input is still by far the better method rather than keeping it sorted after each iteration.
Keeping the vector sorted during insertion would result in quadratic performance since on average you'll have to shift down approximately half the vector for each item inserted. Sorting once at the end would be n log(n), rather faster.
Depending on your needs it's also possible that set or map may be more appropriate.

Sorting a std::vector which has parts of it sorted (formed by concatenation of sorted vectors)

I have an std::vector as one of the inputs for an API i am exposing.
I know that the user of this API can send a huge vector, but that vector was formed by concatenation of sorted vectors. This means that the vector that I get is formed from a number of sorted vectors.
I need to sort this vector.
I would like to know which sorting algorithm is best suited.
I would prefer an in-place sorting algo like merge or quick as I dont want to take up more memory (the vector is already a huge one).
Also would it be better to change the API interface to accept N sorted vectors and then do the N-way merging myself. I dont want to go with this unless the saving is really huge.
Also while doing N-way merge I would want to do it in-place if possible.
So ideally i would prefer the approach where i use some ready sort algorithm on the big vector (as that would be simpler I feel).
Take a look at std::inplace_merge. You can use mergesort idea and merge each pair, then next pairs, then next… And so on until only one remains.
You can search the vector to find the concatenation points of the smaller vectors. Then by using these iterators you can do a merge one by one.
To find the concatenation points you can look for the first element that violates the sorting criteria from the beginning. And then from that position to the next and so on..
Timsort looks to be just what you need -- it is an adaptive sort that looks for presorted runs in the data, and merges them as it goes. It has worst-case O(nlog n) performance, and I expect it will do much better than that if the runs (presorted subarrays) are long.

std::set<T>::insert, duplicate elements

What would be an efficient implementation for a std::set insert member function? Because the data structure sorts elements based on std::less (operator < needs to be defined for the element type), it is conceptually easy to detect a duplicate.
How does it actually work internally? Does it make use of the red-back tree data structure (a mentioned implementation detail in the book of Josuttis)?
Implementations of the standard data structures may vary...
I have a problem where I am forced to have a (generally speaking) sets of integers which should be unique. The length of the sets varies so I am in need of dynamical data structure (based on my narrow knowledge, this narrows things down to list, set). The elements do not necessarily need to be sorted, but there may be no duplicates. Since the candidate sets always have a lot of duplicates (sets are small, up to 64 elements), will trying to insert duplicates into std::set with the insert member function cause a lot of overhead compared to std::list and another algorithm that may not resort to having the elements sorted?
Additional: the output set has a fixed size of 27 elements. Sorry, I forgot this... this works for a special case of the problem. For other cases, the length is arbitrary (lower than the input set).
If you're creating the entire set all at once, you could try using std::vector to hold the elements, std::sort to sort them, and std::unique to prune out the duplicates.
The complexity of std::set::insert is O(log n), or amortized O(1) if you use the "positional" insert and get the position correct (see e.g. http://cplusplus.com/reference/stl/set/insert/).
The underlying mechanism is implementation-dependent. It's often a red-black tree, but this is not mandated. You should look at the source code for your favourite implementation to find out what it's doing.
For small sets, it's possible that e.g. a simple linear search on a vector will be cheaper, due to spatial locality. But the insert itself will require all the following elements to be copied. The only way to know for sure is to profile each option.
When you only have 64 possible values known ahead of time, just take a bit field and flip on the bits for the elements actually seen. That works in n+O(1) steps, and you can't get less than that.
Inserting into a std::set of size m takes O(log(m)) time and comparisons, meaning that using an std::set for this purpose will cost O(n*log(n)) and I wouldn't be surprised if the constant were larger than for simply sorting the input (which requires additional space) and then discarding duplicates.
Doing the same thing with an std::list would take O(n^2) average time, because finding the insertion place in a list needs O(n).
Inserting one element at a time into an std::vector would also take O(n^2) average time – finding the insertion place is doable in O(log(m)), but elements need to me moved to make room. If the number of elements in the final result is much smaller than the input, that drops down to O(n*log(n)), with close to no space overhead.
If you have a C++11 compiler or use boost, you could also use a hash table. I'm not sure about the insertion characteristics, but if the number of elements in the result is small compared to the input size, you'd only need O(n) time – and unlike the bit field, you don't need to know the potential elements or the size of the result a priori (although knowing the size helps, since you can avoid rehashing).