アルゴリズムとデータ構造 2010年7月1日 酒居敬一([email protected]) http://www.info.kochi-tech.ac.jp/k1sakai/Lecture/ALG/2010/index.html 待ち行列(FIFO)(44ページ) データ挿入 データ取得 待ち行列(データの挿入・取得) 待ち行列の配列による実現 データ挿入 データ取得 新しい要素を入れようとすると入らない →右へコピーして移動 →隙間を空ける リングバッファ(46ページ) 配列の最初と最後を接続して環にしたもの 2つのポインタでデータの出し入れを管理 データの先頭を指すポインタ head, front データの最後尾を指すポインタ tail, rear 2つのポインタが重なったらデータは空 領域の大きさをnとしたらポインタの位置はnとおり データの数が0からnまでn+1とおりある ポインタが重なったら、空か満杯の状態が重なる… リングバッファ 挿入口 •環状のデータ格納領域 •データの存在を示すポインタ 取り出し口 フロント リア リア フロント リア 満杯になったとき、 リアとフロントのポインタが 重なってしまって 空と区別が付かない 配列を使用したリングバッファ 配列には始まりと終わりがある ポインタが終わりまで移動したら先頭へ戻る (フロント-リア)の演算でも境界を考慮 ラップラウンド処理 ラップラウンド処理 条件文で判定 配列の大きさを2のべき乗にする 配列のインデックスをビットごとのAND処理 public class Queue { private Queue() { } public Queue(int aMaxSize) { int realSize = aMaxSize + 1; this.maxSize = realSize; this.queueArray = new Object[realSize]; this.front = 0; this.rear = 0; } } private private private private int front; int maxSize; Object[] queueArray; int rear; •データのおき場所は配列 •front, rearというポインタで管理 •キューの容量はmaxSizeで管理 public Object dequeue() { if(this.isEmpty()){ System.err.println("待ち行列は空です"); return null; } Object dequedObject = this.queueArray[this.front]; this.queueArray[this.front] = null; ++this.front; if(this.maxSize == this.front){ this.front = 0; •frontの指すところがキューの先頭 } return dequedObject; •先頭と最後尾が同じ場合は空 } •条件文でラップラウンド処理 public boolean isEmpty() { return (this.rear == this.front); } public boolean enqueue(Object aTarget) { if(this.isFull()){ System.err.println("待ち行列はいっぱいです"); return false; } this.queueArray[this.rear] = aTarget; ++this.rear; if(this.maxSize == this.rear){ this.rear = 0; •rearの指すところがキューの最後尾 } return true; •先頭と最後尾が同じ場合は空 } •そうならないようにする判定が必須 •条件文でラップラウンド処理 public boolean isFull() { return ((this.rear + 1) == this.front); } public void printAll() { System.out.println("待ち行列の内容"); if(this.isEmpty()){ System.out.println(); •場合分けしてラップラウンド処理 return; •frontから配列終わりまでの表示 } •配列先頭からrearまでの表示 int count = 1; int position = this.front; int limit = (this.front > this.rear)? this.maxSize: this.rear; while(position < limit){ System.out.println(count +"\t" + this.queueArray[position]); ++count; ++position; } position = 0; limit = (this.front > this.rear)? this.rear: 0; while(position < limit){ System.out.println(count +"\t" + this.queueArray[position]); ++count; ++position; } System.out.println(); } 値型と参照型ふたたび… • 現代の主流はノイマン型プロセッサによる計算 – 命令はメモリに蓄積し、逐次読み出し実行 みなさんは今、データ構造を勉強し、プログラムを勉強しています。 – データもメモリに置き、命令に従って処理される それでは、プログラムが動作中のメモリのイメージはわかりますか? • メモリからのロード・ストア、四則演算、論理演算 Javaにおける基本型とオブジェクト(構造型)を説明できますか? •そして値型と参照型について説明できますか? 機械語のレベルではデータはほぼすべて参照型 – データどおしの代入という操作すらないものが多い – アドレスを指定してロード、アドレスを指定してストア • つまりデータはアドレスにより参照される – このあたりの区別がわかりやすいので実験2ではH8を使う – 身近なIA32アーキテクチャとそのアセンブラはわかりにくい // リストのデータ構造 /* リストのデータ構造 */ // Javaでアクセッサあり /* C言語版その1 */ public class Element1 { union Object { public Element1(Object aData) { int Integer; this.data = aData; double Double; } }; public Object getData() { struct Element1 { return this.data; union Object data; } struct Element1 *next; public Element1 getNextElement() { }; return this.next; } // リストのデータ構造 public void setNextElement(Element1 anNextElement) { // Javaでアクセッサなし this.next = anNextElement; public class Element2 { } public Element2() { private Object data; // 参照型 } private Element1 next; public Object data; } public Element2 next; } /* リストのデータ構造 */ /* C言語版その2 */ struct Element2 { void *data; struct Element2 *next; }; // リストのデータ構造 // Javaでアクセッサあり // Element1 next_element1; // どこかで与えられている Element1 new_element1; new_element1 = new Element1(new Integer(100)); new_element1. setNextElement(next_element1); 100 Integerのインスタンス /* リストのデータ構造 *//* C言語版その1 */ 100 */ /* struct Element1 *next_element1: /* どこかで与えられている new_element1 structElement1のインスタンス Element1 *new_element1; data new_element1getData() = malloc(sizeof (struct Element1)); next data new_element1->data.Integer getNextElement() = 100; new_element1->next = next_element1; next setNextElement() // リストのデータ構造 // Javaでアクセッサなし data next_element1 100 // Element2 next_element2; // どこかで与えられている next Element2 new_element2; new_element2 = new Element2(); next_element1 next new_element2.data = new Integer(100); new_element2. next = next_element2; Element1のインスタンス getData() getNextElement() next_element1 data /* リストのデータ構造 *//* C言語版その2 */ new_element2 setNextElement() Element2のインスタンス /* struct Element2 *next_element2: /* どこかで与えられている */ data struct Element2 *new_element2; data next next Element2のインスタンス new_element2 =next malloc(sizeof (struct Element2)); new_element2->data = malloc(sizeof (int)); data *((int *)new_element2->data) = 100; /* cast as lvalue で行儀が悪い */ next new_element2->next = next_element2; next_element2 // リストのデータ構造 // Javaでアクセッサあり public class Element1 { public Element1(int aData) { this.data = aData; } public int getData() { return this.data; } public Element1 getNextElement() { return this.next; } public void setNextElement(Element1 anNextElement) { this.next = anNextElement; } } private int data; // 値型 private Element1 next; /* リストのデータ構造 */ /* C言語版その1 */ struct Element1 { int data; struct Element1 *next; }; // リストのデータ構造 // Javaでアクセッサなし public class Element2 { public Element2() { } public int data; public Element2 next; } /* リストのデータ構造 */ /* C言語版その2 */ struct Element2 { int *data; struct Element2 *next; }; // リストのデータ構造 // Javaでアクセッサあり // Element1 next_element1; // どこかで与えられている Element1 new_element1; 100 new_element1 = new Element1(100); new_element1. setNextElement(next_element1); /* リストのデータ構造 *//* C言語版その1 */ /* struct Element1 *next_element1: /* どこかで与えられている */ new_element1 structElement1のインスタンス Element1 *new_element1; data new_element1getData() = malloc(sizeof (struct Element1)); next data new_element1->data.Integer getNextElement() = 100; new_element1->next = next_element1; next setNextElement() // リストのデータ構造 // Javaでアクセッサなし 100 // Element2 next_element2; // どこかで与えられている next Element2 new_element2; 100 Element1のインスタンス new_element2 = new Element2(); next_element1 next new_element2.data = 100; getData() new_element2. next = next_element2; data getNextElement() new_element2 /* リストのデータ構造 *//* C言語版その2 */ next setNextElement() Element2のインスタンス /* struct Element2 *next_element2: /* どこかで与えられている */ data struct Element2 *new_element2; 100 next Element2のインスタンス new_element2 =next malloc(sizeof (struct Element2)); new_element2->data = malloc(sizeof (int)); data *((int *)new_element2->data) = 100; /* cast as lvalue で行儀が悪い */ next new_element2->next = next_element2; next_element2 Javaのfinal • クラスへのfinal – 継承ができなくなる • メソッドへのfinal – オーバーライドできなくなる • フィールドへのfinal – 変更できなくなる • 値型では定数としてふるまう • 参照型では、定数として振舞わない – 参照先の値を変更できなくするというものでもない まとめ • データ構造 – 配列・リスト・スタック・待ち行列・木 • プログラムへの変換 – 参照型と値型の違い・利害得失 • メモリのイメージ – 抽象的なデータ構造との対応 • プログラミング言語による違い – Javaにもポインタは存在する • ただし、ポインタ演算はない。 – Javaと異なり、Cの構造型は値型である • Javaのほうが参照を多用するけど、表立って見えない
© Copyright 2024 ExpyDoc