基本情報技術者試験:科目B練習問題
疑似言語に準拠したオリジナルの問題です。
科目Bの対策にご利用ください。
簡易的な解説とトレース表も掲載しています。
第1問 配列:難易度2/5
次の関数transformArray は、整数型の配列 inputArray を引数に取り、特定の条件に従って配列の要素を加工し、新たな配列を返します。配列の要素番号は1から始まります。ここで、inputArray が {4, 9, -1, 3, 12, 8, -3, 5} で与えられた場合、関数transformArray によって返される新しい配列の内容を選択肢の中から選びなさい。
〇整数型の配列:transformArray(整数型の配列: inputArray)
整数型の配列: resultArray ← {}
整数型: i, newValue
for (i を 1 から inputArrayの要素数まで 1 ずつ増やす)
if (inputArray[i] mod 2 = 0)
newValue ← inputArray[i] - 5
else
newValue ← inputArray[i] * 2
endif
if (newValue ≥ 0)
resultArrayの末尾に newValue を追加する
endif
endfor
return resultArray
解答群
ア. {18, 6, 24, 10}
イ. {-1, 18, -2, 6, 7, 3, -6, 10}
ウ. {1, 6, 7, 10}
エ. {0, 18, 0, 6, 7, 3, 0, 10}
オ. {18, 6, 7, 3, 10}
解説
この関数は、配列の各要素に対して偶数なら-5、奇数なら×2を行い、0以上の値のみを出力します。トレース結果は以下の通りです。
したがって、正解はオ. {18, 6, 7, 3, 10}です。
第2問 リスト:難易度4.5/5
関数insertAfterは、1つ以上の要素を持つ単方向リストにおいて、引数qValで与えられた文字列を、引数targetで指定された要素の後に追加する関数です(targetは対象となるデータのアドレスを示します)。リストの各要素は、クラス ListElement によって表現され、大域変数 listHead はリストの先頭要素への参照を保持します。この手続きでは、新たな要素を挿入できた場合には操作を「成功」と、target がリストに含まれない場合には操作を「失敗」として扱います。なお、リストの最後の要素がもつポインタは未定義とします。以下のプログラムを完成させ、適切な操作を行うために空欄を埋めてください。
〇論理型:insertAfter(ListElement: target, 文字型: qVal)
ListElement: newNode, current
newNode ← ListElement(qVal)
current ← listHead
while (current が □□□□□(A))
if (current が target と等しい)
newNode.next ← □□□□□(B)
current.next ← □□□□□(C)
return 成功
endif
current ← current.next
endwhile
return 失敗
解答群
注1,2:図表は公開問題より引用しています。なお、問題の内容は異なります。「出典:基本情報技術者試験(科目B試験)サンプル問題セット」
解説
オブジェクト指向に関する問題です。
以下の図の通り、current.nxetはcurrentのポインタではなくnewNodeのポインタにつながるようにします。したがって、newNode.next ← current.nextとなります(B)。また、newNodeがcurrentのポインタにつながるようにするため、current.next ← newNodeとなります(C)。
current ← current.nextによって一つずつリストを探しています。リストの一番最後まで行くとポインタは未定義となります。この時点で操作は終了するため、currentが未定義でない限り、リストを探し続けることになります(A)。以上より、正解はオです。
難しい問題であるため、最初は解けなくても大丈夫です。オブジェクト指向とリストの性質をおさえることが大切です。
第3問 条件式:難易度1/5
次のプログラム中の□に入れる正しい答えを、解答群の中から選びなさい。関数 leapYear は、西暦年を表す正の整数を引数として受け取り、うるう年であれば true を、そうでなければ false を返します。
うるう年の条件:
西暦年が4で割り切れる年はうるう年である。
ただし、100で割り切れる年は、400で割り切れない限り、うるう年ではない。
〇論理型: leapYear(整数型: year)
論理型: result
if (year を 4 で割った余りが 0) and (□)
result ← true
else
result ← false
endif
return result
解答群
ア (yearを100で割った余りが0)and(yearを400で割った余りが0)
イ (yearを100で割った余りが0)or(yearを400で割った余りが0)
ウ (yearを100で割った余りが0ではない)or(yearを400で割った余りが0)
エ (yearを100で割った余りが0)and(yearを400で割った余りが0ではない)
オ (yearを100で割った余りが0ではない)and(yearを400で割った余りが0)
カ (yearを100で割った余りが0ではない) キ (yearを400で割った余りが0)
解説
うるう年を判定するプログラムです。複雑ですが一つ一つ丁寧にみていけば答えられます。原則として、4で割り切れる年はうるう年です。ただし、100で割り切れる年はうるう年ではありません。ただし、400で割り切れる年はやっぱりうるう年です。言い換えると、4で割れる年のうち、100で割れない場合と400で割れる場合はうるう年と言えます。よって、正解はウ (yearを100で割った余りが0ではない)or(yearを400で割った余りが0)です。
なお、サンプル問題や過去問をみていると、if文中にandやorが出てくることは記憶の限りありません。ただし、以下のようにifを複数回使用してandを表現することがあるため、考え方自体は重要です。
if (year を 4 で割った余りが 0)
if (year を 100 で割った余りが 0)
第4問 ソート:難易度3/5
次の手続きsortは、整数型の配列dataをあるアルゴリズムを用いて昇順に整列します。配列の要素番号は1から始まるとします。手続きsortを実行すると、/*** α ***/の行を最初に実行したとき、配列dataはどのような状態になっていますか。以下の選択肢の中から正しい配列の状態を選びなさい。
大域: 整数型の配列: data ← {2, 9, 3, 8, 5, 6, 4, 1}
〇sort()
整数型: gap, i, j, temp
gap ← 配列dataの長さを2で割ったときの商
while (gap > 0)
for (i を gap + 1 から配列dataの長さまで 1 ずつ増やす)
temp ← data[i]
j ← i
while (j > gap かつ data[j - gap] > temp)
data[j] ← data[j - gap]
j ← j - gap
endwhile
data[j] ← temp
endfor
gap ← gapを2で割ったときの商/*** α ***/
endwhile
解答群:
ア. [2, 3, 4, 1, 5, 6, 8, 9]
イ. [2, 9, 3, 8, 5, 6, 4, 1]
ウ. [9, 8, 6, 5, 4, 3, 2, 1]
エ. [3, 2, 4, 1, 5, 6, 8, 9]
オ. [2, 6, 3, 8, 5, 9, 4, 1]
カ. [2, 6, 3, 1, 5, 9, 4, 8]
解説
シェルソートを用いて要素を並び替えるプログラムです。やや面倒な問題ですがトレースさえできればシェルソートに気がつかなくても必ず解けます。/*** α ***/の部分はgapの値が変わるタイミングです。そのため、トレース表においてgap値が初めて変わる直前のdataの配列が答えになります。したがって、以下のトレース表より答えはカ. [2, 6, 3, 1, 5, 9, 4, 8]になります。
第5問 諸分野への応用:難易度3/5
外国為替市場において、為替レートの変動は経済の重要な指標の一つです。トレーダーや分析家は、短期的な価格変動から長期的なトレンドを読み解くために、移動平均などのテクニカル分析ツールを頻繁に使用します。移動平均は、一定期間の為替レートの平均値を計算し、それを連続してプロットすることで、価格の平滑化された動向を示します。これにより、市場のノイズを除去し、為替レートの本質的な方向性を明らかにすることができます。
あなたは、以下のプログラムを用いて、過去一週間の為替レートデータから3日間の移動平均を計算し、その移動平均のトレンドを分析する任務を担っています。この分析を通じて、為替レートが「上昇」しているのか「下降」しているのか、あるいは「横ばい」なのかを判断することが目的です。
関数 calcMAは、引数で指定された実数型の配列dataから、指定された日数dにわたる移動平均を計算し、それらの移動平均値を格納した実数型の配列を返す関数である。ここで、引数dataは為替レートなどの時系列データを想定しており、dは移動平均を計算する日数を指定する整数です。
関数 trendAnalyzeは、引数で与えられた実数型の配列MAsに格納された移動平均値を分析し、そのトレンドを示す文字列を返す関数です。MAs配列の最後の値と最後から2番目の値を比較して、データのトレンドが「上昇」しているのか、「下降」しているのか、または「横ばい」なのかを判断します。
手続testは、大域の実数型の配列ratesに格納された為替レートのデータを用いて、関数calcMAを呼び出し、指定された日数にわたる移動平均値を計算します。その後、計算された移動平均値を分析するために関数trendAnalyzeを呼び出し、為替レートのトレンドを示す文字列を得ます。
大域: 実数型の配列: rates ← {100, 102, 104, 103, 105, 107, 106}
〇実数型の配列: calcMA(実数型の配列: data, 整数型: d)
実数型の配列: MAs ← 空の配列
for (i を d から dataの長さまで 1 ずつ増やす)
実数型: sum ← 0
for (j を 0 から □□□□□□(A) まで 1 ずつ増やす)
sum ← sum + data[i - j]
endfor
MAsの末尾に (sum ÷ d) を追加する
endfor
return MAs
〇文字列型: trendAnalyze(実数型の配列: MAs)
if (MAsの最後の値 > MAsの最後から2番目の値)
return "□□□□□□(B)"
else if (MAsの最後の値 < MAsの最後から2番目の値)
return "□□□□□□(C)"
else
return "横ばい"
〇test()
実数型の配列: MA_vals ← calcMA(rates, 3)
trendAnalyze(MA_vals)
設問
□□□□□□にあてはまる正しい答えの組み合わせを解答群の中から選んでください(ア~カ)。また、手続きtest処理が終了した直後のトレンドを選んでください(キ~ケ)。
解答群
解説
移動平均法のプログラムです。隣接する3つの要素の平均をとり、その平均のトレンドについて、上昇・下降・横ばいを判断します。i を d から dataの長さまで 1 ずつ増やすことで、隣接する3つの要素のセットを一つ一つ数えあげていきます。
sumには各iにおける対象となる要素の値の合計値が加算されます。i=3のとき、deta配列の要素番号1,2,3の値を合計する必要があります。そのため、sum ← sum + data[i - j]が正しく機能するためには、i=3に対してjは0,1,2と増えていく必要があるため、正解はd-1となります。dにしてしまうとi=dとなり要素番号0となりますが、dataの要素番号は1から始まるため正しくありません。
続いて、MAsの最後の値 > MAsの最後から2番目の値については、昇順になっていることからトレンドは上昇となります。MAsの最後の値 < MAsの最後から2番目の値はその逆で下降です。以上より、オが正解です。
また、手続きtest処理が終了した直後のトレンドは以下のトレース表より、キ.上昇が正解です。なお、すべてトレースしなくても、data[4~6]の平均とdata[5~7]の平均値を計算して、どちらが大きいかを比較して求めることができます。結局のところ、関数trendAnalyzeは移動平均値のうち、最後とその一つ前の要素しか比較していません。
今回の問題は移動平均を知っていればすぐ解けた方もいたかもしれません。ただ、問題文が長く、iがdから、jが0から始まるなどの解きにくさもあります。表でトレースするのが基本ですが、色付きの図表のように、視覚的に動きを把握する解き方もおすすめです。
ちなみに、dataでは104→103、107→106と下降している部分がありますが、移動平均法を取ると常にトレンドは上昇していることが分かります。短期ではなく長期のトレンドが反映されているからです。
さいごに
内容の正確性は保証しかねますのでご了承ください。問題や解答解説に誤りがある場合、私のプロフィールよりご連絡いただけると幸いです。
皆さま試験勉強お疲れ様です。ひっそりと応援しています(^▽^)/
(問題作るの大変だった~~~( ;∀;))