こんにちは。ECF代表のヒガです。
本記事では初心者向けアルゴリズムの演習問題を紹介しています。日頃のプログラミング学習にご活用ください。
はじめに
アルゴリズムとは、コンピューターに行わせる計算手順のことです。自在にプログラムを作るには、プログラム言語の文法の知識とともにアルゴリズムの考え方を身につけることが必要になります。
アルゴリズム技法習得の肝は「繰り返し」の活用です。この連載では、簡単な題材で繰り返しを使うアルゴリズムの基本パターンを練習していきます。
演習問題の一覧や勉強スタイルについてのアドバイスはこちらからどうぞ。
Q013 左下がりに文字を並べる
複数行にわたり1つずつずらしながら文字「■」を表示することで、実行例のような左下がりの線を表示させてください。ただし、行数はプログラムの先頭で変数に代入することで指定してください。なお、各列で■の前にあるスペース部分は、全角スペースを埋めてください。
行数に「8」を指定した場合の実行例は次のとおりです。
ヒント
全体的な考え方はQ012と同じです。列ループにおいて「どういう条件のときに'■'を表示するか?」を判断して表示させる必要があります。
解答例と解説
考え方
以下の全角スペースを可視化した図で考えると、ほぼ基本の二重ループなのなのがわかります。(行数に「5」を指定した場合)
□□□□■
□□□■□
□□■□□
□■□□□
■□□□□
とりあえず、二重ループの内側の繰り返しは、
- 文字' '(全角スペース)を表示する、ただし、適切なタイミングで文字'■'を表示する
の繰り返しとなります。この「適切なタイミング」を条件に' '(全角スペース)または'■'のいずれかを表示することになります。
条件を探るために、具体的に行数に「8」を指定したときの'■'を表示する位置を考えてみましょう。
i行目 | '■'を表示する位置(j列目) |
---|---|
1 | 8 |
2 | 7 |
3 | 6 |
4 | 5 |
5 | 4 |
6 | 3 |
7 | 2 |
8 | 1 |
どうでしょう。規則性は明確ですが、Q012と違い、i行目と表示位置の関係性は少しわかりにくいですね。Q011の逆三角形でも同じ話題がありましたが、ループ変数iが増えていくに連れ減っていく値は、「全体の繰り返し回数 - i」を使って計算するのが定石です。
これをヒントに、先程の表に関係式を追加してみます。
i行目 | '■'を表示する位置(j列目) | iとの関係式( j =【iを使った計算式】) |
---|---|---|
1 | 8 | 8 = 8 - 1 + 1 |
2 | 7 | 7 = 8 - 2 + 1 |
3 | 6 | 6 = 8 - 3 + 1 |
4 | 5 | 5 = 8 - 4 + 1 |
5 | 4 | 4 = 8 - 5 + 1 |
6 | 3 | 3 = 8 - 6 + 1 |
7 | 2 | 2 = 8 - 7 + 1 |
8 | 1 | 1 = 8 - 8 + 1 |
文字'■'を表示すべき列番号の条件は「列番号j = 指定行数 - 行番号i + 1」となっていることがわかります。外側の行ループも合わせて、箇条書きにしてみましょう。
- 行数(繰り返し回数)を指定する
- 次の動作を行数分繰り返す
- 次の動作を列数分(=行数分)繰り返す
- 「列番号j = 指定行数 - 行番号i + 1」となっているか?
- 等しい場合、文字'■'を表示する
- 等しくない場合、文字' '(全角スペース)を表示する
- 「列番号j = 指定行数 - 行番号i + 1」となっているか?
- 改行する
- 次の動作を列数分(=行数分)繰り返す
となります。
これでも実行例と見た目は同じになっているのですが、もう少しだけ改善できます。'■'を表示した後にも' '(全角スペース)を続けて表示することになりますが、この表示は無駄です。'■'を表示し終わった時点で続きの繰り返しをやめてしまいましょう。つまり箇条書きは
- 行数(繰り返し回数)を指定する
- 次の動作を行数分繰り返す
- 次の動作を列数分(=行数分)繰り返す
- 「列番号j = 指定行数 - 行番号i + 1」となっているか?
- 等しい場合、次の動作を実行する
- 文字'■'を表示する
- 列の繰り返しを終了する
- 等しくない場合、文字' '(全角スペース)を表示する
- 等しい場合、次の動作を実行する
- 「列番号j = 指定行数 - 行番号i + 1」となっているか?
- 改行する
- 次の動作を列数分(=行数分)繰り返す
となります。階層が深くなって見にくいのですが、具体的には次のフローチャート例を見ると理解しやすいでしょう。
フローチャート例
またいつもの話なのですが、プログラム実装を意識した都合で、行ループと列ループの開始が「0回目」から始まっています。そこを考慮して、改めて具体的に行数に「8」を指定したときを考えると、
i行目 | '■'を表示する位置(j列目) | iとの関係式( j =【iを使った計算式】) |
---|---|---|
0 | 7 | 7 = 8 - 0 - 1 |
1 | 6 | 6 = 8 - 1 - 1 |
2 | 5 | 5 = 8 - 2 - 1 |
3 | 4 | 4 = 8 - 3 - 1 |
4 | 3 | 3 = 8 - 4 - 1 |
5 | 2 | 2 = 8 - 5 - 1 |
6 | 1 | 1 = 8 - 6 - 1 |
7 | 0 | 0 = 8 - 7 - 1 |
となります。つまり、文字'■'を表示する条件は「列番号j = 指定行数 - 行番号i - 1」となります。
Javaでの実装例
public class Q013 { public static void main(String[] args) { int n = 8; // 繰り返しの数 for (int i = 0; i < n; i++) { // 行ループ for (int j = 0; j < n; j++) { // 列ループ if (j == n - i - 1) { // ■を表示すべき値になったら System.out.print('■'); break; // ループを抜ける } else { System.out.print(' '); } } System.out.println(); // 列ループが終われば改行 } } }
上のフローチャートとの対応からプログラム実装例の流れを確認しましょう。
Javaでループを終了させるには「break;」命令を使います。breakが実行されると、直近のループ(今回の場合は列ループ)を終了し、14行目の処理に移ります。
おわりに
今回も前回Q012に引き続き、二重ループの2つのカウンタ変数を交えた条件式について、対応表を書いて考えてみました。Q012の右下がりのときと比べ、■を表示する条件が複雑になっています。このレベルでも、なかなか慣れないうちは正解にたどり着けないかもしれません。
特に二重ループを必要とするアルゴリズムでは、すぐにプログラムやフローチャートを書こうとはせずに、しっかりと「何を繰り返せばいいのか」「どういう条件で表示すればいいのか」を具体的な例をもとに考え、紙に書いていきましょう。面倒ではありますが、複雑なアルゴリズムほど逆に短時間で正解を導くことができます。
次回はこちらです。
合同会社イー・シー・エフでは、子ども向けプログラミングなどの教育講座を実施しています。プログラミング教室の案内や教育教材の情報、また関連するご相談・問い合わせにつきましては下記よりご確認ください。