简体   繁体   中英

Parallelize selection sort using OpenMP

I need to implement an algorithm for parallel selection sort using OpenMP, although I couldn't find much information either on SO or on the Internet in general.

Here's my serial code:

void selectionsort(int* arr, int size)
{
    for (int i = size - 1; i > 0; --i)
    {
        int max = i;
        for (int j = i - 1; j >= 0; --j)
        {
            if (arr[j] > arr[max])
            {
                max = j;
            }
        }
        swap(arr[i], arr[max]);
    }
}

Does anybody know how to implement this type of sorting algorithm in parallel? At least in theory?

Since the outer for can't be parallelized due to the constant changes in the array, we need to parallelize the inner for.

So we need to use the max reduction, but since we just don't need the maximum value we also need the index of this maximum value, we need to declare a new reduction (Only available in OpenMP 4.0) that receives a struct, here it is fully functional:

#include <stdio.h>
#include <omp.h>

struct Compare { int val; int index; };
#pragma omp declare reduction(maximum : struct Compare : omp_out = omp_in.val > omp_out.val ? omp_in : omp_out)

void selectionsort(int* arr, int size)
{
    for (int i = size - 1; i > 0; --i)
    {
        struct Compare max;
        max.val = arr[i];
        max.index = i;
        #pragma omp parallel for reduction(maximum:max)
        for (int j = i - 1; j >= 0; --j)
        {
            if (arr[j] > max.val)
            {
                max.val = arr[j];
                max.index = j;
            }
        }
        int tmp = arr[i];
        arr[i] = max.val;
        arr[max.index] = tmp;
    }
}

int main()
{
        int x[10] = {8,7,9,1,2,5,4,3,0,6};
        selectionsort(x, 10);

        for (int i = 0; i < 10; i++)
                printf("%d\n", x[i]);
        return 0;
}

The solution posted by Gabriel Garcia works only for arrays of natural numbers .

If you use this array you get a wrong result:

int x[10] = {-8,-7,-9,-1,-2,-5,-4,-3,0,-6};

The reduction declaration:

#pragma omp declare reduction(maximum : struct Compare : omp_out = omp_in.val > omp_out.val ? omp_in : omp_out)

does not specify an initializer-clause and therefore at every iteration of the parallel loop the max.val and max.index are initialized to 0 even though we initialize them before the loop.

Refer to user defined reduction syntax for more information.

The correct declaration should be:

#pragma omp declare reduction(maximum : \
                              struct Compare : \
                              omp_out = omp_in.val > omp_out.val ? omp_in : omp_out) \
                              initializer(omp_priv=omp_orig)

You can also do a 'minimum' reduction in the same way if you prefer (obviously, changing the indexes and relationship symbols).

Selection sort is far from optimal. You should use a formally efficient algorithm in serial (eg qsort), since it will almost certainly beat threaded selection sort for nontrivial usage.

The comment that suggests merge sort is a good one.

Threading selection sort as you've shown here is not hard, but since it's the wrong thing to do, I'm not going to demonstrate it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM