質問
私は最近、マージソートについて多くを読んだし、少なくとも1つの追加のアレイを使用せずにマージを行う方法があるのだろうか。それは可能でしょうか?
解決
ウィキペディアにそれが実際に可能であるが、任意のパフォーマンスの向上が得られない可能性がありますによると:
ソートはその場で可能である(例えば、配列ではなく、リストを使用して)が、非常に複雑であり、かつ、実際にはほとんどないパフォーマンスの向上を提供する場合でもOにおけるアルゴリズムの実行(のN のログ< em>のN の)時間。これらのケースでは、ヒープソートのようなアルゴリズムは、通常、同等の速度を提供し、はるかに複雑です。また、標準のマージソートとは異なり、インプレースマージソート安定ソートではありません。それよりもリンクされたリストの場合、アルゴリズムは、より多くのスペースを使用しない、既にリスト表現で使用されるが、Oは((のK の)ログ)再帰トレースに使用。いくつかは、あなたが与えられたデータ構造にソートされていても、データ構造は、本質的にO(のN の)余分なあなたが操作しているデータ(例えば、リンクを持っているので、リンクされたリストをソートする場所ではないことを主張するだろう)リストでます。
他のヒント
どうやら、それはあります。 インプレースマージソートを説明するこのホワイトペーパー:
2つは、インプレース古典マージソートアルゴリズムの変異体は、詳細に分析されています。最もNログ2 N + O(N)の比較及び3Nログ2 N + O(N)に移動まず、単純変異行うソートN要素に。第二は、より高度な変異体は、最もNログ2 N + O(N)の比較に必要と「Nは、任意の固定のために、2 Nに移動するログ」? 0と任意のN? N( ")。理論的には、二番目はヒープソートの高度なバージョンに比べて優れている。実際には、インデックス操作でオーバーヘッドのために、私たちの最速のインプレースマージソートの振る舞いはまだ50パーセント程度遅くボトムアップヒープソートより。しかし、我々の実装では、インプレースマージに基づいてマージソートアルゴリズムに比べて実用的である。
ユルキKatajainen、トミパサネン、ユッカTeuhola、 "実用的なインプレースマージソート"(1996)。
ここでのJava実装である
public static <T extends Comparable<? super T>> void iterativeMergeSort(T[] seed) {
for (int i = 1; i <seed.length; i=i+i)
{
for (int j = 0; j < seed.length - i; j = j + i+i)
{
inPlaceMerge(seed, j, j + i-1, Math.min(j+i + i -1, seed.length -1));
}
}
}
public static <T extends Comparable<? super T>> void inPlaceMerge(T[] collection, int low, int mid, int high) {
int left = low;
int right = mid + 1;
if(collection[mid].equals(collection[right])) {
return ;//Skip the merge if required
}
while (left <= mid && right <= high) {
// Select from left: no change, just advance left
if (collection[left].compareTo(collection[right]) <= 0) {
left ++;
} else { // Select from right: rotate [left..right] and correct
T tmp = collection[right]; // Will move to [left]
rotateRight(collection, left, right - left);
collection[left] = tmp;
// EVERYTHING has moved up by one
left ++; right ++; mid ++;
}
}
}
ここで、ユニットテストは
private Integer[] seed;
@Before
public void doBeforeEachTestCase() {
this.seed = new Integer[]{4,2,3,1,5,8,7,6};
}
@Test
public void iterativeMergeSortFirstTest() {
ArrayUtils.<Integer>iterativeMergeSort(seed);
Integer[] result = new Integer[]{1,2,3,4,5,6,7,8};
assertThat(seed, equalTo(result));
}
いいえ、あなたはいつもにソートされた要素をマージするために余分なデータ構造が必要になります。そうでない場合、あなたはちょうどあなたがすでにソートされたものを上書きすることがあります。