web-dev-qa-db-ja.com

非常に小さなリストをソートするための高速アルゴリズム実装

これは私がずっと前に遭遇した問題です。あなたのアイディアをお願いしてもいいかと思いました。並べ替える必要がある数(整数)、4または8要素の非常に小さなリストがあると仮定します。最良のアプローチ/アルゴリズムは何でしょうか?

私のアプローチは、max/min関数を使用することでした(4つの数値を並べ替える10個の関数、分岐なし、iirc)。

// s(i,j) == max(i,j), min(i,j)
i,j = s(i,j)
k,l = s(k,l)
i,k = s(i,k) // i on top
j,l = s(j,l) // l on bottom
j,k = s(j,k)

私の質問は、アルゴリズムのタイプではなく、実装に関するものだと思います。

この時点で、ハードウェアに依存するようになるため、SSE3を搭載したIntel 64ビットプロセッサを想定します。

ありがとう

38
Anycorn

このような小さな配列では、おそらく sorting networks を調べる必要があります。このページを見るとわかるように、挿入ソートはソートネットワークとして表現できます。ただし、アレイのサイズが事前にわかっている場合は、最適なネットワークを考案できます。 このサイト を見てください。これは、特定のサイズのアレイに最適なソーティングネットワークを見つけるのに役立ちます(ただし、最適なサイズは最大16まで保証されています)。コンパレータは、並行して実行できる操作にグループ化されています。コンパレータは基本的にs(x、y)関数と同じですが、これを本当に高速にしたい場合は、必要な比較の数を2倍にするため、minとmaxを使用しないでください。

この並べ替えアルゴリズムが幅広いサイズで機能する必要がある場合は、他の人が示唆しているように、おそらく挿入並べ替えを使用する必要があります。

36
Justin Peel

私はすでに5つの比較を使用するソリューションを持っていることを確認します(s(i、j)が2つの数値を1回比較し、それらを交換するかどうかを仮定します)。比較ベースのソートに固執する場合、5つ未満の比較でそれを行うことはできません。

これは4つあるので証明できます! = 4つの番号を注文する24の可能な方法。各比較は可能性を半分にしか減らすことができないので、4つの比較では2 ^ 4 = 16の可能な順序を区別することしかできませんでした。

7
mathmike

複雑さによりオーバーヘッドが増えるため、少量の数値を並べ替えるには、単純なアルゴリズムが必要です。

たとえば4つのアイテムを並べ替える最も効率的な方法は、並べ替えアルゴリズムを線形比較に解明して、すべてのオーバーヘッドを排除することです。

function sort(i,j,k,l) {
  if (i < j) {
    if (j < k) {
      if (k < l) return [i,j,k,l];
      if (j < l) return [i,j,l,k];
      if (i < l) return [i,l,j,k];
      return [l,i,j,k];
    } else if (i < k) {
      if (j < l) return [i,k,j,l];
      if (k < l) return [i,k,l,j];
      if (i < l) return [i,l,k,j];
      return [l,i,k,j];
    } else {
      if (j < l) return [k,i,j,l];
      if (i < l) return [k,i,l,j];
      if (k < l) return [k,l,i,j];
      return [l,k,i,j];
    }
  } else {
    if (i < k) {
      if (k < l) return [j,i,k,l];
      if (i < l) return [j,i,l,k];
      if (j < l) return [j,l,i,k];
      return [l,j,i,k];
    } else if (j < k) {
      if (i < l) return [j,k,i,l];
      if (k < l) return [j,k,l,i];
      if (j < l) return [j,l,k,i];
      return [l,j,k,i];
    } else {
      if (i < l) return [k,j,i,l];
      if (j < l) return [k,j,l,i];
      if (k < l) return [k,l,j,i];
      return [l,k,j,i];
    }
  }
}

ただし、コードは追加する項目ごとに大きくなります。 5番目の項目を追加すると、コードが約4倍大きくなります。 8つの項目で約30000行になるので、それでも最も効率的ですが、大量のコードであり、正しいコードを記述するプログラムを作成する必要があります。

7
Guffa

挿入配列は、小さな配列に最適です。参照 小さな配列(32または64要素未満)の高速安定ソート

4
mathmike

このような小さなデータセットの場合は、アルゴリズムをできるだけ単純にする必要があります。たいていの場合、基本的な Insertion Sort は望みどおりに機能します。

これが実行されているシステム、1秒間にこのソートを実行する必要がある回数などについて詳しく知る必要がありますが、小規模なソートの一般的なルールは、単純に保つことです。クイックソートなどは有益ではありません。

3
bwawok

ソートネットワークはSIMDで簡単に実装できますが、N = 16前後で醜くなり始めますが、N = 4またはN = 8の場合、これは良い選択です。理想的には、同時にソートするために多くの小さなデータセットが必要です。つまり、8ビット値をソートする場合、少なくとも16のデータセットをソートする必要があります。この種のことを行うのははるかに困難ですacross SIMDベクトル。

参照: 固定長6整数配列の最高速のソート

3
Paul R