15 集合データ構造入門

15.1 学習目標

15.2 集合データ構造

15.2.1 ListTurtle入門

これまでのプログラムでも,同種の要素を複数扱う必要があるプログラムがありました. 例えば,次の4匹の亀を扱うプログラムを考えてみましょう.

リスト 15.2.1.1 FourTurtles0.java
  1: /*
  2: * FourTurtles0.java
  3: * 4匹の亀を動かすプログラム
  4: * Created on 2012/01/07
  5: * Copyright(c) 2011 Yoshiaki Matsuzawa, Shizuoka University. All rights reserved.
  6: */
  7: public class FourTurtles0 extends Turtle {
  8: 	
  9: 	// 起動処理
 10: 	public static void main(String[] args) {
 11: 		Turtle.startTurtle(new FourTurtles0(), args);
 12: 	}
 13: 	
 14: 	// タートルを動かす処理
 15: 	public void start() {
 16: 		hide();
 17: 		window.setSize(1100,500);
 18: 		Turtle turtle0 = new Turtle();
 19: 		Turtle turtle1 = new Turtle();
 20: 		Turtle turtle2 = new Turtle();
 21: 		Turtle turtle3 = new Turtle();
 22: 		{	//c//初期位置に移動する
 23: 			turtle0.warp(100,100);
 24: 			turtle1.warp(100,200);
 25: 			turtle2.warp(200,100);
 26: 			turtle3.warp(200,200);
 27: 		}
 28: 		{	//for
 29: 			int i = 0;
 30: 			while(i < 360){
 31: 				{	//一コマの処理をする
 32: 					turtle0.fd(1);
 33: 					turtle0.rt(1);
 34: 					turtle1.fd(1);
 35: 					turtle1.rt(1);
 36: 					turtle2.fd(1);
 37: 					turtle2.rt(1);
 38: 					turtle3.fd(1);
 39: 					turtle3.rt(1);
 40: 					i++;
 41: 				}
 42: 			}
 43: 		}
 44: 	}
 45: }

ここ をクリックすると、プログラムをダウンロードできます。

下のボタンを押すと、FourTurtles0プログラムが実行できます。

上記プログラムの問題は,カメを増やすたびに変数を追加したり,それに対応する動きのプログラムを書かなければならないことです. その結果,プログラム中に似たようなプログラムが繰り返しでてきてしまっています.

この章では,人間がプログラムを繰り返し書くのではなく,コンピュータに繰り返しをさせることで同様の目的を達成する方法を考えます.

必要なのは「集合データ構造」です.「集合データ構造」とは,同種のデータを一括してプログラムで扱うことの出来る仕組みで, 繰り返し(これはもう習得済みですね)と組み合わせることで,大量のデータを少量のプログラムで指示することが出来ます.

次のプログラムでは,タートルで使える集合データ構造の,ListTurtleクラスを使って4匹の亀を扱うプログラムを書いてみたものです.

リスト 15.2.1.2 FourTurtles1.java
  1: /*
  2: * FourTurtles.java
  3: * 4匹の亀を動かすプログラム1(ListTurtle+カーソルで管理する)
  4: * Created on 2012/01/07
  5: * Copyright(c) 2011 Yoshiaki Matsuzawa, Shizuoka University. All rights reserved.
  6: */
  7: public class FourTurtles1 extends Turtle {
  8: 	
  9: 	// 起動処理
 10: 	public static void main(String[] args) {
 11: 		Turtle.startTurtle(new FourTurtles1(), args);
 12: 	}
 13: 	
 14: 	// タートルを動かす処理
 15: 	public void start() {
 16: 		hide();
 17: 		window.setSize(1100,500);
 18: 		ListTurtle<Turtle> turtles = new ListTurtle<Turtle>();
 19: 		turtles.warpByTopLeft(100,300);
 20: 		{	//c//タートルを4匹作成する
 21: 			int i = 0;
 22: 			while(i < 4){
 23: 				turtles.add(new Turtle());
 24: 				i++;
 25: 			}
 26: 		}
 27: 		{	//c//初期位置に移動する
 28: 			turtles.get(0).warp(100,100);
 29: 			turtles.get(1).warp(100,200);
 30: 			turtles.get(2).warp(200,100);
 31: 			turtles.get(3).warp(200,200);
 32: 		}
 33: 		{	//for
 34: 			int i = 0;
 35: 			while(i < 360){
 36: 				{	//for
 37: 					int j = 0;
 38: 					while(j < 4){
 39: 						{	//一コマの処理
 40: 							turtles.moveCursorToNext();
 41: 							turtles.getObjectAtCursor().fd(1);
 42: 							turtles.getObjectAtCursor().rt(1);
 43: 							j++;
 44: 						}
 45: 					}
 46: 				}
 47: 				i++;
 48: 			}
 49: 		}
 50: 	}
 51: }

ここ をクリックすると、プログラムをダウンロードできます。

下のボタンを押すと、FourTurtles1プログラムが実行できます。

21行目でListTurtleを作っています.他のオブジェクトの生成と基本的には同じですが,ListTurtleに入れることの出来るオブジェクトの型を<>の中に書きます(2カ所).

				
	ListTurtle<Turtle> turtles = new ListTurtle<Turtle>();
				
リストの変数名

変数名は任意ですが,リストに入るものの名前の複数形にすると良いでしょう.

ListTurtleで使える基本的なメソッドとして,追加と削除,閲覧があります.

これらのメソッドを繰り返しを使って呼ぶことで,リストに入っている複数のオブジェクトすべてに対して,1行で命令をすることが出来ます.

集合データ構造と番地

ListTurtleでも,Java標準ライブラリでも,要素の番地は0番地から始まり,[要素数-1]番地まで存在します.

メモリアドレスの扱いやすさの関係から伝統的にC言語では0番地から始まる言語仕様で,C言語に影響を受けたJava言語も0番地から始まる仕様になっています.

しかしながら,人間にとっては1番地から始まり,[要素数]番地まで存在する方がわかりやすいので, 教育用言語を中心に1番地から始まるプログラミング言語も多く存在します.(例えばSmalltalk,Pascalなど).

連続メソッド呼び出し

戻り値を変数に格納するのではなく,メソッドを次々と呼び出すことが出来ます.例えば,30行目では次のようなプログラムがあります.

				
	turtles.get(0).warp(100, 100);
					

これは,turtlesリストの0番目の要素を取り出して,その戻り値(1つめのタートル)に対して,warpメソッドを呼び出すという意味になります.

(戻り値が返ってくる限りは,1行で無制限にメソッドを呼び出すことが出来ます.)

ListTurtleで使える便利な機能として,カーソル機能があります.主な機能を以下に示します.

カーソルを進めて,カーソル位置のオブジェクトを取得して何か命令を行うことを繰り返すことによって,複数のオブジェクトすべてに対して,1行で命令をすることが出来ます.

(カーソルがリストの最後にあるときにカーソルを進めると,最初に戻るところが便利なところです.)

15.2.2 アニメーションへの応用

ListTurtleをアニメーションに応用した例を示します.

リスト 15.2.2.1 WalkingMan2.java
  1: /*
  2: * WalkingMan2.java
  3: * 人が歩くアニメーションプログラム (List使用版)
  4: * Created on 2012/01/07
  5: * Copyright(c) 2011 Yoshiaki Matsuzawa, Shizuoka University. All rights reserved.
  6: */
  7: public class WalkingMan2 extends Turtle {
  8: 	
  9: 	// 起動処理
 10: 	public static void main(String[] args) {
 11: 		Turtle.startTurtle(new WalkingMan2(), args);
 12: 	}
 13: 	
 14: 	// タートルを動かす処理
 15: 	public void start() {
 16: 		hide();
 17: 		window.setSize(1100,500);
 18: 		ListTurtle<ImageTurtle> holder = new ListTurtle<ImageTurtle>(true);
 19: 		holder.warpByTopLeft(50,200);
 20: 		{	//アニメーション用画像を用意する
 21: 			int i = 1;
 22: 			while(i <= 8){
 23: 				holder.addLast(new ImageTurtle((("man" + i) + ".gif")));
 24: 				i++;
 25: 			}
 26: 		}
 27: 		Turtle man = new Turtle();
 28: 		while(true){
 29: 			sleep(0.1);
 30: 			{	//1コマの処理
 31: 				holder.moveCursorToNext();
 32: 				man.looks(holder.getObjectAtCursor());
 33: 			}
 34: 			update();
 35: 		}
 36: 	}
 37: }

ここ をクリックすると、プログラムをダウンロードできます。

下のボタンを押すと、WalkingMan2プログラムが実行できます。

autohideモード

アニメーションをするときには,リストに入れたオブジェクトは,元の位置(キャンバス)からは消去して欲しいことがあります. そんなときに便利なのがListTurtleのautohideモードの指定です.autohideモードでは,リストは自動的にリストに入ってきたものをhide()してくれます.

autohideモードの指定には,new ListTurtleの所で,(true)の引数を与えます.

15.3 ListTurtleの命令リスト

15.3.1 リストを作る命令

ListTurtle<[要素のクラス名]>[変数名] = new ListTurtle<[要素のクラス名]>()
リストタートルを作成します.
ListTurtle<[要素のクラス名]>[変数名] = new ListTurtle<[要素のクラス名]>(true)
autohideモードで,リストタートルを作成します.
ListTurtle<[要素のクラス名]>[変数名] = new ListTurtle<[要素のクラス名]>(true, "[名前]")
autohideモードで,名前付きで,リストタートルを作成します.

以下,「T」とは,リスト作成時に<[要素のクラス名]> で指定したクラスに置き換わることを示しています.

15.3.2 追加と削除

void add(T object)
objectをリストの最後に追加します.addLast(object)メソッドと同様です.
void addLast(T object)
objectをリストの最後に追加します.
void addFirst(T object)
objectをリストの最初に追加します.
void add(int index, T object)
indexの位置に要素を追加します.
void addAll(ListTurtle from)
fromリストの要素すべてをこのリストに追加します.
void moveAllTo(ListTurtle to)
このリストの要素をすべてtoリストへ移動します.
T remove(T object)
要素を削除します.
T remove(int i)
i番目の要素を削除します.
T removeFirst()
最初の要素を削除します.
T removeLast()
最後の要素を削除します.
void removeAll()
すべての要素を削除します.

15.3.3 取得関係

T get(int i)
i番地の要素を取得します.(要素は0番地から始まり,[要素数-1]番地まで存在します.)
int getSize()
要素の数を返します

15.3.4 カーソル関係

int getCursor()
カーソル位置を取得します.
void setCursor(int newCursor)
カーソル位置を設定します.
void moveCursorToNext()
カーソルを前に進めます.(最後の要素の場合は先頭に戻ります.)
void moveCursorToPrevious()
カーソルを後ろに進めます.(先頭の要素の場合は最後に飛びます.)
T getObjectAtCursor()
カーソル位置にある要素を取得します.
void addToCursor(T object)
カーソル位置(の前)に要素を追加します.(addToBeforeCursor()と同じです)
void addToBeforeCursor(T object)
カーソル位置(の前)に要素を追加します.
void addToAfterCursor(T object)
カーソル位置(の後)に要素を追加します.
T removeAtCursor()
カーソル位置にある要素を削除します.
int getNumberAtCursor()
カーソル位置にある要素の数値表現を返します.(1.5以上では推奨されません.CardTurtleのgetNumber()を使ってください)
String getStringAtCursor()
カーソル位置にある要素の文字列表現を返します.(1.5以上では推奨されません.CardTurtleのgetText()を使ってください)

15.3.5 その他の命令

void shuffle()
中身をかきまぜます。
void setBgColor(Color bgColor)
背景の色を変更します.

15.4 練習問題

15.4.1 アニメーションをListTurtleを使って作り直そう

「0655アニメーションを作ろう」で作ったプログラムについて,ListTurtleを使って作り直してみてください.

ファイル名は「Zero655List.java」とすること.

15.4.2 大量流れ星アニメーションを作ろう

「流れ星アニメーションを作ろう」で作ったプログラムについてListTurtleを使って作り直し,たくさんの星が流れるアニメーションを作ってみてください.

下のボタンを押すと、Snowsプログラムが実行できます。

ファイル名は「SuperShootingStar.java」とすること.