汎用的構造と 反復子 この回の要点 • 汎用的構造とは • これまでのリストでは何か問題か? • 解決する方法は? • 反復子とは • 何をするものか? • どのように使うか? • 実装コード • ListNode型 • List型 • ListIterator型 個人情報 PD型 • 個人情報 typedef PDtag { struct PDtag *prev; struct PDtag *next; char *name; int age; } PD; • 名前(char *name) • 年齢(int age) • リストとしての構造 • 前の要素(PD *prev) • 次の要素(PD *next) ListPD型 個人情報のリスト構造 PD型 NULL 前 次 太郎(21) first 前 次 次郎(18) 前 次 三郎(15) last NULL 残念なこと • データと構造とが混在している • 別なデータのリスト構造を使いたいときは、もう一度同 様な型を書く必要がある。 • リスト構造に対する操作も再度作り直し。 • p1の前にp2を接続 insertBefore(PD *p1,PD *p2); • p1の後にp2を接続 insertAfter(PD *p1,PD *p2); • pdを削除 remove(PD *pd); など • 本来、リスト構造と中のデータは関係ない • データと構造を分離できると便利。 • 構造に対する操作は流用できる。 リスト構造の見直し • 中に入っているデータには興味はない • 順に並んでいることが本質 • データとして void* を持てば、何でも入れられる • 最小限持つべき機能 • • • • リストの先頭や末尾に要素を追加できる 要素を取り出すことができる 要素を削除できる 要素数がわかる List型 汎用的リスト構造 ListNode型 NULL 前 次 void* first 前 次 void* 前 次 void* last NULL これまでのリスト構造 • PD型→ListNodePD型に変更 • リストにつながれることを前提とした個人情報の型 • 個人情報(名前と年齢)の他に前後のリンクを持つ • ListPD型 • PD型のデータが一列につながった構造 • 処理 • データが個人情報であることが前提 • print(List*)関数で、すべての個人情報が表示される。 リスト内容の表示(1) /*** ListTestPD.cc *** 個人情報リストのテスト addTop(lp,makeListNodePD("近藤",41)); ***/ printf("**before**¥n"); print(lp); #include "ListPD.h" remove(lp,pd); printf("**after**¥n"); print(lp); int main(void){ printf("2番目は"); ListPD *lp=makeListPD(); print(get(lp,1)); この部分 printf("です。¥n"); ListNodePD *pd; freeListPD(lp); add(lp,makeListNodePD("山田",19)); add(lp,pd=makeListNodePD("森",50)); add(lp,makeListNodePD("田中",23)); print(lp); } すべての要素 を表示する リスト内容の表示(2) // 表示 ListPD.cc void print(ListPD *lp){ ListNodePD *p=lp->first; 先頭のノードから始めて printf("ListPD:(%d):¥n",lp->size); for(int i=1;p;p=p->next,i++){ 次々にノードをたどりながら printf("%d:",i); print(p); printf(" "); } printf("¥n"); } そのノードを表示する リスト内容の表示(3) // 個人情報を表示する ListNodePD.cc void print(ListNodePD *pd){ printf("%s(%d)",pd->name,pd->age); } $ ListTestPD ListPD:(3): 1:山田(19) 2:森(50) 3:田中(23) **before** ListPD:(4): 1:近藤(41) 2:山田(19) 3:森(50) 4:田中(23) **after** ListPD:(4): 1:近藤(41) 2:山田(19) 3:田中(23) 2番目は山田(19)です。 個人情報として表示する 問題点は? • リストをたどる目的は表示だけではない • • • • • 全員の点数を+5点したい 鹿児島市内に居住する人の名前を表示したい 20歳の人にメールを出したい すべてのインベーダとの衝突判定をしたい ・・・ • その都度、print()と同様な関数を書く? • 非効率的 • データ構造の内部に立ち入ることになる • 汎用性の低下 新しいリスト構造 List ListNode first → void* • データ型は構造とデータを分離 • リンクノードを表すListNode型 ListNode void* • 構造(前後の腕)はそのまま • データは void* のポインタ • リンクリストを表すList型 • 先頭要素first • 末尾要素last • 要素数size ListNode void* ListIterator ListNode void* • 反復子ListIterator型 • リストの中の要素を次々に 取り出すための型 void* last → ListNode void* 反復子(Iterator)とは • ある構造の中のデータを順に取り出す仕組み • for文でループを組むのと似ている • データそのものを取り出すので、どんな処理でも可能 • 使用方法 1. 2. 3. 反復子を生成する。 ループ条件で反復子が次のようを持つかどうかをチェック 次の要素を持つなら、それを取り出して処理する • 疑似コード Iterator it=makeIterator(set); while(hasNext(it)){ data *d=next(it); // dを処理 } 反復子を生成する 次の要素がある間、 要素を取り出して処理する ListNode.h #ifndef __ListNode__h #define __ListNode__h // プロトタイプ宣言 /*** ListNode *makeListNode(void*); *** 双方向リンクリストのノード void freeListNode(ListNode*); ***/ void insertBefore(ListNode*,ListNode*); #include <stdio.h> void insertAfter(ListNode*,ListNode*); #include <stdlib.h> void remove(ListNode*); void *get(ListNode*); // ノード型 typedef struct ListNodeTag { struct ListNodeTag *prev,*next; void *data; } ListNode; #endif // __ListNode__h ListNode.cc /*** *** ListNodeの実装 ***/ #include "ListNode.h" // 生成 ListNode *makeListNode(void *d){ ListNode *n=(ListNode*)malloc(sizeof(ListNode)); n->data=d; return n; } // 破棄 void freeListNode(ListNode *n){ if(n->data) free(n->data); free(n); } 続く ListNode.cc // 前に挿入 void insertBefore(ListNode *n1,ListNode *n2){ if(n1==NULL || n2==NULL) return; if(n1->prev) n1->prev->next=n2; n2->prev=n1->prev; n2->next=n1; n1->prev=n2; } // 次に挿入 void insertAfter(ListNode *n1,ListNode *n2){ if(n1==NULL || n2==NULL) return; if(n1->next) n1->next->prev=n2; n2->prev=n1; n2->next=n1->next; n1->next=n2; } 続く ListNode.cc // 取り外す void remove(ListNode *n){ if(n==NULL) return; if(n->prev) n->prev->next=n->next; if(n->next) n->next->prev=n->prev; n->prev=n->next=NULL; } // データを取り出す void *get(ListNode *n){ return n->data; } List.h #ifndef __List__h #define __List__h // プロトタイプ宣言 /*** List *makeList(); *** リスト void freeList(List*); ***/ void addTop(List*,void*); #include "ListNode.h" void add(List*,void*); void remove(List*,void*); // リスト型 void *getFirst(List*); typedef struct { void *getLast(List*); ListNode *first,*last void *get(List*,int); int size int getSize(List*); } List; #endif // __List__h List.cc /*** *** Listの実装 ***/ #include "List.h" // 生成 List *makeList(){ List *l=(List*)malloc(sizeof(List)); l->first=l->last=NULL; l->size=0; return l; } // 破棄 // 中の要素も破棄する void freeList(List *l){ ListNode *n=l->first,*nn; while(n){ nn=n->next; freeListNode(n); n=nn; } free(l); } 続く List.cc // 先頭に追加 void addTop(List *l,void *d){ ListNode *n=makeListNode(d); if(l->first==NULL) l->first=l->last=n; else{ insertBefore(l->first,n); l->first=n; } l->size++; } // 末尾に追加 void add(List *l,void *d){ ListNode *n=makeListNode(d); if(l->last==NULL) l->first=l->last=n; else{ insertAfter(l->last,n); l->last=n; } l->size++; } 続く List.cc // データdのノードを取り出す(線形探索) ListNode *find(List *l,void *d){ for(ListNode *n=l->first;n;n=n->next) if(get(n)==d) return n; return NULL; } // リストから取り外す void remove(List *l,void *d){ ListNode *n=find(l,d); if(n==l->first) l->first=l->first->next; if(n==l->last) l->last=l->last->prev; if(n) remove(n); l->size--; } // i番目の要素 void *get(List *l,int i){ ListNode *n=l->first; for(int j=0;j<i && n;j++) n=n->next; return (n)?get(n):NULL; } // 要素数 int getSize(List *l){ return l->size; } ListIterator.h #ifndef __ListIterator__h #define __ListIterator__h /*** *** リストの反復子 ***/ #include "List.h" // 反復子型 typedef struct { List *list; ListNode *next; } ListIterator; // 反復対象のリスト // 次に返すノード // プロトタイプ宣言 ListIterator *makeListIterator(List*); void freeListIterator(ListIterator*); ListNode *hasNext(ListIterator*); void *next(ListIterator*); #endif // __ListIterator__h ListIterator.cc /*** *** ListIteratorの実装 ***/ #include "ListIterator.h" // 生成 ListIterator *makeListIterator(List *l){ ListIterator *it=(ListIterator*)malloc(sizeof(ListIterator)); it->list=l; it->next=NULL; // 反復未開始状態 return it; } // 破棄 void freeListIterator(ListIterator *it){ free(it); } 続く ListIterator.cc // 次の要素があるか ListNode *hasNext(ListIterator *it){ if(it->next==NULL) return it->next=it->list->first; return it->next=it->next->next; } // 次の要素 void *next(ListIterator *it){ return get(it->next); } PD.h #ifndef __PD__h #define __PD__h /*** *** 個人情報 ***/ #include <stdio.h> #include <stdlib.h> #include <string.h> // 個人情報型 typedef struct { char *name; int age; } PD; // プロトタイプ宣言 PD *makePD(const char*,int); PD *makePD(char*,int); void freePD(PD*); void print(PD*); #endif // __PD__h PD.cc /*** *** PDの実装 ***/ #include "PD.h" // 生成 PD *makePD(const char *n,int a){ return makePD((char*)n,a); } PD *makePD(char *n,int a){ PD *pd=(PD*)malloc(sizeof(PD)); int l=strlen(n); pd->name=(char*)malloc(l+1); strcpy(pd->name,n); pd->age=a; return pd; } 続く PD.cc // 破棄 void freePD(PD *pd){ free(pd->name); free(pd); } // 表示 void print(PD *pd){ printf("%s(%d)",pd->name,pd->age); } ListTest.cc /*** Listのテスト ***/ #include "PD.h" #include "List.h" #include "ListIterator.h" void print(List *list){ printf("List(%d):¥n",getSize(list)); int i=1; for(ListIterator *it=makeListIterator(list);hasNext(it);i++){ PD *pd=(PD*)next(it); printf("%d:",i); print(pd); printf("-"); } printf("¥n"); } 続く ListTest.cc int main(void){ List *list=makeList(); PD *pd; add(list,makePD("山田",21)); add(list,pd=makePD("斎藤",34)); add(list,makePD("森",50)); addTop(list,makePD("近藤",18)); add(list,makePD("山下",33)); printf("*** Before ***¥n"); print(list); remove(list,pd); printf("*** After ***¥n"); print(list); pd=(PD*)get(list,2); printf("2番は");print(pd);printf("です"); freeList(list); } TestListの実行結果 $ ListTest *** Before *** List(5): 1:近藤(18)-2:山田(21)-3:斎藤(34)-4:森(50)-5:山下(33)*** After *** List(4): 1:近藤(18)-2:山田(21)-3:森(50)-4:山下(33)2番は森(50)です 課題141201 • 国語、算数、理科、社会の4科目の点数と名前を 持つデータ型PScoreを作り、それをListに入れて各 科目の平均点を計算するプログラム ProcessPScore.ccを示せ。 (PScoreはPDを参考に作ること) • 作成方法: • 作成した3つのコード PScore.h,PScore.cc,ProcessPScore.ccをワードに添付し て示すこと。 • 提出方法: • メールで。 • メールの本文中にも学籍番号を氏名を明記すること。 • 提出先:[email protected] • メールタイトル:”アルゴリズム課題141201” ←厳守! • 期限:2014年12月7日(日)
© Copyright 2024 ExpyDoc