Sorting does not work

Asked

Viewed 110 times

2

I had to implement my own Sort, using Selection Sort. However, the simple code (I analyzed several times, and for me it is correct) gives strange results.

template <typename T> void swap(T& var, T& var1)
{
    T temp = var;
    var = var1;
    var1 = temp;
}
template <typename T> void selection_sort(T* begin, T* end, unsigned pos = 0) //1 3 5 2 4; tamanho 5
{
    if(begin != end)
    {
        for(int i = pos+1; i < (end - begin) + pos; i++)
        {
            if(begin[pos] > begin[i]) swap(begin[pos], begin[i]);
        }
        selection_sort(begin+1, end, pos+1);
    }
    else return;
}
//resultado 1 3 0 5 0

What’s wrong? What should be done to fix it?

2 answers

1

Error is on startup i, where is pos+1 it’s just pos.

template <typename T> void selection_sort(T* begin, T* end, unsigned pos = 0u) 
{
    if(begin != end)
    {
        for(int i = pos; i < (end - begin) + pos; i++)
        {
            if(begin[pos] > begin[i]) std::swap(begin[pos], begin[i]);
        }
        selection_sort(begin + 1, end, pos);
    }
}

Another thing, you don’t need to reset swap(), can use std::swap() instead.

Code I Tested


Or you can stop using the variable pos that does not affect the algorithm:

template <typename T> void selection_sort(T* begin, T* end) 
{
    if(begin != end)
    {
        for(int i = 0; i < (end - begin); i++)
        {
            if(begin[0] > begin[i]) std::swap(begin[0], begin[i]);
        }
        selection_sort(begin + 1, end);
    }
}
  • Thanks; I can’t use Std::swap because I can’t at least include <Algorithm>

  • I get it. In this case, okay.

  • 1

    It is worth mentioning in the text of the answer, that in addition to having altered the initialization of the i, exchanging pos+1 for pos, the parameter pos+1 recursive call was also changed to pos. In fact, let the variable initialize i as pos+1 is better, since you already skips an unnecessary comparison (if i is equal to pos, then compare begin[pos] with begin[i] is redundant). Yet, as the value of pos is not changed between recursive calls, will always remain 0, it wouldn’t even need to be passed as a parameter.

  • Actually, the pos was unused anyway. I edited. Thanks!

1


There are a number of factors involved here.

First, the mistake is in passing begin+1 and pos+1 for the recursive call of selection_sort. By adding 1 to begin, you effectively lose elements, since by adding 1 to the pos, for example, in the second iteration, you will be taking the index 1 of a vector that has already been incremented, so you are taking the element 2.

Fixing your code would look like this (already adapting the new stop condition):

template <typename T> void selection_sort(T* begin, T* end, unsigned pos = 0)
{
    if(pos < ((end - begin) - 1))
    {
        for(int i = pos+1; i < (end - begin); i++)
        {
            if(begin[pos] > begin[i]) swap(begin[pos], begin[i]);
        }
        selection_sort(begin, end, pos+1);
    }
    else return;
}

However, although it works, there are a few more things that could be arranged here:

  • the else return; is useless
  • Selection Sort could be done without recursion, by the way, it would spend less memory doing with two for, instead of with recursion
  • using the subtraction result of the vectors to obtain an integer (in your case, the vector size) is not very advisable... I would replace the parameter T* end for int count, since end is not used for anything, whether or not
  • the parameter unsigned pos should be replaced by int pos, to make the type match (you are using int for i, but unsigned for pos)

To illustrate how you would look with these changes that I suggested:

template <typename T> void selection_sort(T* begin, int count)
{
    for (int pos = 0; pos < count - 1; pos++)
    {
        for (int i = pos+1; i < count; i++)
        {
            if (begin[pos] > begin[i]) swap(begin[pos], begin[i]);
        }
    }
}
  • Thanks for the reply and the comment regarding the improvements; but you pointed out an error that does not exist: By adding 1 to Begin, you effectively lose elements. This is simply the goal. It does not alter Begin’s memory when using *, but rather changes the parameter in relation. I would change Begin’s memory if before recursive call I added "Begin++"

  • The error is not in advancing the pointer begin for the next recursion iteration (through begin+1). The mistake is in making at the same time begin+1 and pos+1. In doing begin+1 you will start the next iteration on the next element (in the next iteration begin[0] would already bring the next element). But as you also do pos+1, you end up skipping an extra element in the next iteration. Notice how my first solution takes the begin+1 but let the pos+1, while the solution suggested by @ begin+1 but take the pos+1. I mean, neither one has both at the same time.

  • I get it, thank you.

  • With Else Return I feel better knowing that the code will stop, even if it is obvious hahahaha

  • I won’t trade end for int Count for a reason: I implemented it to use with Iterators.

  • Ah, I get the iterator idea. OK!

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.