440 likes | 528 Views
第5回 連結リストを使ったプログラム. ~配列以外のデータ構造に挑戦! ~. 学習目標. Java における参照の仕組みを説明できる 基本データ型と参照型の違いを説明できる 連結リストを使ったプログラムが書ける 連結リストを使う利点を説明できる 連結リストの概念を説明できる 連結リストへの追加、削除、検索のプログラムを Java を使って書ける. 5.1 参照の仕組み. 参照の仕組み練習問題 5.1.1 Java における参照の仕組み ①メモリと番地 ②参照とメモリの仕組み ③基本データ型と参照型. 参照の仕組み練習問題. テキスト(5.1 ) の
E N D
第5回 連結リストを使ったプログラム ~配列以外のデータ構造に挑戦!~
学習目標 • Javaにおける参照の仕組みを説明できる • 基本データ型と参照型の違いを説明できる • 連結リストを使ったプログラムが書ける • 連結リストを使う利点を説明できる • 連結リストの概念を説明できる • 連結リストへの追加、削除、検索のプログラムをJavaを使って書ける
5.1 参照の仕組み • 参照の仕組み練習問題 • 5.1.1 Javaにおける参照の仕組み • ①メモリと番地 • ②参照とメモリの仕組み • ③基本データ型と参照型
参照の仕組み練習問題 • テキスト(5.1)の • リスト「参照練習問題1」 • リスト「参照練習問題2」 がどのような出力をするか考えなさい。
参照練習問題1 public static void main(String args[]){ int x; int y; x = 3; y = x; y = 15; System.out.println(x); System.out.println(y); }
参照練習問題2 public static void main(String args[]){ TestClass x; TestClass y; x = new TestClass(); x.id = 3; y = x; y.id = 15; System.out.println(x.id); System.out.println(y.id); } class TestClass { int id; }
答え • 参照練習問題1315 • 参照練習問題21515
①メモリと番地 • プログラムは、変数をメモリに格納します。 • メモリには、すべての場所に番地がついています。 • この番地のことを参照といったりします。 メモリ 番地 内容 100 101 102 103 104
番地(101) 番地(100) 番地(101) 内容 内容 x x 3 x x x x x x x y y 100 100 100 100 100 100 100 100 3 0(初期値) 0(初期値) 0(初期値) 0(初期値) 3 101 101 101 101 101 3 0(初期値) x 100 100 100 0(初期値) y y y y 101 101 101 3 0(初期値) 0(初期値) 0(初期値) y 101 0(初期値) 内容 内容 x x x x 3 3 3 x 100 100 0(初期値) y y y y y 0(初期値) 3 15 15 101 0(初期値) ②参照とメモリの仕組み(1) メモリ 番地 内容 int x; int y; x = 3; y = x; y = 15; System.out.println(x); System.out.println(y); 100 101 102 103 104
メモリ メモリ 番地(100) 番地(101) 番地 番地 番地 内容 内容 内容 内容 TestClass x; TestClass y; x = new TestClass(); x.id = 3; y = x; y.id = 15; System.out.println(x.id); System.out.println(y.id); TestClass x; TestClass y; x = new TestClass(); x.id = 3; y = x; y.id = 15; System.out.println(x.id); System.out.println(y.id); x x x x x x x x 100 100 100 null 1000 null null 0(初期値) 1000 null 0(初期値) 0(初期値) 0(初期値) 1000 null 0(初期値) 1000 1000 null 0(初期値) y y y y y 101 101 101 null 1000 null null 1000 null オブジェクト用のメモリ オブジェクト用のメモリ 1000 1000 1000 3 0(初期値) 3 0(初期値) 15 3 3 3 1001 1001 ②参照とメモリの仕組み(2) メモリ 番地 内容 TestClass x; TestClass y; x = new TestClass(); x.id = 3; y = x; y.id = 15; System.out.println(x.id); System.out.println(y.id); 100 101 オブジェクト用のメモリ 1000 1001
③基本データ型と参照型 • 基本データ型→値が直接入るタイプ • 参照型→オブジェクト用のメモリに生成され、参照が入るタイプ • どうやって見分けたらいいでしょうか? ※これはJavaだけの話です。
基本データ型を覚えよ • Javaの基本データ型は8種類しかない。 • 整数が入るもの • int • long • short • 真偽値が入るもの • boolean • 小数が入るもの • float • double • 文字が入るもの • byte(1バイト文字) • char(2バイト文字)
その他はすべて参照型 • new 演算子でインスタンス化する必要があるもの • 実は配列も参照型です。 オブジェクト用のメモリ 番地 内容 [0] 1000 0 [1] 1001 0 int[] idArray = new int[5]; [2] 1002 0 メモリ [3] 1003 0 番地 内容 [4] 1004 0 idArray 101 1000(番地)
まとめJavaにおける参照の仕組み • 変数を宣言すると、メモリに領域が確保される。 • =(代入)記号での代入文は、値のコピーが行われる。 • ただし、オブジェクトの場合は、値に参照が入っているため、参照のコピーが行われる。 • このとき、インスタンスのコピーは行われない。 • インスタンスを生成するとオブジェクト用のメモリが確保される。
5.2 連結リスト • 5.2.1 配列にこだわる必要はない • 5.2.2 連結リストとは?
5.2.1 配列にこだわる必要はない • 配列は使いやすいのですが、問題点もあります。 • 考えてみましょう
配列は大きさが決まっている • 配列は、作るときに大きさを決める必要があります。 • その大きさ以上要素を入れることができません。 • また、要素が入っていないと、メモリの無駄になります。
間に割り込んで挿入するのが大変 • テキストエディタ(メモ帳,mule…)を作ることを考えましょう。 • 機能: • 文字を挿入する • 文字を削除する
配列で作ったとすると、、、 • 一文字一文字を配列にいれて管理します。 番地 内容 [0] 1000 ‘お’ [1] 1001 ‘は’ [2] 1002 ‘よ’ [3] 1003 ‘う’ [4] 1004 ‘ざ’ [5] 1005 ‘い’ [6] 1006 ‘ま’ [7] 1007 ‘す’
‘ざ’ ‘い’ ‘ま’ 挿入はどうするか? 番地 内容 [0] 1000 ‘お’ [1] 1001 ‘は’ [2] 1002 ‘よ’ [3] 1003 ‘う’ ‘ご’を挿入したい [4] 1004 ‘ざ’ ‘ご’ [5] 1005 ‘い’ [6] 1006 ‘ま’ [7] 1007 ‘す’
配列での実装の問題点 • もし、これが、1万文字のレポートの最初の所だったらどうなるか? • 一文字挿入するごとに、1万回の移動が必要 • 遅すぎてだれも使ってくれません
5.2.2 連結リストとは? 100番地 102番地 104番地 106番地 108番地 ‘お’ ‘は’ ‘よ’ ‘ご’ ‘ざ’ 102 104 106 108 null
実際のメモリ上では 番地 内容 100 ‘お’ 101 102 102 ‘は’ 103 104 104 ‘よ’ 105 106 106 ‘う’ 107
110 110番地 ‘う’ 106 ①連結リストの特徴(1)連結リストへの挿入 • 移動しなくて済む 100番地 102番地 104番地 106番地 108番地 ‘お’ ‘は’ ‘よ’ ‘ご’ ‘ざ’ 102 104 106 108 null
104番地 104番地 ‘よ’ ‘よ’ 106 106 106 (2)連結リストからの削除 • もっと簡単 100番地 102番地 106番地 108番地 ‘お’ ‘は’ ‘ご’ ‘ざ’ 102 104 108 null
③連結リストの利点・欠点 • 考えてみましょう
③連結リストの利点・欠点 • 利点 • メモリをあらかじめ確保しておく必要が無い • 必要十分な量だけその都度確保できる • メモリの許す限り大きくできる • 挿入、削除が非常に早い • 欠点 • 番地を保存しておくためのメモリ領域を取る • 検索が遅い • 最初から順繰りに辿っていかないといけない • 配列ならば、バイナリサーチ(第8回)などの早い検索方法がある
5.3 連結リストを実装する • 5.3.1 連結リストの実装 • ①連結リストの実装例 • ②クラス設計 • 5.3.2 連結リストのアルゴリズム • ①追加アルゴリズム • ②検索アルゴリズム • ③削除アルゴリズム
①連結リストの実装例 • 前回作ったプログラムを連結リストで作り直す • ItemTypeクラスは変更なし • (前回の配列バージョンも残しておいてください) • 例題5-1-(複数のクラスで一つのプログラムです) • 「Example5_1.java」 • 「ItemType.java」 • 「ItemTypeList.java」 • 「LinkObject.java」 • 「LinkTerminal.java」
②クラス設計 • 前回同様、ExampleクラスとItemTypeListクラスを分離します ItemTypeList{ add(); delete(); search(); display(); } Example{ main(); }
②クラス設計(1)LinkObjectクラス • 連結リスト用オブジェクトLinkObjectを作る 例題5-1 (Example5_1.java) //連結リスト用オブジェクト class LinkObject { ItemType data; //商品種類 LinkObject next; //次の要素への参照 } ??自分で自分を持ってるの??
(1)LinkObjectクラス • 実は参照なので、図のようになります。 //連結リスト用オブジェクト class LinkObject { ItemType data; LinkObject next; } 100番地 102番地 22(id) 23(id) ※ ※ コーラ ソーダ 102番地 null ※実際にはItemTypeも参照です。
(2)LinkTerminalクラス 100番地 102番地 104番地 106番地 108番地 2221 2222 2223 2224 2225 コーラ ソーダ オレンジ 紅茶 緑茶 102番地 104番地 106番地 108番地 null first last 追加や検索をするために、Exampleクラスは、 常にリストの最初の番地(first)と最後の番地(last) だけは、知っておく必要があります。
最初の番地 • 最後の番地 (2)LinkTerminalクラス • 今回は引数として、配列ではなく、最初の番地(first)と最後の番地(last)を渡す必要があります ItemTypeList{ add(); delete(); search(); display(); } Example{ main(); }
LinkTerminal オブジェクト (2)LinkTerminalクラス • 引数用オブジェクトLinkTerminalを作り、それを渡すことにします //連結リストの始点と終点をもつクラス public class LinkTerminal { LinkObject first;//始点 LinkObject last;//終点 } ItemTypeList{ add(); delete(); search(); display(); } Example{ main(); }
5.3.2 連結リストのアルゴリズム • ①追加アルゴリズム • ②検索アルゴリズム • ③削除アルゴリズム
108番地 null null 108番地 2223 first last last 緑茶 追加(1)一般的な追加 public void add(LinkTerminal linkTerminal,ItemType addItemType){ //追加する連結オブジェクトを生成する LinkObject addLink = new LinkObject(); addLink.data = addItemType; linkTerminal.last.next = addLink; linkTerminal.last = addLink; } } 100番地 102番地 2221 2222 コーラ ソーダ 102番地 null
102番地 null null 2223 first last first last 緑茶 追加(2)一番最初の追加 public void insert(LinkTerminal linkTerminal , ItemType addItemType ){ LinkObject addLink = new LinkObject(); addLink.data = addItem; if(linkTerminal.first == null){ linkTerminal. first = addLink; linkTerminal. last = addLink; }else{ linkTerminal.last.next = addLink; linkTerminal.last = addLink; }} null
2222 current current 検索(1)商品種類が見つかる場合 public ItemType search(int searchId, LinkTerminal linkTerminal){ LinkObject current=linkTerminal.first; while(current!=null){ if(current.data.id==searchId){ System.out.println(“見つかりました”) ;return current.data; } current=current.next; } System.out.println(“見つかりませんでした”);return null;} searchId 100番地 102番地 104番地 2221 2222 2223 紅茶 緑茶 水 102番地 104番地 null first last
3333 searchId current current current 検索(2) 商品種類が見つからない場合 public ItemType search(int searchId, LinkTerminal linkTerminal){ LinkObject current= linkTerminal.first; while(current!=null){ if(current.data.id==searchId){ System.out.println(“見つかりました”) ;return current.data; } current=current.next; } System.out.println(“見つかりませんでした”);return null;} 100番地 102番地 2221 2221 紅茶 緑茶 102番地 null null first last
2222 × 104番地 current current previous previous 削除(1) リストの中央で見つかる場合 public ItemType delete(int deleteId, LinkTerminal linkTerminal){ LinkObject current=linkTerminal.first; LinkObject previous; while(current!=null){ if(current.data.id==deleteId){ previous.next=current.next; return current.data; } previous=current; current=current.next; }} deleteId 100番地 102番地 104番地 2221 2222 2223 紅茶 緑茶 水 102番地 104番地 null null first last
2221 current first previous 削除(2) リストの最初で見つかる場合 public ItemType delete(int deleteId, LinkTerminal linkTerminal){ LinkObject current=first; LinkObject previous; while(current!=null){ if(current.data.id==deleteId){ if(currrent==first){ first=current.next; return current.data; } }} deleteId 100番地 102番地 104番地 2221 2222 2223 紅茶 緑茶 水 102番地 104番地 null null first last
2223 × null current last current current previous previous previous 削除(3)リストの最後で見つかる場合 public ItemType delete(int deleteId, LinkTerminal linkTerminal){ LinkObject current= linkTerminal.first; LinkObject previous; while(current!=null){ if(current.data.id==deleteId){ if(corrent== linkTerminal.last){ last=previous; last.next=null; return current.data; }previous=current; current=current.next;} }} deleteId 100番地 102番地 104番地 2221 2222 2223 紅茶 緑茶 水 102番地 104番地 null null first last
102番地 102番地 ‘よ’ ‘よ’ 103 103 ガベージ・コレクション • 削除するときに無駄なメモリが残ってしまうきがするのですが? 100番地 101番地 103番地 104番地 ‘お’ ‘は’ ‘ご’ ‘ざ’ 101 102 104 null Javaでは、いらないメモリを常に見張っている「ガベージコレクタ」 というすばらしい機能が標準でついています。 誰からも参照されていないオブジェクトを自動的にメモリから消します。