Math Battle [ 0322: 0307の回答 ② ]

[ 0322: 0307の回答 ② ]


[ 大宙乗児君の回答 ]

QuickSort ができましたので、次は MergeSort です。
QuickSort と同様な divide & conquer 型アルゴリズムで
対象とする配列 (array) を左半分と右半分に分け
それぞれをソートしつつ合併 (merge) してゆきます。

ソースコードは以下のとおりです。

#!/usr/local/bin/perl

$N = 100; # 100 から 1000 まで変えて実行。

@data = (
 # 1000 個の乱数 (整数)
);

$count = 0;

Sort(0, $N-1);
printf("Count %d\n", $count);

sub Sort($l, $r) {
 my ($l, $r) = @_;
 my $m;

 $count++;

 if ($l < $r) {
  $m = int(($l + $r)/2);

  Sort($l, $m);
  Sort($m+1, $r);

  merge($l, $m, $r);
 }
}

sub merge($l, $m, $r) {
 my ($l, $m, $r) = @_;
 my $n1, $n2, @L, @R;
 my $i, $j, $k;

 $n1 = $m - $l + 1;

 $n2 = $r - $m;

 for ($i = 0; $i < $n1; $i++) {
  $L[$i] = $data[$l + 1];
 }
 for ($j = 0; $j < $n2; $j++) {
  $R[$j] = $data[$m + $j + 1];
 }

 $i = $j = 0;
 $k = 1;

 $count += 2;

 while (($i < $n1) && ($j < $n2)) {
  $count++;
  if ($L[$i] <= $R[$j]) {
   $data[$k] = $L[$i];
   $i++;
  } else {
   $j++;
  }
  $k++;
 }
 $count++;
 while ($i < $n1) {
  $count++;
  $i++;
  $k++;
 }
 $count++;
 while ($j < $n2) {
  $count++;
  $data[$k] = $R[$j];
  $j++;
  $k++;
 }
}

大小比較演算のカウントをプロットしました。ほぼ直線ですね。


[ 湯会老人のコメント ]

よくできました。

Stanford University の Algorithms コースでも divide and conquer
の考えかたの実例として merge sort が詳しく説明されていました。

使うサブルーチンは sort と merge だけです。
sort は対象データ配列の左半分と右半分をそれぞれ sort したうえで
それらを merge によって撚り合わせるように合併してもとの配列に戻します。

Perl の組み込み関数にすでに sort がありますから
乗児君は自分のサブルーチン名を Sort にしました。
よく気がつきましたね。

[ 0341: 次の記事 ]

[ 0340: 素数日プログラム ]

[ 0339: emirp 探し ]

[ 0338: 0331の解きなおし ]

[ 0337: ubuntu 20.04 へ upgrade ]

[ 0336: πの近似計算 ]

[ 0335: 0253 の振り返り ]

[ 0334: Data Camp Python ]

[ 0333: 原始ピタゴラス数をさがす ]

[ 0332: LaTex の使いかた ]

[ 0331: 青い三角形の面積 ]

[ 0330: 長方形の幅 ]

[ 0329: 三角関数の関数の最大最小 ]

[ 0328: IMO 過去問 9 ]

[ 0327: 1+2+3+...+無限 ]

[ 0326: 2分木 sort も含めた性能比較 ]

[ 0325: 最悪ケースでの sort 比較 ]

[ 0324: 0307の回答 ④ ]

[ 0323: 0307の回答 ③ ]

[ 0322: 0307の回答 ② ]

[ 0321: 0307の回答 ① ]

[ 0320: 前の記事 ]

[ トップページへ ]