基本情報技術者 2011年 秋期 午前(科目A) 問07
問題文
要素番号が0から始まる配列TANGOがある。個の単語がTANGO[1]からTANGO[n]に入っている。図は、番目の単語をTANGO[1]に移動するために、TANGO[1]からTANGO[-1]の単語を順に一つずつ後ろにずらして単語表を再構成する流れ図である。[ a ]に入れる処理として、適切なものはどれか。

選択肢
ア:TANGO[] → TANGO[+1](正解)
イ:TANGO[] → TANGO[-]
ウ:TANGO[+1] → TANGO[-]
エ:TANGO[-] → TANGO[]
配列要素の後方シフト(TANGO)【午前2 解説】
要点まとめ
- 結論:最後の要素を先頭に置いてから、逆方向(大きい添字→小さい添字)に TANGO[i] → TANGO[i+1] を代入すると意図した通り全要素を一つ後ろにずらせます。
- 根拠:ループ指定が「i : n−1, −1, 0」であるため i は n−1 から 0 へ減少し、後方へ代入することで上書きによるデータ消失を防げます。
- 差がつくポイント:ループの向き(増分が負)と添字の範囲(0 を含めるか)が正しく理解できるかで、オフバイワンや上書きミスを避けられます。
正解の理由
図ではまず TANGO[n] → TANGO[0] として末尾を一時保存し、そのあとループが i = n−1 から 0 へ減少します。各反復で TANGO[i] を TANGO[i+1] にコピーすれば、元の TANGO[n](今は TANGO[0])が最終的に TANGO[1] に入り、TANGO[1]..TANGO[n−1] は順に後方へずれます。したがって正解は ア の
TANGO[i] → TANGO[i+1]です。
よくある誤解
- ループの方向を見誤って「i を増やしながら左から右へ代入」すると、先に代入した値で以降の元データが上書きされ正しい結果になりません。
- ループ終了値や開始値を 1 ベースで誤読し、i の範囲を間違える(i=0 を抜かす/含めない)と先頭要素への配置がずれます。
- 選択肢の表記を見て「添字の式が複雑なら正しい」と誤解しがちで、実際にはデータの移動方向と上書きの有無を考えるべきです。
解法ステップ
- まず図の通り TANGO[n] を一時的に先頭へ移す:TANGO[n] → TANGO[0]。
- ループを i = n−1 から i = 0 まで(増分 −1)回し、各回で TANGO[i] → TANGO[i+1] と代入する。
- ループ終了後、TANGO[1] に元の TANGO[n] が入り、他は一つ後ろへずれている。
- 計算量は要素数 n に対して O(n)、追加記憶領域は定数(TANGO[0] を一時利用)。
疑似コード例:
# n 個の単語が TANGO[1]..TANGO[n] にあり、TANGO[0] は空とする
TANGO[0] = TANGO[n] # 末尾を先頭へ退避
for i in range(n-1, -1, -1): # i = n-1, n-2, ..., 0
TANGO[i+1] = TANGO[i]
# 結果: TANGO[1] が元の TANGO[n]、TANGO[2] が元の TANGO[1]、...、TANGO[n] が元の TANGO[n-1]
選択肢別の誤答解説
-
ア: TANGO[i] → TANGO[i+1]
正解。末尾を先頭へ退避した後、i を n−1 から 0 へ順に代入すれば上書きを避けつつ全要素を後方へシフトできます。 -
イ: TANGO[i] → TANGO[n−i]
誤り。右辺が添字計算で固定された位置に飛ぶため、目的の「全要素を一つ後ろへずらす」操作になりません。例えば n=4 で i=1 のとき TANGO[1]→TANGO[3] になり、位置関係が崩れます。 -
ウ: TANGO[i+1] → TANGO[n−i]
誤り。これは元データを不均等に別位置へ移す操作で、連続した後方シフトを実現しません。また上書きや抜けが発生しやすい式です。 -
エ: TANGO[n−i] → TANGO[i]
誤り。コピー方向が逆(右側の要素を左へ移すように見える)かつ添字変換が目的と異なり、図示された処理の意図(最後の要素を先頭にし、他を一つ後ろへずらす)を満たしません。
(具体例)n=3, 元の配置 TANGO[1]=A, TANGO[2]=B, TANGO[3]=C:
- 図の処理の後は TANGO[1]=C, TANGO[2]=A, TANGO[3]=B になります。アの方法で得られる結果と一致します。
補足コラム
- この操作は「1 要素分の右回転(ローテーション)」に相当します。TANGO[0] をテンポラリ領域として利用することで追加メモリをほとんど使わずに実現できます。
- 「前から後ろへ」ではなく「後ろから前へ」移す理由は上書きを防ぐためです。配列を前→後に移す場合は、別の一時配列を用意するか、後方から処理する設計にします。
- 応用として、k 項の回転なら同様に k 回繰り返すか、あるいは gcd を使った最適な循環アルゴリズムを使うこともあります(アルゴリズムの幅を広げると得点差がつきます)。
FAQ
Q1: n=1 の場合どうなる?
A1: TANGO[1]→TANGO[0] の後で i=n−1=0 のループで TANGO[0]→TANGO[1] が実行されるため結果は元と同じ(安全に処理されます)。
A1: TANGO[1]→TANGO[0] の後で i=n−1=0 のループで TANGO[0]→TANGO[1] が実行されるため結果は元と同じ(安全に処理されます)。
Q2: なぜ i の増分が −1 なのか?
A2: 添字が小さい側へ代入すると元データを上書きしてしまうため、元データを保護する目的で大きい添字から順に移動します。
A2: 添字が小さい側へ代入すると元データを上書きしてしまうため、元データを保護する目的で大きい添字から順に移動します。
Q3: TANGO[0] を使えないときは?
A3: 別途一時変数を用意して TANGO[n] の値を保持してからシフト操作を行えば同様に実現できます(追加 O(1) のメモリ)。
A3: 別途一時変数を用意して TANGO[n] の値を保持してからシフト操作を行えば同様に実現できます(追加 O(1) のメモリ)。
関連キーワード: 配列、シフト、ローテーション、インプレース操作、オフバイワン、ループ制御、添字操作、アルゴリズム、時間計算量、空間計算量

\ せっかくなら /
基本情報技術者を
クイズ形式で学習しませんか?
クイズ画面へ遷移する→
すぐに利用可能!

