プログラミングに関する基礎的な知識を測るクイズ10問をお送りします。様々な言語やコンセプトをカバーしており、プログラミングの理解度を確認するのに役立つでしょう。ラムダ式、文字列比較、イベントループ、SQLクエリ、ソートアルゴリズム、バージョン管理、メモリ管理、正規表現、動的配列など、プログラミングの重要なトピックを網羅しています。クイズに挑戦して自分の知識を確認し、更なる学習の糸口を見つけてください。
Q1 : git rebaseの説明として正しいものはどれか?
git rebaseは現在のブランチの一連のコミットを取り出して指定した別の基底(ベース)上に順に再適用することで履歴を書き換え、コミット列を線形化します。これによりマージコミットなしで履歴をきれいに保てますが、既に共有したコミット(公開された履歴)をrebaseして書き換えると他の開発者との整合性が崩れるため注意が必要です。
Q2 : C言語において配列とポインタの表現の違いについて正しいのはどれか? int a[3]; に対してどれが正しいか?
C言語では配列名aは式文脈で先頭要素へのポインタに変換されてint*として扱われますが、配列そのもののアドレスを取ると& aは配列全体の型int (*)[3]になります。したがってaと&aは数値的には同じアドレスを示すことがありますが型は異なり、ポインタ演算の意味も変わります。配列とポインタの振る舞いを混同しないことが重要です。
Q3 : PythonのGIL(Global Interpreter Lock)について正しい説明はどれか?
GILはCPythonインタプリタの実装における排他ロックであり、同一プロセス内で複数のPythonスレッドが同時にPythonバイトコードを実行することを防ぎます。そのためCPUバウンドなスレッド処理では真の並列実行が行えず性能が伸びない場合があります。一方、I/O待ちの多いスレッドやマルチプロセス(multiprocessing)や拡張モジュール(Cでスレッドを解放するもの)を使えば回避可能です。
Q4 : 正規表現におけるQuantifierのうち .*? の意味として正しいものはどれか?
.*?は量指定子の非貪欲(最短一致)バージョンであり、.は任意の1文字、*は0回以上を意味します。末尾の?は量指定子を非貪欲にする修飾子で、可能な限り短いマッチを返します。対照的に.*は貪欲でできるだけ長くマッチします。具体的にはテキスト中でタグなどの間を最短で抜き取りたい場合に使うと有効です。
Q5 : 動的配列(例:C++のstd::vectorやPythonのlist)への要素追加(append)の計算量の振る舞いとして正しいものはどれか?
多くの動的配列実装は容量が足りないときに内部配列を倍増するなどの再配置を行います。個々の追加操作は再配置が発生するとO(n)のコストになりますが、再配置は頻繁に起きないため多数の追加操作に対して合計コストを平均化すると1操作あたりの平均コストは定数時間、つまりアモータイズド(平均的に)O(1)になります。これを理解すると、頻繁なappendがある場合でも通常は高速に動作します。
Q6 : 次のPythonコードの実行結果として出力される値は何か? funcs = [lambda x: i*x for i in range(3)]; print(funcs[0](2))
このコードはクロージャと遅延束縛(late binding)の例です。リスト内包表記で作られた各ラムダは外側の変数iを参照しますが、ラムダ実行時に現在のiの値が使われます。ループが終わるとiは2になっているので funcs[0](2) は2*2=4を返します。対策としてはラムダ作成時にデフォルト引数でiの値を固定する(lambda x, i=i: i*x)などがあります。以上より出力は4です。
Q7 : JavaでString同士を比較するとき、==とequalsの違いとして正しいのはどれか?
==演算子はオブジェクトの参照(アドレス)が同じかどうかを比較します。equalsはクラスの実装次第で意味するところが異なりますが、Stringクラスではオーバーライドされており文字列の内容(文字列コンテント)を比較します。したがって同じ文字列リテラルや同じ内容の別インスタンスはequalsでtrueになり、==では参照が違えばfalseになります。
Q8 : 次のJavaScriptコードを実行したときのコンソール出力の順序として正しいものはどれか? console.log(1); setTimeout(()=>console.log(2),0); Promise.resolve().then(()=>console.log(3)); console.log(4);
ブラウザやNodeのイベントループにおいて、マイクロタスク(Promiseのthenなど)はマクロタスク(setTimeoutなど)よりも優先されます。コードは順に同期で1を出力し、setTimeoutがマクロタスクキューへ登録され、Promise.thenはマイクロタスクキューへ登録され、次に同期で4を出力します。現在のターン終了後にマイクロタスクが処理されて3が出力され、その後マクロタスクで2が出力されます。したがって順序は1,4,3,2です。
Q9 : SQLでGROUP BY句とHAVING句の使い方について正しい説明はどれか?
WHERE句はGROUP BYでグループ化される前の行に対するフィルタリングに使用し、集計関数での条件指定には使えません。一方HAVING句はGROUP BYで生成された各グループの集計結果に対する条件を指定するために使います。例えばSUMやCOUNTに対する閾値条件はHAVINGで行い、個々の行の列値によるフィルタはWHEREで行います。これにより効率的なクエリ設計が可能になります。
Q10 : 平均ケースの時間計算量がO(n log n)となるソートアルゴリズムはどれか?
クイックソートは典型的に平均時間計算量がO(n log n)であり、最悪ケースはピボットの選び方によってO(n^2)になります。バブルソートや選択ソートは平均・最悪ともにO(n^2)であり、挿入ソートは入力がほぼ整列している場合は高速ですが平均はO(n^2)です。クイックソートは実装やピボット選択(中央値選択等)によって安定的に良い平均性能を発揮します。