このドキュメントは http://edu.net.c.dendai.ac.jp/ 上で公開されています。
プログラムで扱うデータ構造としてグラフを取り上げます。 グラフとは頂点とそれを結ぶ辺からなるものです。
頂点は vertex、 節、 node などの呼び方があります、辺は edge、枝、 branch とも言います。 辺に向きがないグラフを無向グラフ、 辺に向きがあるグラフを有向グラフと言います。
互いに接続している頂点の列を道(path)と言います。 無向グラフにおいて、全ての頂点の組合せについて道がある場合、そのグラフ は連結であると言います。
頂点に接続している辺の数をその頂点の次数、degree 、arityと言います。 有向グラフにおいては出る辺の数を出次数、out degree、入る辺の数を入次数、in degreeと言 います。
グラフには様々な形があり、それについて名前が付けられています。 無向辺において、木とは、ループのない連結グラフのことを言います。 次数が 1 の頂点を葉、leafと言います。
根付有向木とは、次の条件を満たす有向グラフのことです。
根付有向木で接続している二つの頂点に対して、辺が出る頂点を親 、辺が入る頂点を子と言います。 出次数が 0 (入次数が 1)の頂点を葉と言います。 根付有向木において、出る辺の数が高々 2 本の木を二分木、 二進木、binary tree と言います。
頂点が 4 つの二分木は何種類あるか? 実際に作図して求めなさい。
二分木において、葉にだけ値を割り当てたものを考えます。中間の頂点を . と し丸括弧でくくると次のような式で表すことができます。 これをS 式と呼びます。
S 式を表す二分木において、さらに右側の枝に接続する葉に nil が割り当て られたものをリストと呼びます。 nil とはなにもないことを示す値のことなので、 を と書くことがあります。 このリストはプログラムで処理する時に番兵として使用します。 一方、 を省略して と表現します。
以下に例を示します。
ここでさらに左側の枝には必ず葉が接続するリストに限定して考えると次のような構造になり ます。 これを線形リストと呼びます。
なお、プログラミング言語 LISP, Prolog, Logo はリスト構造を扱え、演算が 可能です。 v
次のリストを木で図示しなさい。
リスト構造は式を表せるだけでなく、構造体なども表せます。
例えば、次の構造体の場合 (point (x double) (y double))
のように表せます。
struct point {
double x;
double y;
};
すべての頂点の次数が 2 の連結グラフは リング になります。
また、すべての頂点間に辺がある無向グラフを完全グラフと言い ます。
頂点数が n の完全グラフの辺の数を求めなさい。
頂点が二つのグループに分割でき、同じグループ同士には辺がないグラフを 二部グラフと言います。 特に、異なるグループのすべての頂点の組み合わせに辺がある無向二部グラフ を完全二部グラフと言います。
頂点数が n, m の完全二部グラフの辺の数を求めなさい。
コンピュータで情報処理をする際、情報をグラフの形で抽象化して処理するこ とがしばしばあります。 そこで、コンピュータでグラフを表現するしかたを考えます。
プログラムへの入出力のために、単純に文字列としてのやりとりを考えます。 そのため数学的に基本的な記述を考えます。
まず、集合の演算である 直積 を導入します。集合 A の要素と集 合 B の要素のすべての組にしたものを新たな要素とした集合を A と B の直 積と言い、 A × B と書きます。数学の記号で書くと次のようになります。
さて、まず、グラフの頂点にはすべて名前が付けられているとします。頂点の名前の 集合を V とします。 すると、辺は二つの頂点の組み合わせで表せますので、辺の集合を E とする と、頂点の集合と頂点の集合の直積の部分集合になります。 なお、有向グラフでは辺は (出発点,終着点) で表すことにします。
グラフは頂点と辺からなりますので、頂点の集合の要素と辺の集合の要素をそ れぞれ列挙すればグラフを表現できることになります。 下のグラフを要素の列挙で表現すると次のようになります。
頂点数が n の有向グラフでは最大でいくつの要素を列挙する必要があるか求 めなさい。
頂点の数が n 個の時、n × n の正方行列を考えます。 もし、 i 番目の頂点から j 番目の頂点へ辺がある場合 (i,j) 成分を 1 に、 なければ (i,j) 成分を 0 にしたものはグラフの構造を表すことができます。 このような行列を 隣接行列 と言います。 なお、無向グラフで i と j に辺がある場合、 (i,j) 成分と (j,i) 成分をと もに 1 にします。
次のグラフの隣接行列を求めなさい。
頂点を構造体とし、辺をポインタで表す方法でもグラフを表現できます。 構造体の中には、頂点の名前と、接続する頂点へのポインタの列を含めます。 もし、各頂点の出次数が制限されていれば構造体の中はポインタの配列になり ます。例えば出次数が 2 であれば次のような定義になります。
struct vertex {
char *name;
struct vertex *edge[2];
};
しかし、出次数に制限がなければ辺を表す頂点へのポインタを値として持つ線 形リストへのポインタになります。
struct edgelist {
struct vertex * edge;
struct edgelist *next;
};
struct vertex {
char *name;
struct edgelist *edges;
};
プログラムの実行時間を評価することを考えます。 コンピュータの性能は個々に違い、また入力によってもプログラムの動きは変 わるので、特定の条件での実時間の計測にはあまり意味はありません。 計算量理論では、プログラムの実行時間の評価をするため、次のようなアプロー チをしています。
コンピュータの実行時間を考えるため、まず、数学的に確立したコンピュータ のモデルとして Turing 機械 を考えます。 これは、外部記憶装置として、マス目のついた無限長のテープを考え、そのテー プにひとマス書き込み、隣のマスをアクセスする時間を一単位時間と計測しま す。
この Turing 機械は通常の計算機と比較して、計算が可能かどうかの能力差は なく、実行時間のステップ数も二乗程度で収まることが知られています。 この Turing 機械は数学的なモデルなので、定理の証明に使うことができます。 そして、プログラムの実行時間に関わるいくつかの定理が知られています。
一つの関数を計算するプログラムは無限に存在する
実行時間が t のプログラムが存在する時、それを c 倍速く計算する別のプロ グラムが存在する。
また、特定の入力に対してはあらかじめ答を覚えておき、プログラムの実行時 に入力が特定の値かどうか調べて、もしそうならその答を出すような改造をす ることができます。 以上のことにより、プログラムの計算時間は単純な数値や関数では表せないこ とが分かります。
そこで計算時間は通常 オーダー という尺度で計られます。 オーダーとは関数の増え方を大雑把に捉える方法です。 端的に言えば、実行時間を入力の長さの関数として表した時、最大次数の項に ついて係数を無視したものを尺度として使うと言うものです。 例えば、実行時間が入力の長さ n に対して、 だった場合、最大次数は 3 でその係数を無視して で表します。 このようにすると、定数倍速いプログラムや、一部の入力について速いプログ ラムも同じオーダーになりますので、プログラムの速さを適切に表現できたこ とになります。 因みにオーダーの数学的な定義は次のようになります。
関数 、 が であるとは次を満たすことを言う。 ある定数 が存在し、すべての に対して が成り立つような定数 c を見つけられることである。
次のプログラムの実行時間を評価しなさい。 但し、数値の代入、計算などは、取り扱っている数値の最大の値を n とする と だと評価しなさい。
int double(int x){
return x*x;
}
int factor(int x){
int i,f;
f=1;
for(i=2; i<=x; i++){
f*=i;
}
return f;
}
Java の SDK(Software Development Kit) に、グラフを表示するデモアプレッ トがあります。次のようにすると表示されます。
cd (Java SDK のインストールしているディレクトリ)demo/applets/GraphLayout appletviewer example1.html