- 題名: クイックソートの末尾再帰をループに置換する手段
- 日時: 2011/10/23 8:19:09
- ID: 29284
- この記事の返信元:
- (なし)
- この記事への返信:
- [29286] Re[1]: クイックソートの末尾再帰をループに置換する手段2011/10/23 19:25:04
- [29288] Re[1]: クイックソートの末尾再帰をループに置換する手段2011/10/24 10:12:08
- ツリーを表示
■No29286に返信(itiさんの記事) おっしゃるとおり実験です。理論の検証ではなくて実際に経験するという意味の実験です。 関数Swapを呼び出さないようにしたところかなり効果がありました。25%ほど速くなりました。 枢軸を選択する関数QuicksortPivotも挿入ソートで並び替えるようにしてSwap関数を 呼ばないようにしました。 static Int32 QuicksortPivot(Int32[] a, Int32 low, Int32 hig) { var mid = ((hig - low) >> 1) + low; var t = 0; if (a[mid] < a[low]) { t = a[mid]; a[mid] = a[low]; a[low] = t; } if (a[hig] < a[mid]) { if (a[hig] < a[low]) { t = a[hig]; a[hig] = a[mid]; a[mid] = a[low]; a[low] = t; } else { t = a[hig]; a[hig] = a[mid]; a[mid] = t; } } return a[mid]; } ■No29288に返信(itiさんの記事) unsafeのコードは*がポインタの宣言なのか、掛け算なのか、値なのか、アドレスなのか 私にはよくわかりません。難しそうなので今回は使用を避けようと思いますが、お教え いただいたコードは後学のために保存しておきたいと思います。ありがとうございます。 全体をループで囲って引数に値を代入することで末尾再帰をループに置き換える ことができました。処理速度はほとんど変わりませんでした。並び替えを行う配列の 内容によってはスタックオーバーフローが起こる可能性があるのでStackクラスを使う やり方の方がよさそうですね。もうすこし検証してみます。 static Int32[] QuicksortSort(Int32[] a, Int32 low, Int32 hig) { var t = 0; while (low < hig) { if (QuicksortIsSorted(a, low, hig)) return a; var v = QuicksortPivot(a, low, hig); var l = low + 1; var h = hig - 1; do { while (a[l] < v) l++; while (a[h] > v) h--; if (l > h) break; t = a[l]; a[l] = a[h]; a[h] = t; l++; h--; } while (true); if (low < h) QuicksortSort(a, low, h); low = l; } return a; }
2011/11/03(Thu) 18:54:38 編集(投稿者) 3つの要素の中央値を枢軸に選ぶクイックソートにはキラーシーケンスがあるようで キラーシーケンスをソートするばあいにマージソートよりも遅くなりました。なので 9つの要素の中央値を枢軸に選ぶようにしました。 要素数が少ないばあいに挿入ソートを行うようにしました。10%ほど速くなりました。 スタックオーバーフローを避けるために要素数が少ない方を再帰で処理して、要素数が 多い方をループで処理するようにしました。 static Int32[] QuicksortSort(Int32[] a, Int32 low, Int32 hig) { var t = 0; while (low < hig) { if (QuicksortIsSorted(a, low, hig)) { return a; } if (hig - low < 10) { Insertionsort(a, low, hig); return a; } var v = 0; var l = 0; var h = 0; if (hig - low < 32) { v = QuicksortPivot(a, low, hig); l = low + 1; h = hig - 1; } else { var step = (hig - low) >> 3; var mid = ((hig - low) >> 1) + low; v = Median( Median(a[low], a[low + step], a[low + step + step]), Median(a[mid - step], a[mid], a[mid + step]), Median(a[hig - step - step], a[hig - step], a[hig])); l = low; h = hig; } while (l < h) { while (a[l] < v) { l++; } while (a[h] > v) { h--; } if (l > h) { break; } t = a[l]; a[l] = a[h]; a[h] = t; l++; h--; } if (h - low < hig - l) { if (low < h) { QuicksortSort(a, low, h); } low = l; } else { if (l < hig) { QuicksortSort(a, l, hig); } hig = h; } } return a; }
分類:[.NET]