後期試験 ・ 2024 年 1 月 25 日 1 時限実施 ・ ページ
| 授業 科目 |
データ構造とアルゴリズム | 学生番号 | 学科 | 学年 | 組 | 番 | フリ ガナ |
評点 | ||||||||
| 氏名 | ||||||||||||||||
| 担当者 | DÜRST, Martin J. | |||||||||||||||
次の英語の用語に相当する日本語の用語を書いて、簡単に説明しなさい。日本語の用語ではカタカナをできるだけ避けなさい。
ただし、部分問題 11 以降は詳細に説明しなさい。
後期試験 ・ 2024 年 1 月 25 日 1 時限実施 ・ ページ
ヒープの主な用途を二つ書きなさい。 (4 点)
ヒープの普遍条件を三つ説明しなさい。(9 点)
ヒープはよく配列で実装される。その場合、次の文が正しくなるように空欄を埋めなさい。(6 点)
合計の項目数が n のヒープで、あるデータ項目が配列の k 番目の場所にある場合、その親は
k / 2 番目の場所で、
左の子が
k*2 番目の場所で、右の子が
k*2 + 1 番目の場所になる。
0 番目の場所は使用されない。
ヒープの普遍条件の修復には heapify_up 関数と
heapify_down 関数が使われます。
両方の関数の計算量は一般的に
O(log n)
である。
ヒープの普遍条件を修復するために、heapify_up 関数と heapify_down
関数が使われます。heapify_up の
疑似コードを書きなさい。ヒント:
前の部分問題 (穴埋め) が分からない場合、parent などの関数で表すとよい。 (12 点)
algorithm heapify_up (前提: 大きい方が優先度が高い)
inputs: heap (as an array, length len)
position p (of element to push down)
output: heap (with position of data at original position p fixed)
while true
break_while if p = root
parent_p = parent(p)
if heap[p] > heap[parent_p] then
heap[p], heap[parent_p] = heap[parent_p], heap[p]
p = parent_p
else
break_while
end
end_while
end
heapify_up 関数などの一般的な計算量にもかかわらず、n
個のデータ項目から一気にヒープを作るときの計算量が O(n) で
可能ということが知られている。その理由を詳しく説明しなさい。(8 点)
ヒープの作成は、データを配列にいれ、そこから木下の項目からスタートして各項目で heapify_down を使って親子の順番を優先度に合わせる。n この項目に O(log n) の heapify_down を適応すると、一般には O(n log n) になるが、一番下の層では heapify_down は使わなくてもいいし、その次の層では O(1), その上の層では O(2),... と項目ごとに時間がかかる。逆に一番下の層の項目数は全体の半分で n/2 で、その次の層ではさらに半分の n/4 です。 そのため、全体の計算量は 0*n/2 + 1*n/4 + 2*n/8 + 3*n/16 + ... と表せる。これを総和として解くにはテイラー展開が必要ですが、結果は O(n) になる。
後期試験 ・ 2024 年 1 月 25 日 1 時限実施 ・ ページ
| 授業 科目 |
データ構造とアルゴリズム | 学生番号 | 学科 | 学年 | 組 | 番 | フリ ガナ |
評点 | ||||||||
| 氏名 | ||||||||||||||||
| 担当者 | DÜRST, Martin J. | |||||||||||||||
ハッシュ表の主な用途を書きなさい。 (2 点)
辞書という抽象データ型の実装
ハッシュ表の全ての実装に共通の仕組みを説明しなさい。(5 点)
データ項目の場所は、キーから計算されるハッシュ関数の結果で決まる。 ハッシュ関数はキーをできるだけバラバラに分散させるように設計されるが、ダブっている場合、激突が起き、その対応にはさまざまな種類がある。
ハッシュ表では実装上で激突が大きな課題となる。激突対策を一つ選んで、細かく説明しなさい。(6 点)
開番地法を選びます: データ項目をキーから計算したハッシュ関数を使って、大きな配列に収める。 激突の場合、再度別の結果をだすハッシュ関数 (簡単な場合、元のハッシュ関数+1) を使い、これを空いている場所が見つけるまで繰り返す。削除した場合は特別なキーを使う必要がある。占有率 α は <=0.5 がいい。
ハッシュ表と同じ用途で使える実用的なデータ構造を、
内部メモリ用・外部メモリ用に分けて合計5つの
名前と簡単な説明を書きなさい。 (10 点)
内部メモリ用
外部メモリ用
ハッシュ表の利点を、同じ用途のデータ構造と比較して書きなさい。(4 点)
上記の五つのデータ構造はすべて探索木です。辞書の主な操作 (挿入、探索、削除) は探索期の場合は、すべて O(log n) ですが、ハッシュ表の場合 O(1) になります。
ハッシュ表の欠点を、同じ用途のデータ構造と比較して書きなさい。(2 点)
探索木の場合、通り掛け準でデータをキーの順で出せるが、ハッシュ表ではソートは別途発生する。
ハッシュ表にどんどんデータ項目を挿入すると激突対策の効率が落ち、表を拡大する必要がある。そのたび、O(n)
の計算量が
発生するが、ハッシュ表の効率は落ちることがない。
その理由を分析し、分析の名前とその名前の理由とともに書きなさい。(8 点)
項目を入れるたびに表を拡大すれば、n 個のデータの挿入に 1+2+...+n で O(n2)
がかかり、一つのデータ項目あたりに O(n) となる。そこで n が倍になるときだけ拡大を行うと、1+2+4+8+...+n/2+n
で全体で O(n) で、データ項目ごとに O(1) になる。これを償却分析という。
償却分析の名前は会計学からきて、票の拡大の時に投資をし、その後の項目の追加でその投資を償却するのが名前の由来。
後期試験 ・ 2024 年 1 月 25 日 1 時限実施 ・ ページ
下記の三つの事情に合わせて、整列アルゴリズムを実装するように頼まれた。
適切なアルゴリズムを選び、そのアルゴリズムの名前、
仕組み、選んだ理由と実装の際に特に注意すべき点を記述しなさい。
You have been asked to implement a sorting algorithm for each of three situations below.
Select algorithms and give name, workings, the reason for the selection,
and points that need special care during implementation.
この授業で一番分かりにくかったことを書きなさい。 (決まった正解はありません。)
What was most difficult to understand in this course? (there is no definite answer)
@@@@
@@@@
この授業で一番勉強になったことを書きなさい。 (決まった正解はありません。)
What topic in this course was most interesting for you? (there is no definite answer)
@@@@
@@@@
一回目の授業では参考書の購入 (又は貸出) と熟読が強く薦められました。熟読した参考書の詳細を書きなさい。
石畑清著、アルゴリズムとデータ構造、
岩波講座ソフトウェア化学、岩波書店
後期試験 ・ 2024 年 1 月 25 日 1 時限実施 ・ ページ
| 授業 科目 |
データ構造とアルゴリズム | 学生番号 | 学科 | 学年 | 組 | 番 | フリ ガナ |
評点 | ||||||||
| 氏名 | ||||||||||||||||
| 担当者 | DÜRST, Martin J. | |||||||||||||||
授業で習った文字列照合アルゴリズムのうち、一番速いものを選んで、その速さの理由を中心に説明しなさい。(8 点)
一番早い文字列照合アルゴリズムは Boyer-Moore アルゴリズムです。 なぜかというと、一般の場合、計算量は O(n/m) である。この場合、n は文書の長さで、m は探しているパターンのながさ。Boyer-Moore アルゴリズムの決めては、 パターンとの照合を前からのではなく、後ろから行うということです。 パーターンの一番後ろの文字が「合うか合わないか」だけでわなく、 合わなかったら文書の文字はどの文字なのかも考慮する。 その文字がパターンのの中に全くない場合、パターン一個分にパターンをすらすことができるので、 一番最前の場合、 一個の比較で m 文字進むので、O(n/m) になる。
上記のアルゴリズムが、アルファベットの大きさ (文字の種類の数) によって、どのように影響されるか論じなさい。(6 点)
アルファベットが大きい場合 (例えば東洋の言語で数千字) ではほとんどの場合、末尾での比較対象がパターンに 入ってない可能性が非常に高く、効率がいい。逆にアルファベッツが小さい (例えばヌクレオチド列で4字、ビット列で2字) 場合、 比較対象がパターンの他のところに存在する確率が高く、効率が落ちる。
四つの行列の連鎖乗算 0M1 · 1M2 · 2M3 · 3M4 が与えられている。 行列の大きさは r0=12, r1=5, r2=10, r3=3, r4=8 である。
最善の計算順とその場合のスカラー値同士の乗算の数を求めなさい。 計算の過程や途中結果も書きなさい。(10 点)
0M1 · 1M2 の乗算数は 600、
1M2 · 2M3 は 150、
2M3 · 3M4 は 240;
0M3
は 0M1 · 1M3 で乗算数が 0+150+180=330 で,
0M2 ·
2M3 で 600+0+360=960 なので、 前者が 330 で最善;
1M4
は 1M2 · 2M4 で 0+240+400=640 で、
1M3 ·
3M4 で 150+0+120=270 なので、後者が 270 で最善。
0M4 は
0M1 · 1M4 で 0+270+480=750 で、
0M2 · 2M4 で 600+240+960=1800 で、
0M3 · 3M4 で 330+0+288=618 で、
0M1 · 1M4 が 618 で最善。
よって、乗算の順番は (0M1 ·
(1M2 ·
2M3) ·
3M4 で最善。
逆に最悪の計算順とその場合のスカラー値同士の乗算の数を求めなさい。
計算の過程や途中結果も書きなさい。
前の部分問題の計算をもう一回書く必要がない。(8 点)
0M3
では 0M2 ·
2M3 が 960 で最悪。
1M4
では 1M2 ·
2M4 が 640 で最悪。
0M4 は
0M1 · 1M4 で 0+960+480=1440 で、
0M2 · 2M4 で 600+240+960=1800 で、
0M3 · 3M4 で 960+0+288=1248 で、
0M2 · 2M4 が 1800 で最悪。
よって、乗算の順番は (0M1 ·
1M2) ·
(2M3 ·
3M4) で最悪。
後期試験 ・ 2024 年 1 月 25 日 1 時限実施 ・ ページ
下記の課題に対して、下記の最初の四つの部分問題のアルゴリズムの設計方針や原理を使った際の、
それぞれのアルゴリズムの
概略を提案しなさい。また、それぞれに対し、予想される計算量とその根拠、発生する問題点について述べなさい。
For the problem explained below, in the first four subproblems propose ideas for algorithms
using the respective
algorithm design strategies. In each case, indicate the expected time
complexity and the reason for it,
and the problems when using this design strategy.
注: この問題の目的は、最適な結果をもたらすアルゴリズムの発見よりも、設計方針の知識の応用である。
Caution: The purpose of this problem is to show you can apply your knowledge about design strategies,
rather than to design the best algorithm.
課題: メモリの割り当て問題: 合計のメモリ量 m (単位: バイト) に対し、n 個のデータ (k 個目のデータは大きさ
lk のメモリを
時間 sk から時間 tk (単位: 秒)
まで使用すること)でできるだけ最適なデータの割り当てを算出する問題。
分割統治法 / divide and conquer
データを再帰的に二つの集合に分け、最初は二つのデータだけの組み合わせの配置を作る。 その組み合わせを逆順で統合しておく。最善の計算量は O(n log n) だが、組み合わせがうまくいかないケースが所持る可能性がある。 分割のところで、できるだけ組み合わせしやすい分割を選ぼうとすると、いいかいが見つけやすくなるが、計算量が増える可能性もある。解を見つける保障がないのが問題。
貪欲アルゴリズム / greedy algorithm
データを大きさまたは時間の長さでソートする。大きいまたは時間的に長いデータの方から 割り当てを試してみる。大きさx長さの積の順でもいいかも。計算量はソートが必要なため O(n log n)。解を見つける保障がないのが問題。
遺伝的アルゴリズム / genetic algorithm
第1世代としてデータの割り当てをいくつか作る。次の世代を作るとき、 前の世代の案を二つ (以上) を組み合わせ、新しい解を作る。その時、乱数で突然変異みたいな変更も加える。 いい解を多めに残し、悪いかいを多めに捨てるように次の世代を構成する。計算量は O(世代数x解の数xn) で相当大きい。細かい設定が課題です。
動的計画法 / dynamic programming
データを開始時間 (sk) でソートする。最初は一秒ごとに局所的な配置を計画する。 そこから隣り合わせの解を組み合わせ、2秒、3秒、とどんどん長いスパンの解を作る。計算量は O(n*全体の時間2) で、解を見つける保障がないのが問題。
社長に「この問題を明日の朝まで解かないうちの部署が危ない。」と言われたときの返事の概略を書きなさい。
なお、メモリの割り当て問題を調べたところ、NP困難問題であることが判明した。
大変申し訳ございませんが、この問題は 3-SAT 問題、独立集合問題や巡回セールスマン問題をはじめ多くの問題と同様に NP 困難であり、いまだに必ず早い時間 (指数的時間で数年以上のではなく、多項式時間で明日の朝まで) で完璧に解けるアルゴリズム (方法) が見つかっていません。 万が一見つかったら世紀の大発見になり、一億円以上の賞金も貰える。 多くの専門家はそれが無理だと思っているが、その証明もいまだできていません。
後期試験 ・ 2024 年 1 月 25 日 1 時限実施 ・ ページ
| 授業 科目 |
データ構造とアルゴリズム | 学生番号 | 学科 | 学年 | 組 | 番 | フリ ガナ |
評点 | ||||||||
| 氏名 | ||||||||||||||||
| 担当者 | DÜRST, Martin J. | |||||||||||||||
O 記法は定義上いくつかの特徴をもつ。以下の特徴がなぜアルゴリズムの評価に適しているのか、それぞれ説明しなさい。
Big-O notation by definition has a number of properties.
For each property, explain why it is suitable
for the evaluation of algorithms.
一定数までの差が無視される。 / Difference up to a constant is ignored.
一定の差 (例えば数ミリ秒や数秒) は初期化や準備の実装の差などで出る可能性があるが、 データの項目数が増えると全体の実行時間がどんどん伸びるので、一定時間の差はアルゴリズムの比較に必要な根本的な差のではなく、 実装の詳細による差に過ぎないので、無視した方がいいです。
定数の倍数が無視される。 / A constant multiple is ignored.
様々な計算機の実行速度のさにより、プログラム言語や実装によっても速度の差が出るし、 最近は並列化も注目されているが、それによって一定の倍数の差が出るが、それ以上の差が出ません。 アルゴリズムの評価では実装の詳細のではなく、アルゴリズム (すなわちアイディア) そのものを評価したいので、定数の倍数を無視した方がいい。
対数の底が不要。 / The base of a logarithm is irrelevant.
これは次の特徴の「定数の倍数を無視できる」ことの結果である。対数の場合、底の変更は定数との掛け算で可能で。 例えば logax = logbx * logab である。この場合、logab は定数なので、無視してもよい。
O 記法でどの場合に対数の底が無視できるのかを、次の O 記法の対で判断し説明しなさい。
Using the following pairs of big-O notations,
decide whether the base of a logarithm can always be ignored or not and explain.
O(2log2n) と/and O(2log4n) O(nlog2n) と/and O(nlog4n)
前者の場合、2log2n = n ですが、2log4n = n1/2
(n の平方根) なので、明らかに伸び率が違う。
後者の場合、log4n を 1/2*log2n と書き換えると、
nlog4n = n1/2*log2n で、これも
nlog2n の平方根になって、明らかに伸び率が低い。
よって、O 記法では係数での log の底は無視できるが、指数では log の底は無視できません。
プログラミング言語によるアルゴリズムの表現方法の利点と欠点を書きなさい。
利点 (2 点): プログラミング言語は正確で、そのまま (コンパイル後) に実行可能。
欠点 (2 点): 場合によって細かすぎる。言語が分からない人にはわかりにくい。
プログラミング言語として C と Ruby を比べると、どちらがアルゴリズムの表現に向いているのか、
そしてその理由を詳しく書きなさい。(4 点)
Ruby だと思います。なぜかというと、行末にセミコロンが不要で、変数の宣言も不要で余計な記述がいらない。 関数や変数に型を指定する必要もないので、同じ記述を複数の型 (例: 整数と実数) に使える。高度でアルゴリズムの本質に近い記述可能です。