4

I'm trying to make a two-way insertion sort. It's supposed to take the very first value in an array, and then sort the following numbers in an array by comparing it to that first value. If the number is greater, it gets placed behind the first one in the array, if it's smaller, it is placed in front.

Here's an image that illustrates the process.

enter image description here

The array here is 6 5 3 1 8 7 2 4, reading from top to bottom is each step of the sorting process. It compares the number 6 with the rest of the numbers, and then places them accordingly.

So far I have this code:

void twowaysort(int n, int a[])
{
    int j;
    int first = a[0];
    for (int i = 1; i < n; i++) {
        if (a[i] > first) {
            j = i + 1;
            while (j <= n - 1 && a[j] < a[j - 1]) {
                swap(a[j - 1], a[j]);
                j = j + 1;
            }
        }
        if (a[i] < first) {
            j = i - 1;
            while (j >= 0 && a[j] > a[j + 1]) {
                swap(a[j + 1], a[j]);
                j = j - 1;
            }
        }
    }
}

While this works with the array above, it seems to fail sorting the following: 13 93 58 33 58 63 11 41 87 32. This makes me believe there's an error somewhere.

Any help would be appreciated.

execut4ble
  • 138
  • 8
  • My advice is to use an IDE with a debugger like Visual Studio and single step through the code looking at the `a` array (use a,10 in the watch window) and a[j], a[j-1], and a[j+1] in the watch window while you step. I have done this in VS 2013 and see a problem with 58 and 33 however I don't fully understand the algorithm so I can't suggest a fix. – drescherjm May 17 '18 at 13:34
  • It's difficult to follow this algorithm. I would first rename ```i``` and ```j``` to something meaningful. Then add some comments, so we can follow the logic which is happening there. – Robert Andrzejuk May 17 '18 at 13:35
  • 2
    Thank you for the suggestions, I've already tried debugging and watching how the values change as the loop goes, but still haven't been able to figure it out. I will try to add comments to the code in case that helps. – execut4ble May 17 '18 at 13:37
  • One thing I see in your code is you don't seem to swap with first after the initial iteration. I mean 11 will not go to the left of 13. – drescherjm May 17 '18 at 13:38
  • I also am wondering, where is first inserted back into the array? – Robert Andrzejuk May 17 '18 at 13:39
  • Your algorithm does not appear to be doing what the picture shows. You are swapping consecutive items but not directly putting things to the left or right of `first`. – drescherjm May 17 '18 at 13:48
  • 1
    The explaination of the algorithm needs to be more specified. What does pushing to the left and pushing to the right mean? Your ```for``` loop is scanning from left to right You can only swap down to the left. – Robert Andrzejuk May 17 '18 at 13:55
  • @RobertAndrzejuk in case the number being sorted is smaller than the first one, it's supposed to be put in front of it. If it's bigger, then it goes behind it, if that makes any sense. Left & right definitions only help if you're looking at the example image. – execut4ble May 17 '18 at 14:12
  • 1
    In an array left and right have no meaning. The index of 6 in the example above is : 0, 1, 2, 3, 3, 3, 4, 5. That is increasing not staying in the same location. – Robert Andrzejuk May 17 '18 at 14:28
  • Yes that is correct. – execut4ble May 17 '18 at 14:35
  • I think this understanding of the algorithm may be incorrect. Please provide a refrence to this algorithm. – Robert Andrzejuk May 17 '18 at 15:19
  • I'm afraid I don't have any reference as I haven't been able to find anything about it on the internet. Your posted code appears to be the the correct solution for it, though. – execut4ble May 17 '18 at 15:27
  • My code can be further reduced to a simple insertion sort. – Robert Andrzejuk May 17 '18 at 15:31
  • Could you demonstrate what you mean exactly? – execut4ble May 17 '18 at 15:43

3 Answers3

3

The first thing I noticed is even though there is a selected value, there is no corresponding selected index. So that had to be added and used.

Second thing is that the selected value is only a boundry. And each time the currently sorted value has to bubble it's way down.

So all in all this is just a standard insertion sort. (That is if I understood the algorithm correctly.)

Renamed the variables i and j to to_sort_idx and look_at_idx.

void twowaysort( int a_size, int a[] )
{
    if ( a_size < 2 )
        return;

    int selected_idx   = 0;
    int selected_value = a[ selected_idx ];

    for ( int to_sort_idx = 1; to_sort_idx < a_size; to_sort_idx++ )
    {
        if ( a[ to_sort_idx ] > selected_value )
        {
            int look_at_idx = to_sort_idx;

            while ( look_at_idx > selected_idx && a[ look_at_idx ] < a[ look_at_idx - 1] )
            {              
                std::swap( a[ look_at_idx -1 ], a[ look_at_idx  ] );
                --look_at_idx;
            }
        }
        else //if ( a[ to_sort_idx ] <= selected_value )
        {
            int look_at_idx = to_sort_idx - 1;

            while ( look_at_idx >= 0 && a[ look_at_idx ] > a[ look_at_idx + 1 ] )
            {
                std::swap( a[ look_at_idx ], a[ look_at_idx + 1] );
                --look_at_idx;
            }

            ++selected_idx;
        } 
    }
}
Robert Andrzejuk
  • 5,076
  • 2
  • 22
  • 31
  • @execut4ble This fixes your code, but please verify the algorithm. In my opinion this implements insertion sort. Not two-way. – Robert Andrzejuk May 17 '18 at 15:44
  • 2
    I'll take it back: you're right, this does the same as a simple insertion sort would, and not how this algorithm describes the sorting. – execut4ble May 17 '18 at 19:46
2

I implemented this with a vector, I save the position of the starting number then insert left is the number is lower or right if the number is greater. Then numbers go to left or right until they are greater or lower.

Hope this helps

int poz = 0; //starting value position
vector<int> b;    
b.push_back(a[0]);//first value

for (int i = 1; i < n; i++)
{
    if (a[i] > prad)    //if greater
    {
        vector<int>::iterator it = b.begin() + poz;    //position of starting element
        it = b.insert(it + 1, a[i]); //insertion to the right
        int t = poz + 1;    //position of the inserted element
        while (t + 1 < b.size() && b[t] > b[t + 1])    
        {
            swap(b[t], b[t + 1]);   
            t++;                    //we go right until our number is greater
        }
    }
    else  //same here but instead of going right we go left until the value is lower
    {
        vector<int>::iterator it = b.begin() + poz;
        it = b.insert(it, a[i]);
        poz++; 
        int t = poz - 1;
        while (t > 0 && b[t] < b[t - 1])
        {
            swap(b[t], b[t - 1]);
            t--;                
        }
    }
}
katinas
  • 432
  • 6
  • 11
  • 2
    That makes sense, didn't think to use vector for a seemingly simple algorithm like this but it works! Thanks a bunch. – execut4ble May 23 '18 at 14:33
0

The issue here is your algorithm is only making one pass at the array where integers are being swapped. Because of the swapping of 93 to the back on the first pass, the second iteration looks at a[2] which is now 33 (not 58). So you have essentially skipped over processing 58. This algorithm only partially sorts the array. You would have to make multiple passes here to get what you want...

void twowaysort(int n, int a[])
{
    int j;
    int first;

    for (int k = 0; k < n; ++k)
    {
        first = a[0];
        for (int i = 1; i < n; i++) 
        {
            if (a[i] > first) 
            {
                j = i + 1;
                while (j <= n - 1 && a[j] < a[j - 1]) 
                {
                    swap(a[j - 1], a[j]);
                    j = j + 1;
                }
            }
            if (a[i] < first) 
            {
                j = i - 1;
                while (j >= 0 && a[j] > a[j + 1]) 
                {
                    swap(a[j + 1], a[j]);
                    j = j - 1;
                }
            }
        }
    }

}

output: 11 13 32 33 41 58 58 63 87 93

Jason
  • 2,493
  • 2
  • 27
  • 27