データ構造とアルゴリズム 第4回 リスト ~ データ構造(1)~ 1 前回の問題 問題 以下の4個のメンバーから構成される構造体を 定義せよ。型名をIMAGEとする。 ・整数値の番号 n ・ローマ字タイトル name ・実数値の平均輝度 avL ・次のIMAGE型構造体へのポインタ next 2 前回の問題の解答 struct IMAGE{ int n; char name[20]; double avL; struct IMAGE *next; }; 多かった間違い 第1位 第2位 char name; ⇒ セミコロン無し 正答率=41% 簡単すぎるかと反省してたので、 ちょっとビックリでガッカリ 文字数を指定して 文字列にする! char name[20]; 3 本日の内容 リスト 抽象データ型としてのリスト 配列によるリストの実現 連結リストによるリストの実現 7 基本的な抽象データ型 3つとも情報関連の資格試 験に頻出する.重要なので よく理解しておくこと. リスト(List) リストの特殊なケース スタック(Stack) キュー(Queue, 待ち行列) D C B A D C B A 8 リストの数学的表現 (p.26~) リスト: 一定の型の要素を0個以上一列に並べたもの. 線形リスト(linear list)と呼ぶこともある. ai : i 番目の位置にある要素 n : 要素数.リストの長さ. n = 0のとき空リストという a0,a1, a2, …, ai-1, ai, ai+1, … , an-1 最後の要素 aiの直前の要素 最初の要素 aiの直後の要素 9 抽象データ型としてのリスト 抽象データ型: データ構造+操作 リスト 操作 新要素の挿入 要素を 並べたもの 要素の削除 リストを空にする 10 表記法についての説明 L p x : リスト :位置を表わす変数 :挿入したいデータ 要素の型はすべて同じであれば よい. 教科書ではelememttype型とし ている. x L a0 a1 p … ai-1 n ai … an-1 11 代表的なリスト操作 INSERT(x, p, L) 新要素の挿入 DELETE(p, L) 要素の削除 LOCATE(x, L) 要素xの位置を探す RETRIEVE(p, L) FIND(i, L) 位置pにある要素を返す i番目の要素を返す TOP(L)、LAST(L) 先頭、末尾の位置を返す NEXT(p, L)、PREVIOUS(p, L) CREATE(L) pの直前、直後の位置を返す 新規に空リストLを作成する 12 INSERT(x, p, L) リストLの位置pの次に要素xを挿入 p L A B C D x E F G H E F G p L A B C D H 13 DELETE(p, L) リストLの位置pの次の要素(もし存在すれば)を削除 p L A B C D E F G H p L A B C D E F G H 14 LOCATE(x, L) 要素xがL中に存在すれば、その位置を返す x L A B C D F D G H この位置が返る 配列のインデクスなら[3] ポインタならば、ここを指すポインタ 15 RETRIEVE(p, L) 位置pのセルの内容を返す p L A B C D F G H ‘ F ’が返る 16 FIND(i, L) L の i 番目のセルの内容を返す(ただし、i は1から 始まるものとする) i = 3のときは? L A B C D F G H ‘ C ’が返る 17 TOP(L) と LAST(L) TOP(L) L の最初の位置を返す LAST(L) L の最後の位置を返す TOP( L ) L A B LAST( L ) C D F G H 18 NEXT(p,L)とPREVIOUS(p,L) NEXT(p, L) 位置pの次のセルの位置を返す PREVIOUS(p, L) 位置pの前のセルの位置を返す p L A B C PREVIOUS(p, L ) D F G H NEXT(p, L ) 19 CREATE(L) CREATE(L) 空リスト L を準備し、その先頭の位置を返す 空リストの先頭の位置が返る L 20 リストの実現(実装) すべての操作が常に必要になるとは限らない すべての操作を効率よく実行できるデータ構造の実 現は困難 ⇒プログラムの実装の際には,必要な操作を,効率よく 実行できるデータ構造を採用する リストの実現に使用できるデータ構造 配列 連結リスト(linked list) ポインタを用いてデータ間の関係を表現したデータ構造 Insert,Deleteの実現方法の例を説明する 21 配列によるリストの実現 例) int a[MAXLENGTH]; a[0] a[1] last 最後の要素の 位置を記録 5 10 リスト 配列の大きさ( 定数) MAXLENGTH 個 22 空 a[MAXLENGTH-1] 23 Insert(x, p, L) 位置pの後ろの要素を一つずつずらし,新しい要素 のための場所を空けてから,要素を入れる x A p last 2 [0] B [1] L [2] L [3] p last 2 ② 3 [0] B [1] A ③ [2] L [3] L [4] [4] [5] [5] ① 24 Delete(p, L) last 4 削除する要素の後の要素を一つずつ前へずらし, すき間を埋める [0] E [1] X [2] E [3] I ① last 3 [4] T 4 [5] p [0] E [1] X [2] EI [3] TI [4] T p ② [5] 25 配列で実現する場合の注意点 last 2 [0] E [1] I [2] T p [3] [4] [5] [6] 削除する要素が 存在する範囲は [0]~[last] 要素を挿入で きる範囲は [0]~[last+1] lastがMAXLENGTH – 1の場合,リストは満杯 (これ以上,要素を挿入できない) 26 mallocの復習 malloc(n); メモリ上に n バイトの領域を確保し、 その先頭アドレスを返す 普通、n にはsizeof演算子を使って 求めた領域の大きさを記述する 28 mallocの使用例 struct ITEM{ int element; struct ITEM *next; }; ptr = (struct ITEM*)malloc(sizeof(struct ITEM)); メモリ空間上に、ITEM構造体が入る大きさの領域を確保して、 その領域の先頭アドレスをptrに代入。 mallocはポインタ(アドレス)を返す関数。型の整合性が取れるよ うにキャスト(型変換)してから代入する。 ptr ? ? 29 メモリ空間上のイメージ 番地 mallocするのか。 それじゃ、ここがstruct ITEMの分確保できるから、 ここをつかうぞ。 00000000 内容 FF1F0204 00000004 00000008 0000000C 0CFFFF1A 00000010 FF001121 ptrが格納されている場所 00000128 00000004 00000004番地を使うことを ptrにメモしておこう。 30 値を返すとは?(2週目のスライド再掲) ある関数を呼び出して計算した値を、呼び出し元の 変数に代入すること。 関数triangle を呼び出す メインプログラム S = triangle(5, 7); (Sに17.5が代入される) 関数 float triangle(int L, int H){ return L*H/2.0; } (5*7/2.0=17.5) 計算結果を 関数の呼び出し元に返す 31 ポインタを返すとは? ある関数を呼び出した結果得られたアドレスを、呼び 出し元のポインタ変数に代入すること。 関数LAST君、末尾のセルは どこか調べてね メインプログラム 関数 struct cell* LAST (struct cell* init){ リストの末尾の位置を探す; return 末尾へのポインタ; } pt = LAST(init); pt にアドレス 0104が 代入される 末尾のセルは 0104番地にありますよ 32 復習 ドット演算子 . struct SAMPLE{ int width; int height; }; data1 width int main(void) { struct SAMPLE data1; 50 height data1.width = 50; … return 0; } 構造体のメンバにアクセスする ときは、ドット演算子を使って、 メンバ名を指定する。 33 復習 int main(void) { int a=5, b; int *pt; 間接演算子 * a 5 pt b 5 pt = &a; b = *pt; … return 0; } ptの指している先の中身に アクセスするときは間接演算 子を使う 34 構造体へのポインタのときは? int main(void) { struct SAMPLE data1; struct SAMPLE *pt; pt data1.width pt = &data1; data1.width (*pt).width pt->width 50 data1.height (*pt).width = 50; … return 0; } これを簡単に書くために アロー演算子->を使用 pt -> width = 50; 35 ポインタによるリストの実現 ポインタによってリストのデータ構造を表現したものを 連結リスト(リンクトリスト,linked list)と呼ぶ 「要素」と「次のセルを指すポインタ」で構成される連 結リストは,特に,単方向リスト,一方向リストなどと 呼ばれる init ここではポインタのみになっているが、実 装を簡単にするため、ヘッダも完全なセ ルにすることもある. a0 a1 a2 an-1 36 例)整数のリスト(単方向リスト版) 型定義 struct CELL { int element; struct CELL *next; }; init a0 CELL型 要素(element)と 次のセルを指すポインタからなる a1 a2 an-1 37 Insert(x, p, L) pが指すセルの次に,新しいセルを挿入する init p 挿入する位置の 一つ前を指して いる点に注意 A B C x 38 Insert(x, p, L)の実現(1) init p A 重要!! 教科書p.30のソースと よく見比べて理解すること B C r ① r = (struct CELL *)malloc(sizeof(struct CELL)); 39 Insert(x, p, L)の実現(2) リストの途中への挿入の場合 init p A ② q = p -> next; B C r 40 Insert(x, p, L)の実現(3) リストの途中への挿入の場合 init p q A B C ③ p -> next = r; r 41 Insert(x, p, L)の実現(4) init r p q A B C x ④ r->element = x; 42 Insert(x, p, L)の実現(5) init r p q A B x C ⑤ r->next = q; 43 先頭へのInsert ②、③が異なる p (先頭への挿入のときpはNULL) init ③ init = r ; r ② q = init; A B C 44 Delete(p, L) pが指すセルの次のセルを削除する init p ① q = p->next; ③ free(q); A B C D ② p->next = q->next; 45 双方向リスト 「要素」と「次のセルを指すポインタ」, 「前のセルを 指すポインタ」で構成される連結リストは,双方向リ ストと呼ばれる 長所:リストを前方にも後方にもたどれる 短所:前のセルを指すポインタが必要になる 単方向リストと比べ,操作が複雑になる ap-1 ap ap+1 46 例)整数のリスト(双方向リスト版) 型定義 前の要素を指す ポインタが増えた struct CELL { int element; struct CELL *next; struct CELL *previous; }; ap-1 ap ap+1 47 計算量の比較 データ構造 INSERT, DELETE 配列 要素数に比例O (n) 単方向リスト 一定時間O (1) last 2 [0] [1] [2] [3] [4] [5] [6] E I T FIND, LAST, PREVIOUS 一定時間O (1) 要素数に比例O (n) p init p E I T 48 メモリの使用効率に関する比較 データ構造 リストの最大長 配列 単方向リスト last 2 [0] [1] [2] [3] [4] [5] [6] 固定 可変 E I T p 余分に必要になるメモリ MAXLENGTH - 実際の長さ ポインタ用の空間 init p E データが 入っていない I T ポインタ用の空間 49 データ構造とアルゴリズム 2008年度前期 出席カード 5月14日 学籍番号 氏名 の様に連結されている時、下の番地表での連結を矢印で示せ。 一つのセルは連続した2つの番地に入っているとする。 ROOT 0093 0091 番地 内容 0094 009D 0000 番地 0106 内容 0093 番地 010E 内容 0095 0108 010F 010A 0110 0096 ROOT 00FF 0100 0107 0100 0091 0108 0101 0106 0109 010E 0111 0112 0102 009C 010A 009A 0112 0098 0103 0104 010B 010C 0113 0114 0104 009D 010C 009B 0114 0099 0105 0000 010D 0102 0115 0000 50
© Copyright 2024 ExpyDoc