View
2
Download
0
Category
Preview:
Citation preview
1
1
プログラミング言語2
おまけ
データ構造の基礎と応用
2/55
この資料の目的
� データ構造に関して取り扱う。
� データ構造とは何か?
� 基本的なデータ構造と実現方法
� リスト
� スタック
� キュー
� 木
2
3/55
プログラムとデータ構造
� プログラム:
入力データを加工しつつ、正しい出力
を求めていくプロセスの記述
� データ構造:
コンピュータにどのように組織化して格
納するか
� データの格納方法が異なれば、その
加工の仕方も変わる。
� プログラム=アルゴリズム+データ構造
入力
データ
データ
出力
データ
…
格納加工加工
4/55
データ構造とは何か
� データ構造を考える目的
� データの保存の仕方
� これがなければ、プログラムを作成できない
� 操作の簡略化
� 確実に動作するプログラムの作成
� プログラミングのし易さの向上
� 操作の高速化
� 目的の速度を達成するプログラムの作成
3
5/55
プログラムを書くに当たって
� アルゴリズムとデータ構造を考える
� そのデータ構造とアルゴリズムは
� 十分な早さを実現できるか?
� 逆に、目標の速度を達成できれば、それ以上は不必要
� プログラムしやすいか?
� 人為的ミスが発生しては困る
� そのデータ構造を計算機言語で実現できるか?
� 例えば、BASICには構造体は無い。
� 正確にプログラムに書きくだす。
6/55
データ構造の作成
� 計算機言語上でデータ構造を実現するのに使用
できる、代表的な型の簡単な紹介をする。
� 構造体
� ポインタ
� 配列
� 集合
4
7/55
構造体
� 幾つかのデータを、ひとまとめにした型。
� 構造体を構成するそれぞれのデータを、メンバと言う。
� 各メンバの型は異なっていても良い。
� この講義では、次のように図示する。
abc10
10
一つの構造体
メンバその1
メンバその3
メンバその2
8/55
� 関係するデータをひとまとめにできる。
� データの受け渡しなどで、一度に引き渡せる。
構造体の使い道・特徴
Tarou
10
80
成績を保存する構造体
出席番号
名前
成績
例:
� 口述するリスト構造の実現等では便利。
5
9/55
ポインタ(リンク)
� 変数のアドレスに対応する型。
� つまり、変数の保存している値そのものではなく、
変数のある場所を保存している。
� 「どこどこにある、値を取り出せ」 「どこどこに、ある
値を書き込め」という手順でデータを更新する
� この講義では、次のように図示する。
1
1010 a
整数型へのポインタ 文字型へのポインタ 構造体へのポインタ
tmp tmp$ tmp
10/55
ポインタの使い道・特徴
� プログラムの実行中に、作成・削除することができる
ので、データ構造を動的に変化させることができる。
� C言語等では、文字列を扱うのに必須。
� C言語等では、関数への変数の受け渡しに必須。
例:
� 口述するリスト構造の実現等では便利。
6
11/55
配列
10a
25
1次元配列
a[0]の値a[1]の値a[2]の値 a 10 1 3 1 5 1
2 3 6 12 15 215 7 3 3 1 5
a[0][0]の値 a[1][2]の値a[2][5]の値2次元配列
� 変数を並べたもの。
� 値を蓄えられる箱が沢山ならんでいて、
その箱がナンバリングされているようなもの。
� この講義では、次のように図示する。
12/55
配列の使い道・特徴
� ナンバリングされているので、for 文の中などで取り
扱うのに便利。
� C言語等では、関数への値の引き渡しにも使える。
for i:=1 to 10 dobegin
a[i]=i……
end
7
13/55
集合型
� あらかじめ決められた要素から構成される集合を取
り扱うことができる。
� 集合に対する演算を行うことができる。
� 本講義では、取り扱わない。
61
3
6
5 2∩
6
5 21
3=
14/55
基本的なデータ構造
� 基本的なデータ構造を説明する
� リスト
� スタック
� 順序行列
� 二分木
8
15/55
リストとはなにか
1
10
5
1
10
5
1
10
5
1
6
5
6
6
1
5
6
10
� 要素を1列に並べたものをリストという。
� 任意の1つの要素を参照することができる。
� 任意の場所への挿入の操作ができる。
� 任意のデータの削除の操作ができる。
16/55
リストの特徴
� 任意の場所への追加、任意の場所の削除ができる
ので、動的に長さの変わるリストを作りやすい。
� 任意の場所のデータの参照ができる。
� 様々な形のデータ構造が作れる。
9
17/55
スタック
� 要素は1列に並んでいる(つまり、リストの1種である)
� 先頭のデータを取り出すことができる
� 先頭にデータを積むことができる。
取り出したデータを参照する。
1
10
5
1
10
5
1
10
5
1
10
5
6
1
10
5
6
1
10
5
6
最後に入れたものが
最初に出てくる
18/55
スタックの使い道・特徴
� スタックへ積む動作(push)と、取り出す動作(pop)し
か無いため、実現が容易である。
� 一時的にデータを保存するときなどに便利。
� スタックを利用している例。
� スタック言語(スタックを利用した計算機言語)
� forth
� PostScript
10
19/55
キュー
1
10
5
1
10
5
6
1
10
5
6
1
10
5
6
1
10
6
1
10
6
� 要素は1列に並んでいる(つまり、リストの1種である)
� 最後尾にデータを積むことができる。
� 先頭のデータを取り出すことができる。
取り出したデータを参照する。
最初に入れたものが
最初に出てくる
20/55
キューの使い道・特徴
1105
先頭 最後尾
� 最後尾に追加する作業と、先頭と取り出す作業しか無
いので、実現が容易。
� リング状のキューを
作ることも多い。
ex. キーバッファ
11
21/55
木
� 木は、次の性質を満たす節点の集合と辺の集合
1. 根といわれる、特別な節点が存在する。
2. 根とそれ以外の任意の節点の間に、丁度1つだ
け道があるもの。
3. それぞれの節点には、名前が付けられているこ
とが多い。
21
0
43
6
5
根
根から5への道
22/55
木の特徴
� 図示する場合、根に近いほど上に書く。
� 根以外の節点は、上に1つだけ、直接結線された節点を持つ。
これを親親親親とよぶ。
例:4の親は1。
� 下に居るものを子子子子と呼ぶ。
例:1の子は3と4。
� 子を持たない物
を葉葉葉葉と呼ぶ。
� 根からの節点
数をレベルという
21
0
3
6
根
葉
4 5
12
23/55
二分木
� 各節点の子の数が2以下で、右にいる子か左に居
る子かを区別する木。
二分木では無い例 正しい二分木の例
子が3つある!右の子か左の子か分からない!
24/55
完全二分木
� 完全二分木とは?
� 一番下の層以外は完全に埋められていて
� 一番下の層のデータは、左に詰められている二分木
完全二分木では無い例
正しい完全二分木の例
一番下の層なのに左詰でない!完全に埋まってない!
13
25/55
木の特徴
� データが1次元上に並んでいるリンクとことなり、データが2次元上に並んでいる。
� データ構造の中心的役割を果たすことが多い。
つまり、応用範囲が広い。
� 数学的対象としても広く研究されている。
� リストやスタックも、木の1種であるとも見える。
26/55
基本的なデータ構造の実現
� 基本的なデータ構造の実現の例を示す
� リスト
� スタック
� 順序行列
� 二分木
14
27/55
構造体とポインタによる
リストの実現(構造)
1データ領域
構造体へのポインタ
1 10 5
null
1. 次のような構造体を定義する。
2. ポインタが次々と次の構造体を指すことで、リストを
実現する。
init
28/55
構造体とポインタによる
リストの実現(データの追加(1))
1. 追加するデータの構
造体を作成
1 10 5
null
6init
1の次に6を追加したい!
tmp1 tmp2
1 10 5
null
6init
2. 追加したい場所をし
めすポインタを作成
tmp1 tmp2
15
29/55
構造体とポインタによる
リストの実現(データの追加(2))
1 10 5
null
6init
3. 追加するデータのポインタを設定する これと同じ要素を指すようにする
tmp2tmp1
1 10 5
null
6init
4. 追加するデータを指すポインタを設定する
これと同じ要素を指すようにするtmp2
tmp1
30/55
構造体とポインタによる
リストの実現(データの追加(3))
� 順番を間違えると失敗するので注意
� 例えば、ステップ3とステップ4の順番を間違えると、10というデータを蓄えている場所がわからなってしまう!
1 10 5
null
6init
行方不明に!tmp1 tmp2
5. いらないものを消す1 10 5
null
6init
tmp1 tmp2
16
31/55
構造体とポインタによる
リストの実現(データの参照)
1 10 5
nullinit
� 先頭から順番に参照していく。例:2番目のデータが欲しい!1つ目 2つ目例:値5の1つ前のデータが欲しい!
1 10 5
nullinit 要保存しておく領域が必つ前に読んだデータを1
32/55
1. 次のような構造体を定義する。
2. ポインタが次々と次の構造体を指すことで、実現
構造体とポインタによる
双方向リストの実現
1 10 5
null
init last
null
null
データ領域
次の構造体へのポインタ
5
前の構造体へのポインタ
一方向のリストだと、手前のデータが扱いにくい。
双方向リスト
17
33/55
配列によるリストの実現
0
0
a
10
0
1
5
0
1
2
3
4
5
0
0
5
0
2
6
4init
31
0
リストの最初の値
次のデータが入っている配列データまだリストに使用していない配列
5
10
1
34/55
配列によるリストの実現(2)
0
0
a
10
0
1
5
0
1
2
3
4
5
0
0
5
0
2
6
4init
31
0
5
10
1
6
6の
挿入
① 先頭からたどり、どこに挿入するかを確認する② スタックから1つとる6
0
a
10
0
1
5
0
1
2
3
4
5
5
0
0
0
2
6
4init
31
0
③ a[0][0]に6を書き込む④ a[0][0]にa[2][1]を書き込む⑤ a[2][1]に0を書き込む
18
35/55
配列によるリストの実現(3)
5
10
1
6
10の
削除
① 先頭からたどり、どれを削除するかを確認する② スタックに2を積む6
0
a
10
0
1
5
0
1
2
3
4
5
5
0
0
0
2
6
4init
31
③ a[4][1]にa[2][1]の内容を書き込む6
0
a
10
0
1
5
0
1
2
3
4
5
5
0
0
0
0
6
4init
31
2
2
36/55
配列によるリストの実現(4)
5
1
66の
削除
① 先頭からたどり、どれを削除するかを確認する② スタックに0を積む6
0
a
10
0
1
5
0
1
2
3
4
5
5
0
0
0
2
6
4init
31
③ a[4][1]にa[0][1]の内容を書き込む6
0
a
10
0
1
5
0
1
2
3
4
5
5
0
0
0
0
6
4init
31
0
22
0
ここの値が違うだけ
19
37/55
配列によるリストの実現(5)
5
1
1の
削除
① 先頭からたどり、どれを削除するかを確認する② スタックに4を積む6
0
a
10
0
1
5
0
1
2
3
4
5
5
0
0
0
2
6
4init
31
③ init にa[4][1]の内容を書き込む6
0
a
10
0
1
5
0
1
2
3
4
5
5
0
0
0
0
6
5init
31
0
22
0
今までのパターンと違う!4
4
最初のデータを削除したいときは、例外処理が必要なの?
38/55
配列による
ダミーを含んだリストの実現(1)
0
0
a
10
0
1
5
0
1
2
3
4
5
4
6
5
0
2
1
init
3
:ダミーを含むリストの先頭
次のデータが入っている配列データまだリストに使用していない配列
5
10
1
ダミーダミー
最後
最初
と最
後にダミー
を追
加
20
39/55
配列による
ダミーを含んだリストの実現(2)
0
0
a
10
0
1
5
0
1
2
3
4
5
4
6
5
0
2
1 3
① 先頭からたどり、どこに挿入するかを確認する② スタックに4を積む0
0
a
10
0
1
5
0
1
2
3
4
5
2
6
5
0
2
1 34
③ a[0][1]にa[4][1]の内容を書き込む5
10
1
ダミーダミー
1の削除今までのパターンと同じ!
40/55
1次元配列によるリストの実現
5
10
1
a
10
0
1
5
0
1
2
3
4
5
00
2last
• 任意の場所の値の参照が簡
単にできる。
• データを追加したとき、後ろの
データをすべてずらす必要が
あるので、計算量が必要。
• データの削除も、計算量が必
要。
デー
タが順
に並
ぶ
21
41/55
リストの実現(まとめ)
� ポインタと構造体で実現した場合、自由にデータ
数を設定できる。
� 配列で実現した場合、最初にデータ数の最大値
が決まってしまっている。
� ダミーを含んだリストを作成することで、例外処理
を取り除くことができる。
これは、プログラミングの簡略化に繋がる(場合
もある)。
42/55
配列によるスタックの実現(1)
a
10
0
1
5
0
1
2
3
4
5
00
2last
� サイズに制限があるス
タックなら、配列で容易
に実現できる。
データの保存
スタックの一番上が、
配列のどこにあるか
22
43/55
配列によるスタックの実現(2)
a
10
0
1
5
0
1
2
3
4
5
00
3last
� スタックへのデータの追加
1. last の値を+1する。
a
10
6
1
5
0
1
2
3
4
5
00
3last
2. last の示す場所に、
積むデータを書き込む。
44/55
構造体とポインタによる
スタックの実現(構造)
1データ領域
構造体へのポインタ
1 10 5
null
1. 次のような構造体を定義する。
2. ポインタが次々と次の構造体を指すことで、スタックを実現する。
init
23
45/55
構造体とポインタによる
スタックの実現(データの追加(1))
1. 追加するデータの構
造体を作成
データの追加の仕方
2. 作成した構造体のポ
インタが指す先を、
設定。
1 10 5
null
6init
1 10 5
null
6init
tmp
tmp
46/55
構造体とポインタによる
スタックの実現(データの追加(2))
3. init が指す先を設定
データの追加の仕方
4. 不要な物を消す 1 10 5
null
6init
� 必ず同じところに追加されるため、ダミーは要らない。
双方向のリストも必要ない。
tmp
24
47/55
1. 次のような構造体を定義する。
2. ポインタが次々と次の構造体を指すことで、実現
構造体とポインタによる
キューの実現(構造)
1 10 5
null
init last
null
null
データ領域
次の構造体へのポインタ
5
前の構造体へのポインタ
48/55
構造体とポインタによる
二分木の実現
1. 次のような構造体を定義する。
2. ポインタが次々と次の子を指すことで、実現根データ領域
右の子供へのポインタ
5
左の子供へのポインタ
A
B
CD
A
25
49/55
配列による完全二分木の実現
• ノードa の子はノードa+1とノードa+2
これを結線情報として利用する。
0
1 2
3 4 5 6
7 8 9
A
B E
D
C
D
D
A
B
C
表現したい木
a5
6
7
8
9A
D
C
C
B
a0
1
2
3
4
A
D
D
E
B
配列による表現
50/55
完全二分木内の探索(1)
木の中にEがあるか否かを判定したい!
0
1 2
3 4 5 6
7 8 9
A
B C
D
C
D
D
A
B
C
� 深さ優先探索(先行順)
• 左側の子を優先的に探索していく。
• 外側をなぞるように探索するように見える。
• 左横を通ったときに値の判定を行う。
1
2
3
45
6
7
8
910
左側の子を先に探索 左側がすべて終わってから、右の子の方を探索左横を通ったときに判定
26
51/55
完全二分木内の探索(2)
木の中にEがあるか否かを判定したい!
0
1 2
3 4 5 6
7 8 9
A
B C
D
C
D
D
A
B
C
� 深さ優先探索(中央順)
• 左側の子を優先的に探索していく。
• 外側をなぞるように探索するように見える。
• 真下を通ったときに値の判定を行う。
1
2
3
4
5
6
7
8
9
10
左側の子を先に探索 左側がすべて終わってから、右の子の方を探索真下を通ったときに判定
52/55
完全二分木内の探索(3)
� 深さ優先探索(中央順)の使用例
0
1 2
3 4 5 6
7 8 9
10
5 9
7
6
12
11
8
15
1
1
2
3
4
5
6
7
8
9
10
� 左の子は自分よりも小さい値を持ち
右の子は自分よりも大きい値を持つ木構造。
深さ優先探索(中央順)を行うと、
1 – 5 – 6 – 7 – 8 – 9 – 10 – 11 – 12 – 15
となり、小さい順の整列となる。
27
53/55
完全二分木内の探索(4)
木の中にEがあるか否かを判定したい!
0
1 2
3 4 5 6
7 8 9
A
B C
D
C
D
D
A
B
C
� 深さ優先探索(後行順)
• 左側の子を優先的に探索していく。
• 外側をなぞるように探索するように見える。
• 真下を通ったときに値の判定を行う。
1 2
3
4
5
6
7 8
9
10
左側の子を先に探索 左側がすべて終わってから、右の子の方を探索右を通ったときに判定
54/55
完全二分木内の探索(5)
木の中にEがあるか否かを判定したい!
0
1 2
3 4 5 6
7 8 9
A
B C
D
C
D
D
A
B
C
� 深さ優先探索(先行順・中央順・後行順)
• 再帰を行うとき、どのタイミングでデータを処理する
のかに対応している.
scantree(親){( 省略 )
scantree(左の子)scantree(右の子)
}
親に関する処理
どこに挟むかで、先行順・中央順・後行順のどれであるか決まる.
28
55/55
完全二分木内の探索(4)
木の中にEがあるか否かを判定したい!
0
1 2
3 4 5 6
7 8 9
A
B C
D
C
D
D
A
B
C
� 幅優先探索
• 同じレベルを優先的に探索していく。
• 配列を上から順番に探索しているように見える。
1
2 3
4 5 6 7
8 9 10
同じレベルの子を先に探索 a5
6
7
8
9A
D
C
C
B
a0
1
2
3
4
A
D
D
E
B
Recommended