Microsoft Word - 09

Similar documents
Microsoft Word - 13

Microsoft Word - 03

Microsoft Word - 12

Microsoft PowerPoint - 10.ppt [互換モード]

Microsoft Word - 05

Taro-再帰関数Ⅲ(公開版).jtd

Microsoft PowerPoint - C言語の復習(配布用).ppt [互換モード]

Taro-2分探索木Ⅰ(公開版).jtd

Microsoft PowerPoint - 計算機言語 第7回.ppt

Taro-リストⅢ(公開版).jtd

memo

gengo1-11

Microsoft PowerPoint - ca ppt [互換モード]

memo

バイオプログラミング第 1 榊原康文 佐藤健吾 慶應義塾大学理工学部生命情報学科

kiso2-09.key

プログラミング基礎

Taro-最大値探索法の開発(公開版

次に示す数値の並びを昇順にソートするものとする このソートでは配列の末尾側から操作を行っていく まず 末尾の数値 9 と 8 に着目する 昇順にソートするので この値を交換すると以下の数値の並びになる 次に末尾側から 2 番目と 3 番目の 1

Microsoft PowerPoint - lec10.ppt

Microsoft PowerPoint - C_Programming(3).pptx

Microsoft Word - 3new.doc

プログラミング実習I

プログラミング入門1

Taro-リストⅠ(公開版).jtd

プログラミング基礎

Taro-2分探索木Ⅱ(公開版).jtd

コンピュータ工学講義プリント (7 月 17 日 ) 今回の講義では フローチャートについて学ぶ フローチャートとはフローチャートは コンピュータプログラムの処理の流れを視覚的に表し 処理の全体像を把握しやすくするために書く図である 日本語では流れ図という 図 1 は ユーザーに 0 以上の整数 n

02: 変数と標準入出力

<4D F736F F D20438CBE8CEA8D758DC F0939A82C282AB2E646F63>

Microsoft PowerPoint - 説明3_if文switch文(C_guide3)【2015新教材対応確認済み】.pptx

02: 変数と標準入出力

Microsoft PowerPoint - 05.pptx

関数 C 言語は関数の言語 関数とは 関数の定義 : f(x) = x * x ; 使うときは : y = f(x) 戻り値 引数

C プログラミング演習 1( 再 ) 2 講義では C プログラミングの基本を学び 演習では やや実践的なプログラミングを通して学ぶ

プログラミングI第10回

Microsoft PowerPoint - algo ppt [互換モード]

<4D F736F F D2091E63589F182628CBE8CEA8D758DC08E9197BF2E646F6378>

情報処理演習 B8クラス

Prog1_10th

Microsoft PowerPoint - kougi7.ppt

第2回

Microsoft PowerPoint - exp2-02_intro.ppt [互換モード]

Microsoft Word - 10

4 分岐処理と繰返し処理 ( 教科書 P.32) プログラムの基本的処理は三つある. (1) 順次処理 : 上から下に順番に処理する ぶんきそろ (2) 分岐処理 : 条件が揃えば, 処理する はんぷく (3) 反復処理 : 条件が揃うまで処理を繰り返す 全てのプログラムは (1) から (3) の

PowerPoint プレゼンテーション

cp-7. 配列

PowerPoint プレゼンテーション

/*Source.cpp*/ #include<stdio.h> //printf はここでインクルードして初めて使えるようになる // ここで関数 average を定義 3 つの整数の平均値を返す double 型の関数です double average(int a,int b,int c){

I. Backus-Naur BNF : N N 0 N N N N N N 0, 1 BNF N N 0 11 (parse tree) 11 (1) (2) (3) (4) II. 0(0 101)* (

PowerPoint プレゼンテーション

Microsoft PowerPoint - lec4.ppt

Microsoft PowerPoint - 11.pptx

8 / 0 1 i++ i 1 i-- i C !!! C 2

Microsoft PowerPoint - CproNt02.ppt [互換モード]

演算増幅器

第2回

Microsoft PowerPoint - 09.pptx

プログラミング及び演習 第1回 講義概容・実行制御

Microsoft PowerPoint - IntroAlgDs-05-4.ppt

Taro-スタック(公開版).jtd

Microsoft PowerPoint - prog04.ppt

pp2018-pp9base

関数の呼び出し ( 選択ソート ) 選択ソートのプログラム (findminvalue, findandreplace ができているとする ) #include <stdiu.h> #define InFile "data.txt" #define OutFile "surted.txt" #def

02: 変数と標準入出力

関数の呼び出し ( 選択ソート ) 選択ソートのプログラム (findminvalue, findandreplace ができているとする ) #include <stdio.h> #define InFile "data.txt" #define OutFile "sorted.txt" #def

Microsoft Word - no206.docx

02: 変数と標準入出力

Taro-ポインタ変数Ⅰ(公開版).j

Prog1_15th

memo

:30 12:00 I. I VI II. III. IV. a d V. VI

Microsoft PowerPoint - kougi10.ppt

Java講座

論理と計算(2)

I. Backus-Naur BNF S + S S * S S x S +, *, x BNF S (parse tree) : * x + x x S * S x + S S S x x (1) * x x * x (2) * + x x x (3) + x * x + x x (4) * *

Microsoft Word - no12.doc

今回のプログラミングの課題 ( 前回の課題で取り上げた )data.txt の要素をソートして sorted.txt というファイルに書出す ソート (sort) とは : 数の場合 小さいものから大きなもの ( 昇順 ) もしくは 大きなものから小さなもの ( 降順 ) になるよう 並び替えること

Microsoft PowerPoint - 06.pptx

CプログラミングI

Microsoft PowerPoint - 12.ppt [互換モード]

char int float double の変数型はそれぞれ 文字あるいは小さな整数 整数 実数 より精度の高い ( 数値のより大きい より小さい ) 実数 を扱う時に用いる 備考 : 基本型の説明に示した 浮動小数点 とは数値を指数表現で表す方法である 例えば は指数表現で 3 書く

Microsoft Word - Cプログラミング演習(8)

Java プログラミング Ⅰ 7 回目 switch 文と論理演算子 今日の講義講義で学ぶ内容 switch 文 論理演算子 条件演算子 条件判断文 3 switch 文 switch 文 式が case のラベルと一致する場所から直後の break; まで処理しますどれにも一致致しない場合 def

02: 変数と標準入出力

Microsoft Word - no103.docx

Microsoft PowerPoint - C4(反復for).ppt

Taro-再帰関数Ⅱ(公開版).jtd

情報処理 Ⅱ 2007 年 11 月 26 日 ( 月 )

02: 変数と標準入出力

Taro-再帰関数Ⅰ(公開版).jtd

講習No.12

JavaプログラミングⅠ

Microsoft PowerPoint - prog07.ppt

講習No.9

memo

PowerPoint プレゼンテーション

今後の予定 6/29 パターン形成第 11 回 7/6 データ解析第 12 回 7/13 群れ行動 ( 久保先生 ) 第 13 回 7/17 ( 金 ) 休講 7/20 まとめ第 14 回 7/27 休講?

C のコード例 (Z80 と同機能 ) int main(void) { int i,sum=0; for (i=1; i<=10; i++) sum=sum + i; printf ("sum=%d n",sum); 2

PowerPoint プレゼンテーション

Transcription:

担当 : 富井尚志 (tommy@ynu.ac.jp) アルゴリズムとデータ構造 講義日程 1. 基本的データ型 2. 基本的制御構造 3. 変数のスコープルール. 関数 4. 配列を扱うアルゴリズムの基礎 (1). 最大値, 最小値 5. 配列を扱うアルゴリズムの基礎 (2). 重複除去, 集合演算, ポインタ 6. ファイルの扱い 7. 整列 (1). 単純挿入整列 単純選択整列 単純交換整列本日の内容 8. 整列 (2). マージ整列 クイック整列 9. 再帰的アルゴリズムの基礎. 再帰におけるスコープ. ハノイの塔など. 10. バックトラックアルゴリズム.8 王妃問題など. 11. 線形リストを扱うアルゴリズム 12. 木構造を扱うアルゴリズム (1) 基礎 13. 木構造を扱うアルゴリズム (2) 挿入, 削除, バランスなど. 14. ハッシング 15. その他のアルゴリズム 第 9 回 再帰的アルゴリズムの基礎 再帰的 とは あるものが部分的にそれ自身で構成されていたり, それ自身によって定義されている 例 1) 自然数例 2) 階乗関数 (i) 0 は自然数 (i) 0! 1 (ii) 自然数の次の要素も自然数 (ii) n! n*(n-1)! (n>0) 例 3) 木構造 (i) φ は木 ( 空木 (empty tree)) (ii) t1, t2 が木ならば, それらを 2 つの 子 としてもつ節点 (node) ならびに t1, t2 から構成される構造も木 再帰的アルゴリズムの図式 再帰はある意味での繰り返し 終了条件 が必要 図式 (a) P if () omp[s,p] これも再帰的?! (b) P omp[ S, if () P ] ( ただし,S は P を含まない文の集合,omp[S,P] は S と P の組み合わせ ) ある条件 がいつかは偽にならないといけない.( そうでないと無限に自分自身を呼び続け, プログラムが終了しない.) 扱っている問題や扱うべきデータが再帰的に定義されているときに適する. 1

変数のスコープ ( おさらい ) 再帰呼び出しの場合はどうなるか? アルゴリズムとデータ構造 第 3 回 有効範囲 のプリント参照 ( fact.c 本資料 p.5 ) ポイント 関数の内部で宣言される変数 ( 仮引数を含めて ) は, 関数本体のブロック内 でのみ有効. 例 )int func( int n1, int n2 ) int i, sum = 0; for (i=n1;i<=n2;i++) sum = sum + i; return sum; この変数 i, sum はこの関数の外からは見えない (= 参照できない, 代入できない ) 上記変数は関数呼び出しのたびに新しく別に作られる ( 例外 :static 宣言 ). 自分自身を再帰的に呼び出しても, 値は保存され, 混同することはない. 再帰プログラムの例その 1 ハノイの塔 (hanoi.c p.6) 条件を満足しつつ, 初期状態 から 目標状態 まで移行するにはどのように円盤を移動させればよいか? 初期状態 初期状態 3 枚 = = == == === === ---------------------------- 棒 棒 棒 目標状態 目標状態 = = == == === === ---------------------------- 棒 棒 棒 2

条件 1: 一度に一枚の円盤だけが移動できる. 条件 2: どの円盤もその円盤より小さい円盤の上に置いてはいけない. 条件 3: 棒 を補助的な場所として使用してよい. 再帰的な解法棒 から棒 に n 枚移動する場合は, 1) まず, 上から n-1 枚を棒 から棒 に移動. n-1 枚を動かす 再帰的 2) 棒 にある円盤一つを棒 に移動 ( 最も下にあるベースとなる円盤の移動 ) 3) 棒 の上から n-1 枚を棒 に移動. n-1 枚を動かす 再帰的 再帰を使うと良くない場合 問題が再帰的に定義できる 再帰的アルゴリズムが最良な方法 ある場合には再帰的な定義を単純な繰り返しに直すことが可能 こちらのほうが高速 本質的には, 非再帰的な機械を使って, 再帰的手続きが実現されているのであるから, すべての再帰的なプログラムは繰り返しのプログラムに書き換え可能. しかし, スタック ( 先入れ後だしのデータ保存場所 ) が必要. 問題は, 繰り返しアルゴリズムが明解であること. 典型的図式 --- 末尾再帰 (tail recursion) 終り ( もしくは始め ) において,1 回だけPの ( 再帰 ) 呼び出しがある場合. (a') P if () S; P (b') P S; if () P S の後に if()p を実行 P f = f0; while () S f は一つ前の計算結果を保存するための変数. 例 --- 階乗計算 ( fact.c 本資料 p.5 ) 少し複雑な例 --- フィボナッチ数 フィボナッチ数 fib(0) 0, fib(1) 1, fib(n) fib(n-1) + fib(n-2) fib(i-1) と fib(i-2) を保存する変数を用意すればよい. 3

再帰版 int fib( int n ) if (n == 0 ) return 0; else if ( n == 1 ) return 1; else return fib(n-1)+fib(n-2); ループ版 int fib( int n ) int x=1, y=0, i=1, z; /* x<->fib(i-1), y<->fib(i-2) */ /* n==0, n==1 の場合は省略 */ while ( i < n ) z = x; x = x + y; y = z; i++; return x; 再帰プログラムの例その2 ヒルベルト曲線 ( hilbert.c 本資料 p.8 ) 考案者. Hilbert 基本となる コの字 形の線図形を, 半分に縮小して回転したものを合成する操作を再帰的に行うことによって複雑な曲線を描くもの. このような曲線は一般に空間充填曲線と呼ばれ, ヒルベルト曲線以外にも, ペアノ曲線, ドラゴン曲線などがある. 再帰は, 最初は混乱するかも知れませんが, 慣れれば非常に楽な方法であることがわかります. ふんふん, なるほど... 4

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 /********************************************************** アルゴリズムとデータ構造 サンプルプログラム << 再帰プログラムの例 : 階乗 fact.c >> copyright (c) T.Mori <mori@forest.dnj.ynu.ac.jp> **********************************************************/ #include <stdio.h> int fact_rec(int n); int fact_nonrec(int m); これは簡単だから説明がなくても大丈夫ですね... int main(void) int m; m = 10; printf(" 階乗 ( 再帰 ) = %d n", fact_rec(m)); printf(" 階乗 ( 非再帰 ) = %d n", fact_nonrec(m)); return 0; /* 再帰版階乗計算 */ fact_rec( int n ) if ( n <= 0 ) return 1; else return n*fact_rec(n-1); /* f(n) = n * f(n-1) */ /* 非再帰版階乗計算 */ fact_nonrec( int m ) int fn,n; fn = 1; /* f(0) = 1 */ n = 1; while (n<=m) fn = n*fn; /* f(n) = n*f(n-1) */ n++; return fn; 実行結果 階乗 ( 再帰 ) = 3628800 階乗 ( 非再帰 ) = 3628800 5

全1 /********************************************************** 2 アルゴリズムとデータ構造 3 サンプルプログラム 4 << 再帰プログラムの例 : ハノイの塔 >> hanoi.c 5 copyright (c) T.Mori <mori@forest.dnj.ynu.ac.jp> 6 7 ハノイの塔 8 初期状態 9 3 枚 10 = = 11 == == 47 /* に移動する */ 12 === === 13 ---------------------------- 14 棒 棒 棒 15 目標状態 16 = = 17 == == 18 === === 19 ---------------------------- 20 21 棒 棒 棒 22 条件 1: 一度に一枚の円盤だけが移動できる. 23 条件 2: どの円盤もその円盤より小さい円盤の上においてはいけない. 24 条件 3: 棒 を補助的な場所として使用してよい. 25 26 **********************************************************/ 27 #include <stdio.h> 28 void hanoi(int height, char *src, char *dst, char *work); 29 void move(char *src, char *dst); 30 31 int main(void) 32 33 /* " 棒 " から 3 枚の円盤を " 棒 " に移動する.*/ 34 /* このとき " 棒 " を円盤の一時保持場所として利用する.*/ 35 hanoi( 3, " 棒 ", " 棒 ", " 棒 " ); 36 return 0; 37 38 39 /* src にある ndisk 枚の円盤を dst に移動する.*/ 40 /* このとき work を円盤の一時保持場所として利用する.*/ 41 void hanoi( int ndisk, char *src, char *dst, char *work) 42 43 if ( ndisk >= 1 ) /* 移動するのが 1 枚以上の場合は,*/ 44 hanoi(ndisk-1, src, work, dst); /* まず,ndisk-1 枚を作業領域に移し */ 45 move(src,dst); /* ndisk 枚めを目標の棒に移し */ 46 hanoi(ndisk-1, work, dst, src); /* 作業領域の ndisk-1 枚を目標の棒 */ てコメントです.6

48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 /* src の円盤を dst に移動する手続き */ /* ここでは 移動する というメッセージを印刷するだけ */ void move(char *src, char *dst) printf("%sにある一番上の円盤を %s へ移動する n", src, dst); 実行結果 棒 にある一番上の円盤を棒 へ移動する棒 にある一番上の円盤を棒 へ移動する棒 にある一番上の円盤を棒 へ移動する棒 にある一番上の円盤を棒 へ移動する棒 にある一番上の円盤を棒 へ移動する棒 にある一番上の円盤を棒 へ移動する棒 にある一番上の円盤を棒 へ移動する 66 67 68 69 図で書くとこうなります. 超ムズいパズルが超楽に解けちゃった! 再帰って, スゴくない? 7

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 /********************************************************** アルゴリズムとデータ構造 サンプルプログラム << 再帰の例 : Hilber 曲線 >> hilbert.c copyright (c) T.Mori <mori@forest.dnj.ynu.ac.jp> **********************************************************/ #include <stdio.h> #include <stdlib.h> #define H0 16 /* 画面の大きさ */ #include "plot.c" /* 簡易プロッタルーチン (H0 の値を使用する ) */ #define N 3 /* ヒルベルト曲線の位数 */ void pat_( int i, int h ); void pat_( int i, int h ); void pat_( int i, int h ); void pat_( int i, int h ); int main(void) int i, h, x0, y0; init_screen(); i=0; h = H0; x0 = h/2; y0 = x0; do i++; h /= 2; x0 += h/2; y0 -= h/2; set_pen(x0,y0); pat_(i,h); while (i!= N); print_screen(); return 0; /* パターン の描画 */ void pat_(int i, int h) if (i>0) pat_(i-1,h); move_pen(-h,0); pat_(i-1,h); move_pen(0,h); pat_(i-1,h); move_pen(h,0); pat_(i-1,h); /* パターン の描画 */ void pat_(int i, int h) if (i>0) pat_(i-1,h); move_pen(0,-h); y x 0 H0 0 H0 座標系 基本型分割法 基本型分割法 8

50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 pat_(i-1,h); move_pen(h,0); pat_(i-1,h); move_pen(0,h); pat_(i-1,h); /* パターン の描画 */ void pat_(int i, int h) if (i>0) pat_(i-1,h); move_pen(h,0); pat_(i-1,h); move_pen(0,-h); pat_(i-1,h); move_pen(-h,0); pat_(i-1,h); /* パターン の描画 */ void pat_(int i, int h) if (i>0) pat_(i-1,h); move_pen(0,h); pat_(i-1,h); move_pen(-h,0); pat_(i-1,h); move_pen(0,-h); pat_(i-1,h); 実行結果 基本型 基本型 分割法 分割法 9

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 /********************************************************** アルゴリズムとデータ構造 サンプルプログラム << 簡易プロッタルーチン >> plot.c copyright (c) T.Mori <mori@forest.dnj.ynu.ac.jp> **********************************************************/ /********************************************************** 使い方 画面は正方形 画面の一辺を H0 というマクロで定義する. 画面は以下の座標系. +------>x この関数はちょっと難しい ですから, 無理して理解し なくても大丈夫です. V y 2 次元配列 screen 使用できる関数 void init_screen(void) 画面を初期化する. void set_pen(int sx, int sy) ペンをアップし, ペンの位置を (sx,sy) に移動する. void move_pen(int dx, int dy) ペンをダウンさせて, ペンの位置を現在の座標から x 座標を dx, y 座標を dy だけ移動する. void print_screen(void) 画面を印刷する. **********************************************************/ /* 一つのマスからどの方向に線が出ているかの定義 */ #define UP 1 #define OWN 2 UP 0001(2 進数 ) #define RIGHT 4 OWN 0010(2 進数 ) #define LEFT 8 RIGHT 0100(2 進数 ) /* 画面データ */ LEFT 1000(2 進数 ) int screen[h0][h0]; /* ペンの座標 */ int x, y; 大域変数 /* 画面ならびにペン座標の初期化 */ void init_screen(void) int i, j; x = 0; y = 0; for( i=0; i<h0; i++ ) for( j=0; j<h0; j++ ) screen[i][j] = 0; ゼロ 0 が何もない状態を表しています. 10

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 /* ペン座標設定 */ void set_pen( int sx, int sy ) x = sx; y = sy; /* ペンを相対移動し, 描画する */ void move_pen( int dx, int dy ) int i, x_start, x_end, y_start, y_end; if ( dx!= 0 && dy!= 0 ) printf("plot Error n"); exit(1); 強制終了 if ( dx!= 0 ) if ( dx < 0 ) x_start = x + dx; x_end = x; else x_start = x; x_end = x + dx; for ( i=x_start+1; i<x_end; i++ ) screen[i][y] = RIGHT LEFT; screen[x_start][y] = RIGHT; screen[x_end][y] = LEFT; if ( dy!= 0 ) if ( dy < 0 ) y_start = y + dy; y_end = y; else y_start = y; y_end = y + dy; for ( i=y_start+1; i<y_end; i++ ) screen[x][i] = UP OWN; screen[x][y_start] = OWN; screen[x][y_end] = UP; x += dx; y += dy; この x と y は, あらゆる関数から参照することができる大域変数です. 本来なら, 大域変数はあまり使わない方が良いですが, ここではプログラムを分かり易くするために用いています. はビットごとの OR 演算子 screen[i][y] = RIGHT LEFT screen[i][y] = 1100 screen[i][y] = screen[i][y] 1100 これは,screen[i][y] で 1100 のビットが立っているビットを立てる処理を表しています. 以下同様です. UP 0001(2 進数 ) OWN 0010(2 進数 ) RIGHT 0100(2 進数 ) LEFT 1000(2 進数 ) 11

98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 /* 画面描画 */ void print_screen(void) int i,j; screen[j][i] のどのビットが立っているかで処理を分岐しています. 例えば, LEFT OWN は 1010 を表しています. その場合は 左方向, 下方向に線が出ている ですから, と表示するということになります. 以下同様です. for ( i=0; i<h0; i++) for ( j=0; j<h0; j++) switch(screen[j][i]) case UP: case OWN: case UP OWN: printf(" "); break; case RIGHT: case LEFT: case RIGHT LEFT: printf(" "); break; case LEFT OWN: printf(" "); break; case RIGHT OWN: printf(" "); break; case LEFT UP: printf(" "); break; case RIGHT UP: printf(" "); break; case LEFT RIGHT OWN: printf(" "); break; case LEFT UP OWN: printf(" "); break; case LEFT RIGHT UP: printf(" "); break; case RIGHT UP OWN: printf(" "); break; case LEFT RIGHT UP OWN: printf(" "); break; default: printf(" "); printf(" n"); UP 0001(2 進数 ) OWN 0010(2 進数 ) RIGHT 0100(2 進数 ) LEFT 1000(2 進数 ) 12