When do you call stable_sort() on scalars? - c++

Is it ever good to call stable_sort instead of sort on scalar types (i.e. int, long, etc.) with the default comparator?
If so, when should you do this?
If not, then why don't standard libraries just forward such calls to sort? Wouldn't that be much faster?

Stable sorts are really only useful when the items you are sorting have satellite information.
From CLRS (Introduction to Algorithms, 3rd Ed.):
"In practice, the numbers to be sorted are rarely isolated values. Each is usually part
of a collection of data called a record. Each record contains a key, which is the
value to be sorted. The remainder of the record consists of satellite data, which are
usually carried around with the key. In practice, when a sorting algorithm permutes
the keys, it must permute the satellite data as well."
When a sort is stable, it means that ties are broken in the sorted array by the items' original ordering. If you are only sorting int and long types, you don't need a stable sort.

There should be no difference (maybe with exception of things like -0.0 and 0.0). However I do not think there is any need to forward such calls, because std::sort or std::stable_sort should not know what they are sorting, so long as the comparison operation compiles. These functions don't need to be too smart.

With the default comparator specifically (implying the natural strict ordering)? I don't see any use for stable sorting on scalars in that case. Stable sorting can't provide any additional benefits in situations when equivalent values (according to the comparator) are indistinguishable. (Although #Andrey Tuganov in his answer makes an interesting and relevant remark about negative zeros).
Nevertheless stable sorting on scalars might be useful when the ordering criterion is weaker than the natural strict ordering. For example, you can write a comparison predicate that will say that any odd number is greater than any even number. In that case the resultant ordering will simply partition the array into contiguous blocks of even and odd numbers (in that order). If you are interested in keeping the relative order of these numbers unchanged, you need stable sorting algorithm.

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).

Number of times the custom sort function is called

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...

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).

Multiset without Compare?

I want to use multiset to count some custom defined keys. The keys are not comparable numerically, comparing two keys does not mean anything, but their equality can be checked.
I see that multiset template wants a Compare to order the multiset. The order is not important to me, only the counts are important. If I omit Compare completely what happens? Does multiset work without any problems for my custom keys? If I cannot use std::multiset what are my alternatives?
If you can only compare keys for equality then you cannot use std::multiset. For associative containers your key type must have a strict weak ordering imposed by a comparison operation.
The strict weak ordering doesn't necessarily have to be numerical.
[For use in an associative container, you don't actually need an equality comparison. Key equivalence is determined by !compare(a, b) && !compare(b, a).]
If you really can't define an ordering for your keys then your only option is to use an sequence container of key-value pairs and use an linear search for lookup. Needless to say this will be less efficient for set like operations than a multiset so you should probably try hard to create an ordering if at all possible.
You cannot use std::multiset if you don't have a strict weak ordering. Your options are:
Impose a strict-weak ordering on your data. If your key is a "linear" data structure, it is usually a good idea to compare it lexicographically.
Use an unordered container equivalent, e.g., boost::unordered_multiset. For that, you will need to make your custom data-type hash-able, which is often-times easier than imposing some kind of order.
If you omit the Compare completely, it will get the default value, which is less (which gives the result of the < operator applied to your key) - which may or may not even compile for your key.
The reason for having an ordering is that it allows the implementation to look up elements more quickly by their key (when inserting, deleting etc), To understand why, imagine looking words up in a dictionary. Traditional dictionaries use alphabetical order, which makes words easy to look up. If you were preparing a dictionary for a language that isn't easily ordered - say a pictographic language - then either it would be very hard to find words in it at all (you'd have to search the whole dictionary), or you'd try to find a logical way to order them (e.g. by putting all the pictures that can be drawn with one pen stroke first, then two lines, etc...) - because even if this order was completely arbitrary, it would make finding entries in the dictionary far more efficient.
Similarly, even if your keys don't need to be ordered for your own purposes, and don't have any natural order, you can usually define an ordering that is good enough to address these concerns. The ordering must be transitive (if a<b and b<c then a<c), and strict (never return true for a<a), asymmetric (a<b and b>a never both true). Ideally it should order all elements (if a & b are different then either a<b or b<a), though you can get away with that not being true (ie a strict weak ordering) - though that's rather technical.
Indeed, perhaps the most obvious use for it is the rare case where it is completely impossible to order the items - in which case you can supply a comparison operator which always returns false. This will very likely result in poor performance, but will at least function correctly.
So you have two important criteria which you listed.
You don't care about order
comparison of keys do not mean anything
and one assumed,
the fact that you are using multiset implies that there are many instances
So, why not use std::vector or std::deque or std::list? then you can take advantage of the various algorithms that can use the equality check (such as count_if etc.)

What is the difference between set and hashset in C++ STL?

When should I choose one over the other?
Are there any pointers that you would recommend for using the right STL containers?
hash_set is an extension that is not part of the C++ standard. Lookups should be O(1) rather than O(log n) for set, so it will be faster in most circumstances.
Another difference will be seen when you iterate through the containers. set will deliver the contents in sorted order, while hash_set will be essentially random (Thanks Lou Franco).
Edit: The C++11 update to the C++ standard introduced unordered_set which should be preferred instead of hash_set. The performance will be similar and is guaranteed by the standard. The "unordered" in the name stresses that iterating it will produce results in no particular order.
stl::set is implemented as a binary search tree.
hashset is implemented as a hash table.
The main issue here is that many people use stl::set thinking it is a hash table with look-up of O(1), which it isn't, and doesn't have. It really has O(log(n)) for look-ups. Other than that, read about binary trees vs hash tables to get a better idea of the data structures.
Another thing to keep in mind is that with hash_set you have to provide the hash function, whereas a set only requires a comparison function ('<') which is easier to define (and predefined for native types).
I don't think anyone has answered the other part of the question yet.
The reason to use hash_set or unordered_set is the usually O(1) lookup time. I say usually because every so often, depending on implementation, a hash may have to be copied to a larger hash array, or a hash bucket may end up containing thousands of entries.
The reason to use a set is if you often need the largest or smallest member of a set. A hash has no order so there is no quick way to find the smallest item. A tree has order, so largest or smallest is very quick. O(log n) for a simple tree, O(1) if it holds pointers to the ends.
A hash_set would be implemented by a hash table, which has mostly O(1) operations, whereas a set is implemented by a tree of some sort (AVL, red black, etc.) which have O(log n) operations, but are in sorted order.
Edit: I had written that trees are O(n). That's completely wrong.