Algorithms and Data Structures on C リストと配列 Algorithms and Data Structures on C この回の要点 • C言語における変数 – プリミティブ型とポインタの違い – 参照型における実体オブジェクトへの参照 • リストとは? • 配列によるリスト – 配列の利点と欠点 – C言語による配列の実現 – 配列の代入と複製の違い Algorithms and Data Structures on C データ構造 • アルゴリズム+データ構造=プログラム – アルゴリズム・・・データをどのように加工するか – データ構造・・・データをどのように表現するか • アルゴリズムと、データ構造とは、互いに密接に関 係している – プログラムを書くとき、アルゴリズムとデータ構造とを同時 に考えていく必要がある – 並べ替えアルゴリズムの場合 • データの移動がほとんどないアルゴリズム・・・配列による表現 • データの削除・挿入が頻繁にあるアルゴリズム・・・リンクリストに よる表現 – どちらでも可能であるが、効率が問題 Algorithms and Data Structures on C 変数 • 変数(variables)とは – プログラム中で、値が変化するデータを格納する箱 – 1つの箱に、1つのデータを格納できる – 箱にはいろいろな大きさがある(型、Type) • 変数には名前をつける=変数名(識別子) 箱 x = 変数名 123 pi = str = 3.141592 “Hello World” pt = (100,120) p = PersonalData 箱にはいろいろな データが入っている Algorithms and Data Structures on C C言語の基本型(プリミティブ) 種類 型 長 signed unsigned 型なし void ー ー ー 文字型 char 8 -128 ~ 127 0 ~ 255 short 16 -32768 ~ 32767 int 32 -2147483648 ~ 2147483647 0 ~ 4294967295 long 32 -2147483648 ~ 2147483647 0 ~ 4294967295 long long 64 -9223372036854775808 ~ 9223372036854775807 0~ 18446744073709551615 float 32 最小の正の数1.175494351e-38 最大値3.402823466e+38 double 64 最小の正の数2.2250738585072014e-308 最大値1.7976931348623158e+308 整数型 浮動小 数点型 0 ~ 65535 ILP32(一般的な32ビット環境)での例 Algorithms and Data Structures on C ポインタ型 • メモリへの参照を示す • 参照するメモリのアドレスが格納されている • 型の後に*(アスタリスク)を付けた型 – int* ip; – double* dp; (変数名の方に*を付けて宣言することも多い。が、*は変数名ではない) アドレス幅 ip 参照 dp 参照 123 4バイト 3.14 8バイト メモリ メモリ Algorithms and Data Structures on C プリミティブとポインタ 実体(値) プリミティブ int x = double pi = int* ip = 実体 (オブジェクト) 123 3.141592 123 参照 “Hello World” char* str = 参照 MyData* dp = 参照 ポインタ 構造体 実体への参照 Algorithms and Data Structures on C 変数への代入 • プリミティブ int x=123; double pi=3.141592; MyPoint pt={3,4}; • ポインタ プリミティブには直接数値を代入 構造体の初期化 プリミティブのアドレスを代入 int* ip=&x; double* dp=π const char* str=“Hello World”; int* data=(int*)malloc(100*sizeof(int)); MyPoint* pt1=(MyPoint*)malloc(sizeof(MyPoint)); malloc() を使用 free()でメモリを解放すること! Algorithms and Data Structures on C 構造体 • いくつかのデータをまとめた型 – – – – キーワードstructで定義する タグ名を付ける 内部に複数の異なる型の変数を持つ 構造体の宣言の形 struct タグ名 { データ型 メンバー名 データ型 メンバー名 ・・・ }; – 変数の宣言 struct タグ名 変数名; – メンバーへのアクセス(.か->を使用) 変数.メンバー名 ポインタ変数->メンバー名 Algorithms and Data Structures on C 構造体の例1 #include <stdio.h> struct MyPoint { int x; int y; }; 構造体タグの宣言 初期化 int main(void){ struct MyPoint pt1; struct MyPoint pt2={ 3,4 }; struct MyPoint *pt3=&pt2; 構造体タグを使って 変数を宣言 printf(“(%d,%d)¥n”,pt1.x,pt1.y); printf(“(%d,%d)¥n”,pt2.x,pt2.y); printf(“(%d,%d)¥n”,pt3->x,pt3->y); } Algorithms and Data Structures on C 構造体の例2 #include <stdio.h> typedef struct { int x; int y; } MyPoint; int main(void){ MyPoint pt1; MyPoint pt2={ 3,4 }; MyPoint *pt3=&pt2; typedefを使った場合 タグ名は省略 構造体型の定義 構造体型を使って 変数を宣言 printf("(%d,%d)¥n",pt1.x,pt1.y); printf("(%d,%d)¥n",pt2.x,pt2.y); printf("(%d,%d)¥n",pt3->x,pt3->y); } Algorithms and Data Structures on C 抽象データ型とリスト(list) • 抽象データ型とは – データが持つ性質+データに行える操作 – 「クラス」として表現される – 中にどんなデータが入るかは関知しない • リストとは – 一般には、一覧表、目録、名簿 – 要素を順番に並べた構造を表す総称 • • • • • • データを一列に並べたもの→線形リスト リスト x の k 番目の要素→ x[k] とすると、 それの1つ前→ x[k-1] 番号によって それの1つ後→ x[k+1] 要素にアクセス可能 先頭の要素→ x[1] (ただし、C言語の配 末尾の要素→ x[n] (n個の場合) 列の添字は0から始 まるので注意) Algorithms and Data Structures on C 抽象データ型としてのリスト • リストのメンバ変数 – そのリストに格納されているデータ • リストが持つべきメソッド – – – – – – – – – – k番目の要素の内容を読む・書く k番目の要素の前に要素を挿入する k番目の要素の後に要素を挿入する k番目の要素を削除する 特定のキーを持つ要素を取り出す 複数のリストを1つにまとめる 1つのリストを複数のリストに分割する リストを複製する リストの要素数を得る ・・・ • すべのメソッドを効率よく実現するリストは困難 – 必要に応じて、どのメソッドを重視するかで、データ構造が決まる Algorithms and Data Structures on C 配列(array) 0 • リストの実現の一種 • たくさんの箱を一列に並べた構造 1 2 – 箱の数(配列の大きさ)は固定 3 • 配列を作るときに決める • あとから変更はできない – 箱には番号(添え字)がつけられる N-1 • 0,1,2,・・・,N-1(JavaやCの場合) – 番号を使って、中のデータにアクセス可能 • たくさんのデータを1つの名前(配列名)で管理できる • 多くのデータを扱うプログラムで有効 • 多次元配列 – 配列の添え字が2つ以上 Algorithms and Data Structures on C 配列の利点と欠点 • 利点 – 箱の番号を利用してデータに直接アクセスできる=O(1) – データだけから構成され、無駄なメモリが不要 • 欠点 – サイズが固定 – 途中に要素を挿入、削除する際、前後のデータを移動さ せる必要がある=O(N) 0 1 2 3 ・・・ 削除 後ろにずらす 前にずらす 挿入 N-1 Algorithms and Data Structures on C C言語の配列1 • C言語の配列は連続するメモリ領域(=ポインタ) • 変数名に[]をつけて宣言する int a[10]; // 10個の箱を持つ配列変数a int b[5]={1,2,3,4,5}; // 初期化 int c[]={1,2,3}; // 初期化すればサイズは不要 • 配列要素へのアクセス a[0]=3; a[9]=123; • 2次元配列 int x[3][4]; // 3行4列の2次元行列 int y[][2]={{1,2},{3,4},{5,6}}; // 3行2列 (実際には2次元配列も1次元として確保されている) • 注意 – C言語の配列のインデックスはチェックされない – 初期化しなければ、何が入ってるかは不定 Algorithms and Data Structures on C C言語の配列2 • ポインタとしての配列 int* a=(int*)malloc(10*sizeof(int)); // 10個の配列 MyPoint* pt=(MyPoint*)malloc(5*sizeof(MyPoint)); // 5個のMyPointの配列 • 配列へのアクセス – 前ページの配列同様、[]でアクセスできる a 参照 配列 変数 a[0] ? a[1] ? a[2] ? a[3] ? a[9] ? pt 参照 配列 変数 pt[0] MyPoint pt[1] MyPoint pt[2] MyPoint pt[3] MyPoint pt[4] MyPoint Algorithms and Data Structures on C ポインタの配列 • MyPointクラスのポインタの配列 MyPoint** pt=(MyPoint**)malloc(5*sizeof(MyPoint*)); pt[1]=(MyPoint*)malloc(sizeof(MyPoint)) // 実体 pt[3]=(MyPoint*)malloc(sizeof(MyPoint)); pt[4]=(MyPoint*)malloc(sizeof(MyPoint)); pt 参照 配列自体 の参照 pt[0] ? pt[1] 参照 pt[2] ? pt[3] 参照 pt[4] 参照 2段階の参照 (x,y) 実体 (ヒープメモリ) (x,y) MyPoint 型の参照 (x,y) Algorithms and Data Structures on C 配列の代入と複製 • 配列の代入 – 参照だけが代入され、その先は同じもの • 配列の複製(コピー) – 配列の先は別々なオブジェクトとなる memcpy(c,a,sizeof(a)); int a[5] 参照 a[0] 5 a[1] 14 a[2] 3 a[3] 8 a[4] 4 b=a int *b 参照 int c[5] 参照 c[0] 5 c[1] 14 c[2] 3 c[3] 8 c[4] 4 別なメモリ Algorithms and Data Structures on C 代入と複製の違い • 代入と複製の違いを確認する – – – – – – 配列 a を { 5,14,3,8,4 } で初期化 a を配列 b に代入 a を配列 c に複製 a と b , c を表示 a の2番目 a[1] の 14 を 99 に変更 a と b , c を表示 • 結果 – 代入・・・b[1] は 99 に変わる – 複製・・・c[1] は 14 のまま Algorithms and Data Structures on C ArrayTest.c 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. #include <stdio.h> #include <stdlib.h> #include <memory.h> void printArray(char c,int *a,int s){ printf("%c: ",c); int i; for(i=0;i<s;i++) printf("%d ",a[i]); printf("¥n"); } 実行結果: int main(void){ int a[5]={5,14,3,8,4}; int *b=a; int c[5]; memcpy(c,a,sizeof(a)); a[1]=99; printArray('a',a,5); printArray('b',b,5); printArray('c',c,5); } $ gcc –o ArrayTest ArrayTest.c $ ./ArrayTest.exe a: 5 99 3 8 4 b: 5 99 3 8 4 c: 5 14 3 8 4 $ Algorithms and Data Structures on C プログラムの作成方法 • 実際にプログラム – ヘッダファイルと実装ファイルに分けて作る • ヘッダファイル(.h) – データ型(クラス)の宣言 – データ操作(関数)のプロトタイプ宣言 • 実装ファイル(.cc) – 関数の具体的なコード – 拡張子.ccで書くことで、コンパイラがソースコードをC++として 扱うようになる – C++言語はC言語の拡張 – この講義ではC言語の機能だけを用いるが、C++として扱って おくと後々便利(かもしれない) – ということで、以下ではコンパイラとしてg++を用いる Algorithms and Data Structures on C ヘッダファイル • ソースファイルを分割する手段 • 拡張子 .h • #include文で読み込む – プリプロセッサによる作業 – 標準ヘッダ <stdio.h> – 自作ヘッダ “hogehoge.h” .h .h .h #include • 目的 – – – – 複数のソースで共通して使う場合 定義を書く場合 プロトタイプ宣言 関数の実体を書いてはいけない • リンクエラーになる場合がある .cc コンパイル .o Algorithms and Data Structures on C コンパイルとリンク • コンパイル – .hと.ccから.oを作る – 共通で使える.oを使う場合 – 規模が大きい場合 .o .o • リンク リンク – .oから.exeを作る • コンパイル&リンク – .hと.ccから直接.exeを作る – 規模が小さい場合はこれでもよい 具体例: $ g++ –o test1 test1.cc $ ./test1 .o .exe Algorithms and Data Structures on C 成績型Seiseki • 小学生の1回の試験の成績 – 名前と国語、算数、理科、社会の点数 – 成績の生成と表示ができる メンバー const char* name 名前 int kokugo 国語の点数 int sansuu 算数の点数 int rika 理科の点数 int shakai 社会の点数 Seiseki* makeSeiseki(const char*,int,int,int,int) 成績の生成 void print(Seiseki*) 成績の表示 関数 Algorithms and Data Structures on C Seiseki.h 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. #ifndef __Seiseki__h #define __Seiseki__h #include <stdio.h> #include <stdlib.h> ヘッダファイルの重複読み込みを回避 // データ型宣言 typedef struct { const char* name; int kokugo; int sansuu; int rika; int shakai; } Seiseki; // プロトタイプ宣言 Seiseki* makeSeiseki(const char*,int,int,int,int); void print(Seiseki*); void free(Seiseki*); #endif // __Seiseki__h Algorithms and Data Structures on C Seiseki.cc 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. #include "Seiseki.h" ヘッダファイルの読み込み // 成績の生成(コンストラクタ) Seiseki* makeSeiseki(const char *n,int k,int m,int r,int h){ Seiseki *s=(Seiseki*)malloc(sizeof(Seiseki)); s->name=n; s->kokugo=k; s->sansuu=m; Seiseki型のメモリを確保し、 s->rika=r; 中にデータを入れて、返す s->shakai=h; return s; } // 成績の表示 void print(Seiseki *s){ printf(“%s 国%d 算%d 理%d 社%d¥n", s->name,s->kokugo,s->sansuu,s->rika,s->shakai); } // 成績の解放 void free(Seiseki *s){ free((void*)s); } Algorithms and Data Structures on C TestSeiseki.cc 1. #include "Seiseki.h" 2. 3. int main(){ 4. Seiseki *s[3]; 5. s[0]=makeSeiseki("山田太郎",78,55,80,88); 6. s[1]=makeSeiseki("佐藤花子",90,80,85,87); 7. s[2]=makeSeiseki("中村裕次郎",40,62,72,21); 8. 9. for(int i=0;i<3;i++) s s[0] 10. print(s[i]); s[1] “山田太郎” 11. 78 55 80 88 12. for(int i=0;i<3;i++) s[2] 13. free(s[i]); 14. } “佐藤花子” “中村裕次郎” 90 80 85 87 40 62 72 21 Algorithms and Data Structures on C 課題151019 • TestSeiseki.ccをコンパイルして実行し、実行結果を示せ。 • 次のページのTestSeiseki2.ccは、ポインタ配列の代わりに二重ポインタ をつかって、同じプログラムを書きなおしたものである。このコードの不足 分を埋めて完成させ、完成したコードと実行結果を示せ。 • 作成方法:ワードで作成し、実行結果は図として貼り付けること。 • ファイル名は”scXXXXXX-al151019.docx” • 提出方法:メールで渕田まで送付すること。 • メールの本文中にも学籍番号を氏名を明記すること。 • 提出先:[email protected] • メールタイトル:”アルゴリズム課題151019” ← 厳守! • 期限:2015年10月25日(日) 24:00 Algorithms and Data Structures on C TestSeiseki2.cc 1. #include "Seiseki.h" 2. ここを変えた 3. int main(){ 4. Seiseki **s; 5. /* ここにs用のメモリを確保するコードを追加する */ 6. s[0]=makeSeiseki("山田太郎",78,55,80,88); 7. s[1]=makeSeiseki("佐藤花子",90,80,85,87); 8. s[2]=makeSeiseki("中村裕次郎",40,62,72,21); 9. 10. for(int i=0;i<3;i++) 11. printSeiseki(s[i]); 12. 13. for(int i=0;i<3;i++) 14. freeSeiseki(s[i]); 15. /* ここにs用のメモリを開放するコードを追加する */ 16. } Algorithms and Data Structures on C リストと配列 終了
© Copyright 2025 ExpyDoc