先週からデータ構造の話 データ構造 既存のデータ型から、新しいデータ型を作る仕組み # 新しいデータ型から、元となる既存のデータ型を取りだす事ができる # # 新しいデータ型 # +-----------------------+ # | 元となるデータ型 | # +-----------------------+ # => 新しいデータ型 : 内部構造 ( 元となるデータ型と、新しいデータ型の関係 ) # => データ構造 ( 型の組合わせ ) コーディング ( 前回の内容 ) の方法を指す * 表現したい情報を、(コンピュータの内部の)数値で、どのように表現するかという手段を表す 例: 文字を数値で表現するための手段 ( ASCII Code 表 ) 二次元の直交座標を表現するために、x, y 座標値の組み合わせ 1. 表現したい情報自身が構造を持つ場合がある 二次元の直交座標は、x 座標と y 座標という内部構造を持つ => これを表現する時に、数値の方も、同じ内部構造を持つ方が扱いやすい y 4 | 3 | * (4,3) 4, 3 という二つの数値の組 2 | 下に一つ平行移動 1 | y 座標を減らすだけ 0 +--------- x 0123456789 6 y17 4 |628 3 |4839 19 という一つの数値で座標を表現する事ができる 2 |2594 19 -> 14 1 |13605 平行移動を示す一般的な方法がなかなか思いつかない 0 +--------- x => 直観と反している 0123456789 情報に構造があった場合は、 それを表現するデータ型にも ( 同じような ) 構造があった方が便利 * データ型は、それ自身がなんらかの情報を表現ではなく、 そのデータ型の数値を、どのように扱うかで、表現する情報が異なる 例: ASCII Code : 'a' <-> 76 76 という数値が文字の 'a' を表すのは、 この数値を、ASCII Code 表での文字を表す数値としてとらえるから 'a' + 1 => 76 + 1 => 77 ( <= 整数値として扱っている ) この計算結果 ( 77 ) を改めて、文字を表現していると思うと、 'b' という文字とみなす事ができる !! 情報処理 ( 計算機の中では計算によって実現されている ) は、 !! (コーディングを経由して..) 情報とデータ(数値)を行き来する事によって、実現されている 情報 データ ASCII Code 文字 'a' --------------------> 76 | | | (次の文字を得る) | +1 という計算ができる v v 'b' <------------------ 77 演習 二次元平面の点の二つの表現 直交座標を使う 極座標を使う [2021/11/12] 先週の資料に基づいて データ構造 既存のデータ型から、新しいデータ型を作る仕組み C 言語上での既存データ型 整数型 : int 浮動小数点数型 : double 文字 : char ( 小さな整数値 ) ( 文字列 : char * => データ構造を持つ.. ) 組み合わせ方 構造体 [構造体] 「点」のデータの構造の例 平面上の点を扱う事を考える x 座標と y 座標の組で「点」を表現 点 p1 の x, y 座標をそれぞれ p1x, p1y で表現してみる 点の表示や、距離などは、普通に扱える [005] 「点」を 「x 座標と y 座標の組」で表現する p1 <-> p1x, p1y p2 <-> p2x, p2y # これで、問題なく「点」を表現(扱う事)ができる # 「p1 を表すのに p1x p1y という二つの変数を利用する」事は、 # (今)プログラムを書いている自分にしかわからない # 他の人(後の自分を含む)には、なかなかわからない # => C Compiler にもわからない 「点」を表すもの(データ構造)を考える 構造体 : 複数のデータをまとめて扱えるようにする仕組[009] 次のような形で、宣言されたもの 構文: struct { 組み合わせる型と、その型のデータを参照するタグ名の宣言の並び } 意味: 組み合わせる型の直積を作り、 その要素を参照する名前(タグ)を宣言する struct { 中身 }; 中身 : 直積を作る空間(となる型名)と、 その要素を取り出す(射影:projection)を行う場合に、 その要素を指定するタグ名を宣言している 構造体を作り、それを使いまわす場合、 構造体の宣言を毎回書くのは面倒なので、 構造体の宣言に名前を付けてしまう typedef 構文 typedef 型宣言 新しい型名 意味 新しい型名を利用できるようにし、その意味は、 ここで指定した型宣言と同じ役割を与える 例: typedef struct { double x; double y; } Orthogonal; => 以下、 Orthogonal とかくと、 struct { double x; double y; } と書いてあるがごとくふるまう !! Orthogonal が ( int, double のような.. ) 型名として利用可能 !! => 型チェックもやってくれる !! 変数同士の代入が可能 !! 方針 !! 構造体を利用する場合は、(構造体の宣言を毎回書くのは不便なので..) !! いつでも、typedef を利用して、名前を付けて利用する !! cf. !! if / while の後ろには { } をつける.. 構造体の中身は、色々な型を並べる事ができる[010] 課題: 20211105-03 C 言語には、三次元ベクトルを表す(組み込みの)データ型は存在しないが、 自分で、構造体を利用して、型宣言を行い、 さらに、その型の値に対して、操作を行う関数を実装すれば、 新しい型として、「三次元ベクトル」型を扱えるようになる # 新しい型を増やす事ができる !! 特に、 !! 構造体は、「直積空間」を作る役割を担う !! 数学の世界での直積空間の事例は、全て、構造体で実装可能.. [配列] 配列 同じ型のデータが並んだ物を表現する仕組 例: double a0,a1,a2 -> double a[3] 配列名 : データの並びが入る変数の代表名 cf. 構造体との比較 struct { double a0; double a1; double a2; } a; でも表現可能 構造体 配列 メンバーの型 色々な型を組み合わせる事ができる 同じ型 参照方法 タグ名(定数)で参照 添え字(数値:式が使える) 添字 「'[' + 整数値 ']'」を付けて、要素が参照できる double a[3] で宣言された配列 a の要素は、 ! <注意> 配列の宣言では、配列サイズは定数にする必要がある a[0], a[1], a[2] の三つ # i=1; a[i] とすれば、a[1] を表す事ができる cf. struct { double a0; double a1; double a2; } a; の要素は、 a.a0. a.a1, a.a2 の三つ 配列の宣言 配列を利用する(宣言する)場合は、「配列名[サイズ]」の形にする サイズの個数の変数がまとめて用意される 参照する場合は 0 〜 サイズ-1 まで cf. for ( i = 0; i < サイズ; i++ ) { 配列の要素処理 配列名[i] i = 0 〜 サイズ - 1 } 例: int ary[10]; とすると ary[0] 〜 ary[9] が使える 配列の利点 配列の要素を参照するときに添え字(場所を表す整数値)を指定するが、 その値は、式の結果でよい => 式の中に変数が含まれていれば、 同じ命令で、異なる機能が実現できる 例: 構造体 struct { x, y, z } s s.x <= x の要素しか参照できない # プログラミング時には決定しておく必要がある 配列 a[3] a[i] <= i の値によって、a[0], a[1], a[2] が変化する # 実行時に選択できる 配列プログラミング (集合操作) 配列 vs 集合 配列は、複数の同じ型の変数(配列の要素)をまとめたもの 個々の要素は、同じ型の値を保持する 一つの配列(が保持する値の集まり) は、その型の「集合」を表す 例: 集合 : { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } 一桁の非負の整数の集合 集合操作 配列の要素(複数)への操作を「繰返し」で表現する 「集合全体への操作」が、「個々の要素の操作の繰返し」になる まとめ データ構造上の処理は、 全体への処理を、個々の要素の処理の組み合わせで実現 構造体の場合は順接になる struct { x, y, z } d, s d.x = s.x d.y = s.y d.z = s.z 配列の場合は、くり返しなる d[3], s[3] for ( i = 0; i < 3; i++ ) { d[i] = s[i] }