質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
マージ

複数のデータベースやファイル、プログラムなどを決まった手順や規則に従って一つに結合すること。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

ソート

複数のデータを、順序性に従って並べ替えること。 データ処理を行う際に頻繁に用いられ、多くのアルゴリズムが存在します。速度、容量、複雑さなどに違いがあり、高速性に特化したものにクイックソートがあります。

Q&A

解決済

2回答

1690閲覧

Javaによるマージソート

meltySAGAWA

総合スコア2

マージ

複数のデータベースやファイル、プログラムなどを決まった手順や規則に従って一つに結合すること。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

ソート

複数のデータを、順序性に従って並べ替えること。 データ処理を行う際に頻繁に用いられ、多くのアルゴリズムが存在します。速度、容量、複雑さなどに違いがあり、高速性に特化したものにクイックソートがあります。

0グッド

0クリップ

投稿2021/09/28 04:01

前提・実現したいこと

マージソートをしたいです

発生している問題・エラーメッセージ

エラーはなく実行されるのですが、結果がソートされていません
どこを直すべきか教えてください

以下実行結果

{3, 2, 8, 4, 5, 7, 1, 0, 6, 9} // ソート前 {3, 2, 7, 1, 0, 6, 8, 4, 5, 9} // ソート後

該当のソースコード

Java

1public class testMeregeSort { 2 private final int n = 10; 3 private int[] a = { 3, 2, 8, 4, 5, 7, 1, 0, 6, 9 }; 4 5 public testMeregeSort() { 6 } 7 8 private void mergesort(int low, int high) { 9 int xSize = (high - low + 1) / 2; 10 int ySize = (high + 1) - xSize; 11 int[] x = new int[xSize]; 12 int[] y = new int[ySize]; 13 int[] z = new int[n]; 14 int xIndex = 0; 15 int yIndex = 0; 16 17 if (high - low + 1 <= 1) { 18 return; 19 } 20 21 // ここから分割 22 for (int i = 0; i < xSize; i++) { 23 x[i] = a[i]; 24 } 25 26 for (int i = 0; i < ySize; i++) { 27 y[i] = a[i + xSize]; 28 } 29 30 mergesort(0, xSize - 1); 31 mergesort(0, ySize - 1); 32 33 // ここからマージ 34 while (xIndex < xSize && yIndex < ySize) { 35 if (x[xIndex] <= y[yIndex]) { 36 z[xIndex + yIndex] = x[xIndex]; 37 xIndex++; 38 } else { 39 z[xIndex + yIndex] = y[yIndex]; 40 yIndex++; 41 } 42 } 43 44 if (xIndex >= xSize) { 45 for (int i = yIndex; i < ySize; i++) { 46 z[i + xIndex] = y[i]; 47 } 48 } else { 49 for (int i = xIndex; i < xSize; i++) { 50 z[i + yIndex] = x[i]; 51 } 52 } 53 54 for (int i = 0; i < n; i++) { 55 a[i] = z[i]; 56 } 57 58 } 59 60 public void sort() { 61 mergesort(0, a.length - 1); 62 63 for (int i = 0; i < n; i++) { 64 System.out.println(a[i]); 65 } 66 } 67 68 public static void main(String[] args) { 69 testMeregeSort ms = new testMeregeSort(); 70 ms.sort(); 71 } 72} 73

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

とりあえず、クラスの名前はtestMergeSortに直すべきだと思います。
(課題などで指定がある場合は仕方ないです(丸投げはやめてほしいですが))。

けっこういっぱい間違いがありましたので、下記の修正したソースコードに、コメントで直接間違っていた内容を記入しておきました( !-- --! で囲まれたコメントの部分が間違いです。それ以外はお節介だと思ってください)。

基本的に使用する直前に変数宣言は移動してあります。
古い教科書などでは最初にまとめて変数宣言するのもありがちですが、
どこで使っているのかが追いかけ辛くなります。

あと、マージソートは引数の扱いが微妙に違うものがありまして、

  • low から high をソートするもの(今回)
  • low から high - 1 をソートするもの(mergesort(0, a.length)のように呼び出せて便利)

などがあります。
どこからどこまでをソートする、などの要件は次回から明確に記していただけるとありがたく思います。

実行時にログが出るようにしておきましたので、動作のイメージを掴んでみてください。

java

1public class testMeregeSort { 2 private int[] a = { 3, 2, 8, 4, 5, 7, 1, 0, 6, 9 }; 3 private final int n = a.length; 4 5 public testMeregeSort() { 6 } 7 8 /** 9 * 配列の low ~ high をソートする 10 * 11 * @param low ソートしたい要素の先頭を指す 12 * @param high ソートしたい要素の一番最後の要素を指す 13 */ 14 private void mergesort(int low, int high) { 15 // いくつかログを出すsysoutを追加したので、消したければ消してください 16 System.out.println("関数呼び出し >>> low: " + low + " high: " + high); 17 18 // high - low + 1 <= 1 でもいいのですが、 19 // こちらのほうが意味も明快で、シンプルで良いと思います 20 // 計算式系を維持するなら high - low <= 0 でもよいと思います 21 if (low >= high) { 22 return; 23 } 24 25 final int len = high - low + 1; // low ~ high までの長さ 26 final int xSize = len / 2; 27 final int ySize = len - xSize; // !-- yの長さは high - low + 1 - xSize です --! 28 int[] x = new int[xSize]; 29 int[] y = new int[ySize]; 30 31 // !-- 再帰先が間違っていました --! 32 // 分割点をxとyの分割サイズと合わせる必要があります 33 int mid = low + xSize; 34 mergesort(low, mid - 1); // xと同じ長さ分呼び出す 35 mergesort(mid, high); // yと同じ長さ分呼び出す 36 37 // !-- コピーするのはソート後の配列なので、呼び出し後に分割しましょう --! 38 // ここから分割 39 for (int i = 0; i < xSize; i++) { 40 x[i] = a[low + i]; 41 } 42 43 for (int i = 0; i < ySize; i++) { 44 y[i] = a[low + i + xSize]; 45 } 46 47 // ここからマージ 48 System.out.println("マージ開始 >>> low: " + low + " high: " + high); 49 50 // zのサイズを全体ではなくxとyの合計分のみに変更しました 51 // xとyからaへ直に書き込んだり、 52 // aから直接zを生成し、マージ処理後にzからaに書き戻すような方法もありますが、 53 // オフセットが必要ないのでこのほうがわかりやすいかなと思います 54 int[] z = new int[len]; // x と y を合計したサイズの一時領域 55 int xIndex = 0; 56 int yIndex = 0; 57 while (xIndex < xSize && yIndex < ySize) { 58 if (x[xIndex] < y[yIndex]) { 59 z[xIndex + yIndex] = x[xIndex]; 60 xIndex++; 61 } else { 62 z[xIndex + yIndex] = y[yIndex]; 63 yIndex++; 64 } 65 } 66 67 if (xIndex >= xSize) { 68 for (int i = yIndex; i < ySize; i++) { 69 z[i + xIndex] = y[i]; 70 } 71 } else { 72 for (int i = xIndex; i < xSize; i++) { 73 z[i + yIndex] = x[i]; 74 } 75 } 76 77 System.out.println("処理内容: " + intArrayToStr(x) + " + " + intArrayToStr(y) + " => " + intArrayToStr(z)); 78 // !-- aにlow基準で書き込むようにしました --! 79 // z[0]から使っている様子でしたので、こういう意図だと思いましたがどうでしょうか。 80 for (int i = 0; i < len; i++) { 81 a[i + low] = z[i]; 82 } 83 System.out.println("書き込み結果: " + intArrayToStr(a)); 84 } 85 86 public void sort() { 87 mergesort(0, a.length - 1); 88 89 for (int i = 0; i < n; i++) { 90 System.out.println(a[i]); 91 } 92 } 93 94 /** 95 * intの配列をいい感じに文字列化するヘルパーメソッドです 96 * 実行中のログ出力の必要がないのであれば削除しても問題ありません 97 * @param array 任意のintの配列 98 * @return 配列の中身を文字列化したもの 99 */ 100 public static String intArrayToStr(int[] array) { 101 String s = "["; 102 for (int i = 0; i < array.length; i++) { 103 s += array[i]; 104 if (i != array.length - 1) { 105 s += ", "; 106 } 107 } 108 s += "]"; 109 return s; 110 } 111 112 public static void main(String[] args) { 113 testMeregeSort ms = new testMeregeSort(); 114 ms.sort(); 115 } 116}

投稿2021/09/28 16:05

soemono

総合スコア11

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

meltySAGAWA

2021/09/29 02:36

回答ありがとうございます コメントやログのおかげで動作がよく理解できました testMeregeSortもスペルミスを放置してただけなのですぐ直そうと思います 本当にありがとうございました
guest

0

mergesort は配列 a の low から high までをソートするんですよね。
a の一部を x や y にコピーしても、それらをソートすることはできません。

追記
a や x や y など、複数の配列をソートしたいのなら、
mergesort にそれらを引数で渡す必要があります。
次の修正が必要です。

diff

1- private void mergesort(int low, int high) { 2+ private void mergesort(int[] a, int low, int high) { 3 int xSize = (high - low + 1) / 2; 4- int ySize = (high + 1) - xSize; 5+ int ySize = (high - low + 1) - xSize; 6 7- mergesort(0, xSize - 1); 8- mergesort(0, ySize - 1); 9+ mergesort(x, 0, xSize - 1); 10+ mergesort(y, 0, ySize - 1); 11 12- for (int i = 0; i < n; i++) { 13- a[i] = z[i]; 14+ for (int i = 0; i < high - low + 1; i++) { 15+ a[low + i] = z[i]; 16 17- mergesort(0, a.length - 1); 18+ mergesort(a, 0, a.length - 1);

ySize の求め方を間違っていますし、z から a に戻すところも間違っています。

x や y を使わないで書くなら、

java

1public class Main { 2 private int[] a = { 3, 2, 8, 4, 5, 7, 1, 0, 6, 9 }; 3 private int[] z = new int[a.length]; 4 5 private void mergesort(int low, int high) { 6 int n = high - low + 1; 7 if (n <= 1) return; 8 int mid = low + n/2; 9 mergesort(low, mid - 1); 10 mergesort(mid, high); 11 int i, j, k; 12 for (i = low; i < mid; i++) z[i] = a[i]; 13 for (j = high; i <= high; i++) z[j--] = a[i]; 14 for (k = i = low, j = high; k <= high; k++) 15 a[k] = z[i] < z[j] ? z[i++] : z[j--]; 16 } 17 18 public void sort() { 19 mergesort(0, a.length - 1); 20 for (int i = 0; i < a.length; i++) 21 System.out.print(" " + a[i]); 22 System.out.println(); 23 } 24 25 public static void main(String[] args) { 26 new Main().sort(); 27 } 28}

mergesort は再帰的に何度も呼び出されるので、毎回 z を new するのは非効率です。
一度だけ new して、それを使えば問題ありません。

投稿2021/09/28 07:36

編集2021/09/28 15:56
kazuma-s

総合スコア8224

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

meltySAGAWA

2021/09/28 08:06 編集

xやyにコピーしたものをzに並び替えて、最終的に for (int i = 0; i < n; i++) { a[i] = z[i]; } のようにしてaに入れなおしたつもりだったんですけどこれじゃダメなんですか?
meltySAGAWA

2021/09/29 02:39

追記ありがとうございます xやyを使わない方のコードの for (j = high; i <= high; i++) z[j--] = a[i]; for (k = i = low, j = high; k <= high; k++) a[k] = z[i] < z[j] ? z[i++] : z[j--]; の部分がよくわかりません どういう意図でこのようなコードになっているか教えていただけると助かります
kazuma-s

2021/09/30 00:32 編集

a[low]~a[mid-1] と a[mid]~a[high] はどちらもソート済みです。これらを z[low]~z[mid-1] にはそのままコピー、z[mid]~z[high] には逆順にコピーします。 z[low]~z[high] の両端から一つずつ取り出して小さいほうを a[low] から順に入れていき マージを完了させます。2つの領域のうち先に無くなった領域の添字は、もう一つの領域の 最大値の添字となるので、残った領域は順番に a に移されます。 マージする2つの領域の終わりをチェックせずにマージが完了します。 具体的なデータで考えても分かりませんか?
meltySAGAWA

2021/09/30 02:15

実際にプログラム通りにソートをしたら流れがわかりました 数日に渡ってコメントをしてくださりありがとうございました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問