teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

2

追加コードについてもの問題点の指摘と cache の意味と mergeSortedDataByCache関数の説明を追加

2021/07/30 14:31

投稿

kazuma-s
kazuma-s

スコア8222

answer CHANGED
@@ -49,6 +49,55 @@
49
49
  sort { 1 2 2 9 9 }
50
50
  [0 4 9] { 3 3 8 8 | 1 2 2 9 9 }
51
51
  sort { 1 2 2 3 3 8 8 9 9 }
52
- ````
52
+ ```
53
+
53
54
  ソートされていますよね。
54
- 変数の値の変化を見るとはこういうことです。
55
+ 変数の値の変化を見るとはこういうことです。
56
+
57
+ **追記2**
58
+ 質問の最後に「質問のコード追記」とあるのに、コードがない、
59
+ と思ったら、元のコードに追記したんですね。
60
+ そんなことをされたら、四角い枠の右上の + ボタンでコードをコピペ
61
+ しようとしたとき、要らないコードの削除が必要になります。
62
+ 別のコードとして追記してもらいたかった。
63
+ また「コード」や「プログラム追記マージソート」という文字列も
64
+ 枠の外に書くようにしてください。
65
+
66
+ その追記マージソートですが、問題があります。
67
+ `#define N 10` の 10 を別の値にしてみてください。
68
+ もちろん `int array[N] = { ... };` のデータも変更します。
69
+ 実行結果には変な数値が現れたりしませんか?
70
+
71
+ `void mergesort(int *A, int i, int j)` の j はソートしたい配列の
72
+ 最後の要素の添字です。
73
+ しかし、main の呼び出し元では `mergesort(array, 0, N);` と
74
+ 配列の最後の要素の次の添字 N を渡しています。
75
+ これは `N-1` にしないといけないでしょう。
76
+ N を渡すと、配列の範囲外の要素をアクセスし、未定義動作となります。
77
+
78
+ 次に、関数 mergesort は内部で `int A1[N], A2[N];` という配列を確保しています。
79
+ mergesort は再帰呼出しをしますから、呼び出しごとにスタック上に配列が
80
+ どんどん確保され、N が大きい場合、その確保に失敗する恐れがあります。
81
+
82
+ この問題を回避するために、main で確保した A1[N] と A2[N] をポインタで
83
+ 渡してやれば、mergesort は新たな領域を確保する必要がなくなります。
84
+
85
+ cache を使うほうのマージソートはそれを行っているのです。
86
+ A1 と A2 には分割されたデータが入るので 2つは要りません。
87
+ 1つの cache の中を使えばすみます。
88
+
89
+ では、
90
+ `void mergeSortedDataByCathe(int *data,int *cache,int first,int last,int half)`
91
+ の説明をします。
92
+
93
+ ここで渡されるデータは、main の配列 data の添字が first から half-1 までと
94
+ half から last-1 までの 2つの領域です。
95
+ この 2つのデータは既にソートされています。
96
+ それらをマージして、data の first から last-1 までに入れて返します。
97
+
98
+ 前半部分は cache の first から half-1 までにそのままコピーしますが、
99
+ 後半部分は cache の half から last までに data の後半部分を逆順に入れます。
100
+ すると 3つめの for文でマージするときに、2つのソート済みデータの末尾を
101
+ 気にする必要がなくなります。
102
+ 先に末尾に達したほうの添字は、もう一方の末尾の添字になるので、
103
+ 残りのデータは問題なく data に収容されます。

1

デバッグ表示を追加

2021/07/30 14:31

投稿

kazuma-s
kazuma-s

スコア8222

answer CHANGED
@@ -7,4 +7,48 @@
7
7
  }
8
8
  ```
9
9
  コンパイルエラーは自分で修正してください。
10
- 他も修正しないと動きません。
10
+ 他も修正しないと動きません。
11
+
12
+ **追記**
13
+ デバッグ用に printf を追加した mergeSortedDataByCahce です。
14
+ ```C
15
+ void mergeSortedDataByCathe(int *data,int *cache,int first,int last,int half){
16
+ int i, j, k;
17
+
18
+ printf("[%d %d %d] {", first, half, last);
19
+ for (i = first; i < half; i++) printf(" %d", data[i]);
20
+ printf(" |");
21
+ for (; i < last; i++) printf(" %d", data[i]);
22
+ printf(" }\n");
23
+
24
+ for (i = first; i < half; i++) cache[i] = data[i];
25
+ for (j = last; i < last; i++) cache[i] = data[--j];
26
+ for (i--, j = first, k = first; k < last; k++)
27
+ data[k] = cache[j] < cache[i] ? cache[j++] : cache[i--];
28
+
29
+ printf("sort {");
30
+ for (i = first; i < last; i++) printf(" %d", data[i]);
31
+ printf(" }\n");
32
+ }
33
+ ```
34
+ これで `3 8 3 8 9 2 9 2 1` をソートすると、次のようになりました。
35
+ ```text
36
+ [0 1 2] { 3 | 8 }
37
+ sort { 3 8 }
38
+ [2 3 4] { 3 | 8 }
39
+ sort { 3 8 }
40
+ [0 2 4] { 3 8 | 3 8 }
41
+ sort { 3 3 8 8 }
42
+ [4 5 6] { 9 | 2 }
43
+ sort { 2 9 }
44
+ [7 8 9] { 2 | 1 }
45
+ sort { 1 2 }
46
+ [6 7 9] { 9 | 1 2 }
47
+ sort { 1 2 9 }
48
+ [4 6 9] { 2 9 | 1 2 9 }
49
+ sort { 1 2 2 9 9 }
50
+ [0 4 9] { 3 3 8 8 | 1 2 2 9 9 }
51
+ sort { 1 2 2 3 3 8 8 9 9 }
52
+ ````
53
+ ソートされていますよね。
54
+ 変数の値の変化を見るとはこういうことです。