Insertion sort issues? - c++

I'm just now trying out different sorting algorithms to find out how they work.
I'm looking at this one:
template< typename Iterator >
void insertion_sort( Iterator First, Iterator Last )
{
Iterator min = First;
for( Iterator i = First + 1; i < Last; ++i )
if ( *i < *min )
min = i;
std::iter_swap( First, min );
while( ++First < Last )
for( Iterator j = First; *j < *(j - 1); --j )
std::iter_swap( (j - 1), j );
}
It's the Insertion Sort and it sorts them from smallest to largest, however I have 2 issues:
Reversing any comparison sign doesn't change the sort order to descending.
When implementing it with my own container, it never sorts the last element. Maybe I didn't get how Begin and End should work for a container? This is how I make them:
If I have a dynamic array container that has an unsigned int size and a T* data, Begin returns an iterator that has a pointer to data[0] and End returns an iterator with a pointer to data[size - 1]. If I make end to instead return data[size], it works fine, however if the size is equal to the allocated capacity, that would overflow the buffer. So the presented insertion sort algorithm is incorrect then? I got it from this site:
http://en.wikibooks.org/wiki/Algorithm_Implementation/Sorting/Insertion_sort#C.2FC.2B.2B

About question 1: I think it should work if you reverse all comparison signs that involve dereferenced iterators, i.e., replace
if ( *i < *min )
by
if ( *i > *min )
(one might also replace the name 'min' by 'max' then to avoid confusion), and
for( Iterator j = First; *j < *(j - 1); --j )
by
for( Iterator j = First; *j > *(j - 1); --j )
These are the comparisons that compare the actual data.
About question 2: usually, an 'end' iterator refers to the position behind the last actual item that you want to sort. Standard algorithms (such as yours) will never dereference this iterator, so no overflow will occur.

The iterators pointing to an end() are one past the last element, so that you'd usually loop through them like:
for(Iterator it = begin(); it != end(); ++it) ...
Your iterator implementation thus stops one before that last and is the culprit.
It might be a good idea not to test everything at once, i.e. a custom algorithm with custom iterators. You can use a stl container to test the algorithm and an stl algorithm to test your container.

Related

map find() function if the wanted key is in the last position

I am a C++ beginner. I know that find() is used to search for a certain key. This function returns an iterator to the element if the element is found, else it returns an iterator pointing to the last position of the. map i.e map.end().
I read from websites that
if(it == mp.end())
cout << "Key-value pair not present in map" ;
else
cout << "Key-value pair present : "
What if the found key is in the end postition? How can it still work? Key is sorted in a certain order and I think the iterator traverses the sorted key to find the one we want. (is it correct?)
The result of all .end() in the stl is beyond the valid values. So end() will never be valid.
int arr[10];
// arr has valid indices 0,1,2,3,...,7,8,9
// arr[10] is not valid.
for( auto i = 0; i < 10; i++ ){
}
std::vector vec;
vec.resize( 10 );
// vec.end() is equivalent to arr[10] - not part of the vector
for( auto it = vec.begin(); vec != vec.end(); vec++ ) {
}
So lets re-write the array in the vector idiom
for( auto i = 0; &arr[i] != &arr[10]; i++ ){
}
Maps are more complicated, they have a different guard mechanism, but an iterator == end() never is valid.
According to cplusplus.com , .end() Returns an iterator pointing to the past-the-end element in the sequence:
It does not point to an element in the container ( the map in your case ), rather points outside of it.

std::max_element for second largest element?

The STL provides std::max_element to find the largest element in an iterable, e.g. like this:
std::vector<float>::const_iterator max =
std::max_element(obj.pt()->begin(), obj.pt()->end());
return std::distance(obj.pt()->begin(), max);
Is there also something to get an iterator for the n-th largest element?
(Note that max_element returns an iterator and this is actually important: Rather than for the value itself, I am looking for the position of the n-th largest element within the iterable.)
max_element() method can be used to get second largest element by passing lambda function which compares the element with the previously found largest element and if it is equal to the largest element then it'll simply skip that element.
auto largest = max_element(vec.begin(), vec.end());
auto secondLargest = max_element(vec.begin(), vec.end(),
[&largest](unsigned long &a, unsigned long &b) {
if (a == *largest) return true;
if (b == *largest) return false;
return a < b;
});
If you are specifically interested in the second-largest element, you can do a simple scan of the array in which most elements require a single comparison:
float second_largest_element(std::vector<float> vec) {
float m2, m1;
/* Check to make sure that vec has at least 2 elements!! */
std::tie(m2, m1) = std::minmax(vec[0], vec[1]);
for (auto it = vec.begin() + 2, limit = vec.end();
it != limit;
++it)
if (*it > m2) std::tie(m2, m1) = std::minmax(*it, m1);
return m2;
}
Getting the index of (or an iterator to) the second largest element is very similar, although std::minmax is less useful. Here's a very sloppy example:
template<typename T>
typename T::iterator second_largest(T& container) {
using iterator = typename T::iterator;
iterator limit = container.end();
iterator it = container.begin();
if (it != limit) {
iterator first = it++;
if (it != limit) {
iterator second = it++;
if (*first < *second) std::swap(first, second);
for (; it != limit; ++it) {
if (*second < *it) {
if (*first < *it) { second = first; first = it; }
else { second = it; }
}
}
return second;
}
return first;
}
return it;
}
You could also consider using std::accumulate to scan the array, although the explicit for loop is not complicated.
As Dyp mentioned in comment, if you are fine to alter the order of elements within your vector you can use std::nth_element as follows. On top if you use find again over vector you will get original position of the nth element from vector. Since nth_element modifies the positions, you have to keep a local copy of it before doing nth_element operation over vector.
2nd largest element:
std::vector<float> orig_vec=obj.pt;
std::nth_element(obj.pt().begin(), obj.pt().begin()+1,
obj.pt().end(), std::greater<float>());
float 2nd= *(obj.pt().begin()+1);
auto it=std::find(orig_vec.begin(), orig_vec.end(), 2nd);
nth largest element:
std::nth_element(obj.pt().begin(), obj.pt().begin()+n-1,
obj.pt().end(), std::greater<float>());
float nth= *(obj.pt().begin()+n-1);
auto it=std::find(orig_vec.begin(), orig_vec.end(), nth)
This is a trivial algorithm to implement in linear time. The naive approach would be to compare the first two values, and select them as the max and second largest values. Then you need to iterate over the other elements comparing each new element with both of them and adjusting your current max and second largest values. For most use cases that is probably more than enough. If you really care about performance (as in you care a lot) you will need to think what values you want to compare to minimize the number of comparisons.
Also note that float (floating point in general) have quirks... you might get funny values if your input contains NaN or infinite values.
It took me a while to find a solution, because I worked with const vector (so I can't use nth_element) and copy would be just wasting (especially, when vector is holding a bigger structures). So I came with this:
// Find 1st max
auto max1 = max_element(vec.begin(), vec.end());
if (max1 != vec.end())
// Use max1
// Find 2nd max. Split the vector into 2 parts, find max and merge results
auto max2Beg = max_element(vec.begin(), max1);
auto max2End = max_element(max1 + 1, vec.end());
auto max2 = max2Beg == max1 ? max2End :
max2End == vec.end() ? max2Beg : max(max2Beg, max2End);
if (max2 != max1 && max2 != vec.end())
// Use max2

C++ iterating with changing vector.size()

I've written some perhaps naive code that is meant to remove elements from a vector that are too similar. The functionality is fine, but I think I may get unexpected results now and then because of the dynamic resizing of the vector.
for (size_t i = 0 ; i < vec.size(); i++) {
for(size_t j = i+1; j < vec.size(); j++) {
if(norm(vec[i]-vec[j]) <= 20 ) {
vec.erase(vec.begin()+j);
}
}
}
Is this safe to do? I'm concerned about i and j correctly adapting as I erase elements.
You need to pay better attention to where your elements are. It might be easier to express this directly in terms of iterators rather than compute iterators via indexes, like this:
for (auto it = vec.begin(); it != vec.end(); ++it)
{
for (auto jt = std::next(it); jt !=; vec.end(); )
{
if (/* condition */)
{
jt = vec.erase(jt);
}
else
{
++jt;
}
}
}
Yes, you are safe here. Since you are using indexes, not iterators, there is nothing to invalidate by erasing an item in the container except the size, and the size would be updated automatically, so we are good here.
One more thing to consider is what effect does erasing an element inside the inner loop has on the stopping condition of the outer loop. There is no problem there either, because j is guaranteed to be strictly greater than i, so j < vec.size() condition of the inner loop will be hit before the i < vec.size() condition of the outer loop, meaning that there would be no unsafe vec[i] access with an invalid index i.
Of course you should increment j after erasing an element to avoid the classic error. An even better approach would be to start walking the vector from the back, but you would need to do so in both loops to make sure that i a valid element is never erased from underneath the outer index of i.

Nested iterators access

I have a question about iterators.The question is:" How can I access ( if it's a nested iterator ) the element in row, that is higher or below.Here's an example what I mean:
for( auto i = graphMatrix.begin();i != graphMatrix.end();i++ )
{
for( auto j = i->begin();j != i->end();j++ )
{
if( *j == 'O' )
{
// here we must analyze an element which is a row higher or lower
}
}
}
Next thing is what I wanted to do ( but it's with vector ):
for( int i = graphMatrix.size();i < graphMatrix.size();i++ )
{
for( int j = graphMatrix.size();j < graphMatrix.size();j++ )
{
if( graphMatrix[i][j] == 'O' )
{
graphMatrix[j][i] == 'X';
}
}
}
I know that vector has fast size function, but to generalize the code, in my mind, it's better to use iterators ( as my mentor said ).So how can I do the same stuff with iterators as with vectors?
Since iterators are non-numeric, they are not well-suited to this problem.
You can write complex, confusing and possibly costly code with std::distance and std::advance, performing "pointer arithmetic" on your iterators... or you can stick with your numeric loop counters approach, which is precisely what I'd do. Especially seeing as you're using vectors, which have constant-time (and, let's face it, immediate) access to arbitrary elements in arbitrary positions.
If you're wondering why, in this case, iterators are suddenly not the "better" mechanism for iteration that you've been taught they are: it's because one must use the correct tool for the job, and no technology is the correct tool for all jobs.
to get the position of you vector from the iterator with std::distance:
for( auto i = graphMatrix.begin();i != graphMatrix.end();i++ )
{
for( auto j = i->begin();j != i->end();j++ )
{
int x = std::distance(graphMatrix.begin(),i);
int y = std::distance(i->begin(),j);
graphMatrix[x][y] = 'x';
}
}

C++ list iterator arithmetic?

I'm trying to create a set of loops with iterators and I'm having trouble with some iterator arithmetic (that I thought was possible but is not working).
Below is some code:
for (list<Term>::iterator itr = final.begin(); itr != final.end(); itr++) {
for(list<Term>::iterator j = itr + 1; j != final.end(); j++) {
cout << itr->term << " " << j->term;
if(itr->term == j->term) {
//Do stuff
}
}
}
What I am trying to do is have j start at the next place in the queue along from itr. The reason for this is I don't want to check the first item against itself. The error itself comes from the part in the code where I have specified itr + 1. Now I was sure with pointers you could do arithmetic like this, why is it not working with the list iterator (which is essentially the same thing?)
The error I am getting from my IDE is as follows: main.cpp:237:48: error: no match for ‘operator+’ in ‘itr + 1’. Again I thought you could do this sort of arithmetic on iterators so I'm not really sure what to do to make this work, is there an alternate implementation I could try?
list iterators are not random access so you cannot do + with them. They are bidirectional iterators so the only movement operations you can do are -- and ++. You can either make a copy and use ++ on it, or make a copy and std::advance(it, 1).
For C++11 there is also std::next which gives you it + 1, without you having to explicitly make a named copy like you do with the others.
list has bidirectional iterators, that doesn't support operator +. You can use std::advance, or std::next in C++11.
for (list<Term>::iterator j = next(itr); j != final.end(); ++j)
or
list<Term>::iterator j = itr;
advance(j, 1); // or ++j
for (; j != final.end(); ++j)