4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

OpenMPでクイックソート

Last updated at Posted at 2015-07-20

なんかクイックソートブームが自分の中で起きてました。
早くするにはどうするんだろうと考えてて、アルゴリズム的にばしっと分割するんだからマルチスレッド行けるんじゃねと思ってOpenMP化してみた。

qsort.cpp
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <omp.h>

template<typename T>
class Rand{
  T x = 1;
public:
  T next() {
    x ^= x >> 12;
    x ^= x << 25;
    x ^= x >> 27;
    return x * 2685821657736338717;
  }
};

template<typename T>
void part(T a[], int& i, int& j) {
  const T pivot = a[i];
  while (1) {
    while (a[i] < pivot) i++;
    while (pivot < a[j]) j--;
    if (i >= j) break;
    const T tmp = a[i]; a[i] = a[j]; a[j] = tmp;
    i++; j--;
  }
}

template<typename T>
void _qsort(T a[], const int left, const int right) {
  if (left < right) {
    int i = left, j = right;
    part(a, i, j);
    _qsort(a, left, i - 1);
    _qsort(a, j + 1, right);
  }
}

template<typename T>
void qsort(T a[], const int left1, const int right1) {
  if (left1 >= right1) return;

  int i1 = left1, j1 = right1;
  part(a, i1, j1);
  const int left2 = left1, right2 = i1-1;
  const int left3 = j1+1, right3 = right1;

  int i2 = left2, j2 = right2;
  int i3 = left3, j3 = right3;
  part(a, i2, j2);
  part(a, i3, j3);

#pragma omp parallel shared(a)
  {
#pragma omp sections
    {
#pragma omp section
      _qsort(a, left2, i2 - 1);
#pragma omp section
      _qsort(a, j2 + 1, right2);
#pragma omp section
      _qsort(a, left3, i3 - 1);
#pragma omp section
      _qsort(a, j3 + 1, right3);
    }
  }
}

int main(int argc, char** argv) {
  const int size = 10000000;

  auto rand = new Rand<int>();

  auto a = new int[size];
  for (int i = 0; i < size; i++) {
    a[i] = rand->next();
  }

  double st = omp_get_wtime();
  qsort(a, 0, size-1);
  double ut = omp_get_wtime() - st;
  printf("Used time         = %2.6lf (s)\n", ut);

  delete a;
  return 0;
}

やり方は一発目に呼ばれるqsort関数で配列を4つに分割して、それをスレッドにして普通のクイックソートである_qsort関数を実行する感じ。普通のクイックソートにラッパーかますイメージ。

qsort関数がごちゃってるのは本来、再帰な処理を一段階、無理やりインライン化してるから。まず全体を分割(part関数)して、さらにそれぞれを分割(part関数)することで4分割にして、_qsortに渡す、っていうラッパーがこの関数。

肝心の速度は割と早くなりました。

4
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?