コンピュータ基礎演習 −アルゴリズムとデータ構造−

Post on 19-Mar-2016

59 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

コンピュータ基礎演習 −アルゴリズムとデータ構造−. アルゴリズムの設計と解析. アルゴリズムとは 問題を解くための 論理または手順 データ構造とは 問題を解くための情報をどのような形で 表現・記憶 するか プログラム データ構造を利用して,アルゴリズムを プログラミング言語で表現したもの. プログラミングとは. 問題分析 何をするプログラムを書くのか決める  (プログラム仕様の決定) どんなアルゴリズム,データ構造を使用すればよいかを選択 実際にプログラムを書く プログラムが正しく動くことを保証する (検証). この授業では, - PowerPoint PPT Presentation

TRANSCRIPT

コンピュータ基礎演習アルゴリズムとデータ構造− −

アルゴリズムの設計と解析 アルゴリズムとは

問題を解くための論理または手順 データ構造とは

問題を解くための情報をどのような形で表現・記憶するか

プログラム データ構造を利用して,アルゴリズムを

プログラミング言語で表現したもの

プログラミングとは1. 問題分析2. 何をするプログラムを書くのか決める  

(プログラム仕様の決定)3. どんなアルゴリズム,データ構造を使用す

ればよいかを選択4. 実際にプログラムを書く5. プログラムが正しく動くことを保証する 

(検証)

この授業では,適切なアルゴリズム,データ構造

を選ぶ能力を身に付ける.

良いアルゴリズムの条件 信頼性が高い

(精度の良い,正しい結果が得られる) 処理効率が良い(計算回数が少ない,処理速度が速い,

大量のメモリ領域を使わない) 一般性がある

(特定の問題だけでなく,他の問題にも適用できる) 拡張しやすい(仕様変更に対し簡単に修正が行える) わかりやすい

(誰が見ても理解できる.プログラムの保守がしやすい) 移植しやすい(他のシステムにも少ない労働で

稼働させることができる)

プログラミング 問題分析

与えられた問題の意味を正確に理解 目的 与えられるデータは何か 求めるべき結果は何か 要求される精度は 処理に与えられた計算量は

その他の要素 そのプログラムは何度ぐらい利用されるか

処理方法の決定 計算方法の選択

どの方法が与えられた問題の処理に適しているか(アルゴリズム+データ構造)

その方法により所望の精度は得られるか 計算量の制限は満たしているか

データの入力方法 データの種類,使用できる入力装置の種類に

応じて適当な方法を選ぶ キーボードからの直接入力 ディスクからのファイル読み込み

処理結果の出力方法 結果の利用方法,使用できる出力装置の種類

処理手順の記述 コーディング

文法的な誤り→言語処理プログラムによりこの時点で発見できる

プログラムの検査 論理的な誤り→事前条件,事後条件の検査

アルゴリズム設計段階での条件設定 中間処理の例外検出

プログラムの実行

事前条件と事後条件(1) 事前条件 (precondition)

プログラムが正しく動作するための前提条件 事後条件 (postcondition)

プログラムが動作した後に成立する条件 不変条件

プログラムが動作中に成立している条件

事前条件と事後条件(2)

プログラムの実行中

事前条件 事後条件不変条件

プログラムの起動 プログラムの終了

正しいプログラムとは:

事前条件が成立しているときに起動された場合に,実行中に不変条件が常に成立しており,かつ,終了後に事後条件が成立するプログラム

プログラムの検査 プログラム起動時に事前条件が成立し

ているか? プログラム実行中は不変条件が成立し

ているか? プログラム終了時に事後条件が成立し

ているか?

演習問題1)漸化式

n個の中からr個を選ぶ組み合わせの数 nCr を求める

a,b,c の中から2個選ぶ組み合わせは,ab,ac,bc の3通り

一般には, Crn = n!

r!(n – r)!

計算機でこの式を実行した場合,大きい n の値に対し n! がオーバーフローする危険性がある.

演習問題1)漸化式

例えば, C515 = 15!

5!(15 – 5)! = 130767436800120 × 3628800 = 3003

最終結果はオーバーフローしないが,分子では???

ヒント:  int は通常 232 (≒約 4,000,000,000)まで

問題を分析する 組み合わせは漸化式で表現できる

Crn = n – r + 1

r Cr – 1n

C0n = 1

自分自身 {nCr}を次数の低い自分自身 {nCr-1}で再帰的に定義

問題を分析する (2)

漸化式の表現方法

1) 繰り返しの利用関数呼び出しのオーバーヘッドが小さい複雑な再帰的定義を展開する場合,プログラムが複雑になる

2) 再帰呼び出しの利用  定義通りにプログラムを組みやすく保守しやすい メモリの使用効率が悪い

問題を分析する (3)

漸化式を繰り返しで表現する場合:

方針)  を初期値とし,それに係数     を   順次掛け合わせていく.   繰り返しの制御には r を利用する.    r を 1から始めて,繰り返し毎に +1 を加え,   指定した値になれば停止する.

C0n n – r + 1

r

Crn = 1 × n – 1 + 1

1 × n – 2 + 12 × ×

n – r + 1r C0n

C1n

問題を分析する (4)

事前条件

今までの議論が成立するために暗黙的に仮定していたこと

C32 ? C–13 ?例えば,こういう組み合わせの値は?

n ≥r≥0プログラムが正しく動作するためには

があらかじめ成立していなければならない

問題を分析する (5)

契約の概念

事前条件を満たした状態でプログラムが呼び出された場合,プログラムは事後条件を満たすことを保証する.

この場合の事後条件とは? Crn が正しく計算されること

繰り返しによる実装例#include <stdio.h>

int combination(int n,int r){

int i,p;p = 1;for (i = 1; i<=r; ++i) {

p *= (n-i+1);p /= i;

}return p;

}

int main(void){

int n,r;n = 5; r = 3;printf( "%dC%d=%d\n", n, r, combination(n,r) );return 0;

}

計算方法の選択方法,考え方 どの方法が与えられた問題の処理に適してい

るのか? アルゴリズム+データ構造

疑似コーディング(疑似プログラム) どのようなアルゴリズムを使えば良いか ごく大ざっぱなスケッチ,全体像を掴む 始めは自然言語(日本語等)で 徐々に事前条件,事後条件を明らかにしつつ,プ

ログラミング言語に置き換え→段階的詳細化

(Stepwise Refinement)

段階的詳細化 (Stepwise Refinement)

問題に対する適切な数学モデルが構築できればアルゴリズムはそのモデルを使って定式化できる

詳細化の過程で,どのようなデータが必要か?(事前条件)

そのデータに対してどのような操作を行うか?(事後条件)

データに加える操作が明らかになれば,それを効率良く行うアルゴリズムとデータ表現(データ構造)が決定される.

問題解決の過程

数学モデル

自然言語で記述したアルゴリズ

抽象データ型

疑似コーディング

データ構造

Cプログラム

問題の表現能力 大問題の記述量  小

問題の表現能力 小問題の記述量  大

疑似コーディング プログラミング言語と自然言語とを利用して,

設計の補助として作成するコード例えば,

日本語 疑似コーディング

C言語

XにYを代入 X ← Y X = Y;XとYは等価 X = Y (X == Y);XとYは等しくない X≠Y (X != Y);N回繰り返し for (i←1..N) for (i=1;i<=N; ++i)

データ型とデータ構造 データ型 (type of data)

ある特定言語のデータの型 例えば, int, char など

データ構造 (data structure) ある数学モデルを実装するための

データの集まり いろいろなデータ型をもつデータの集ま

C言語のデータ型 基本型

文字型,整数型,実数型 構造型

配列,構造体,共用体 ポインタ型

データ構造 ある数学モデルを実装するための様々なデー

タ型を持つデータの集まり リスト( list ) 待ち行列( queue ) スタック( stack) 木( tree ) ハッシュ表( hash table ) グラフ( graph)

これらのデータ構造は,配列型のデータ領域と格納場所を示す整数型カウンタで実装できる.もちろん,ポインタと構造体を使っても実装できる.

抽象データ型(Abstract Data Type)=データ構造+手続き

コンピュータ基礎演習 ーC言語の復習:配列ー

配列と構造体 配列 (array)

同じデータ型を持った要素を集めたもの 配列の要素は,添字(インデックス ,index)により参照可能

構造体 (structure) 異なるデータ型を意味的にひとまとまりに

したもの

配列(C言語) データ型 配列名 [ 要素数 ];

指定されたデータ型が要素数分だけ連続した格納領域の宣言

例) int data[4];

0 〜 3番までの 4 個の int 領域が確保される.

data[0] data[1] data[2] data[3]int int int int

配列の初期化 データ型 配列名 [要素数 ] = {定数,定数 ,…,定数 }

例)int data[4] = { 7, 4, 3, 10 };

演習問題2 例えば,最大値を求めるには

最大値の条件: 他のすべてのデータより大きい(事後条件)

すべてのデータと比較が必要 ∃m∀x [m ≥ x]

1) m←data[0]2) for (I ← 1 .. N-1)

if (!(m >= data[I])) m ← data[I]

最大値の条件 最大値になるよう修正論理否定

疑似言語記述:繰り返し

配列データの最大値計算

#include <stdio.h>

int main(void){

int data[10] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };int i, m, n = 10;

m = data[0];for (i=1; i<n; ++i)

if (m < data[i]) m = data[i];printf( "maximum = %d¥n", m );return 0;

}

配列の要素数疑似言語を C言語に変換した部分

課題2 解答例#include <stdio.h>

double average(int cs[],int n){

int i; double sum = 0;/* 合計値の計算 */for (i=0; i<n; ++i)

sum += cs[i];return sum/n; /* 合計 /要素数 */

}

int main(void){

/* データの初期化 */int cs[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };/* 平均を計算する関数の呼出と平均値の出力 */printf( "average = %lf¥n", average(cs,10) );

}

配列と次元( 2 次元配列, 3次元配列) 次元とは,配列に含まれる要素を識別

するために必要な添え字の個数のこと

データ型 配列名 [要素数 ] ; 1次元配列データ型 配列名 [要素数 ][要素数 ]     ; 2次元配列データ型 配列名 [要素数 ][要素数 ][要素数 ] ; 3次元配列

例) 3人で 4回トランプをした場合の得点表

整数型2次元配列で表現 int score[3][4];

2次元配列

(0,0) (0,1) (0,2) (0,3)

(1,0) (1,1) (1,2) (1,3)

(2,0) (2,1) (2,2) (2,3)

列 0    1   2    3

012

列にゲームの回数,行にプレイヤー

メモリ(計算機)の中ではどんな形で格納?

int score[3][4];[0][0] [0][1] [0][2] [0][3] [1][0] … [2][2] [2][3]

低位アドレス 高位アドレス

2次元配列の初期値設定データ型 配列 [要素数 ][要素数 ] =

{ {定数,定数,… , 定数 }, {定数,定数 , … , 定数 },

・・・・・・  {定数,定数,… , 定数 } };

int score[3][4] = {{ 7, 45, 3, 10 },{ 11, -3, 8, 17 },{ 90, 41, 32, 100 } };

[0][0] [0][1] [0][2] [0][3] [1][0] … [2][2] [2][3]

7 45 3 10 11 … 32 100

演習問題3 4行4列のデータを入力し,縦計,横

計,総合計を求め,表形式で出力せよ

○問題の分析 縦計,横計のデータ領域も必要であるから, 5行5列の配列を用意する.

基本方針) 1)16個のデータを配列に入力 2)縦計,横計,総合計を求める 3)結果の表形式での表示

☆演習課題2の応用,各要素に対して繰り返し (for 文で ) 演算を行う

疑似コーディング 16個のデータを配列に入力

4行4列のデータ入力であり,各行は同じ形式としてよいから,まず1行分の入力を4回行うと考える

1-1) for (i ← 0 .. 3)    1-2) 1行分( data[i])を入力

1行には4列分のデータがある 故に data[i][0], data[i][1], data[i][2], data[i][3] にデータが格納されるようにする

疑似コーディング(2) 1行分を入力する

行の場合と同様に列も4回繰り返し

1-1) for (i ← 0 .. 3)    1-2) for (j ← 0 .. 3)

1-3) 1つのデータ (data[i][j]) を入力する

1-1) for (i ← 0 .. 3)    1-2) 1行分( data[i])を入力

繰り返し回数を覚えている変数は違うものを利用

疑似コーディング (3) 1つのデータを入力する

Cの標準ライブラリ scanf 関数を利用する

int i;float f;double d;

scanf( "%d", &i ); /* 変数 i に整数値を入力する */scanf( "%f", &f ); /* 変数 f に単精度実数値を入力する */scanf( "%lf", &d); /* 変数 d に倍精度実数値を入力する */

疑似コーディング (4) 縦計,横計,総合計を求める

<縦計の計算>

<横計の計算> 縦計の場合と行と列を入れ替える

1-1) for (j ← 0 .. 3) 1-2) data[4][j] ← 0 1-3) for (i ← 0 .. 3) 1-4) data[4][j] += data[i][j]

疑似コーディング (5) < 総合計の計算>

縦計か横計が得られれば計算できる. 事後条件

総合計=Σ縦計=Σ横計 縦計の総和と,横計の総和を求め比較 正しい総合計ならば data[4][4] に格納

1-1) tate ← 0, yoko ← 01-2) for (i ← 0 .. 3) 1-3) tate += data[4][i], yoko += data[i][4]1-4) if (tate = yoko) data[4][4] ← tate

もちろん tate = yoko なので yoko でもよい

事後条件を満たさない場合 プログラムが動作終了した時に,事後

条件を満たさないプログラムは,欠陥品である

責任の所在 事前条件が満たされていない

プログラムを起動した側(ユーザ)の責任 事前条件は満たされている

プログラム側の責任

事前条件 演習課題3では明確にしていない

設計者が設定する必要がある データの精度,有効桁数など

例えば,以下のような条件のプログラム事前条件:データ入力の桁数1桁から3桁までの正の整数     データは16個なければならない事後条件:総合計= Σ縦計= Σ横計

コンピュータ基礎演習 ーC言語復習:関数ー

岩井 儀雄iwai@sys.es.osaka-u.ac.jp

サブプログラム 大きなプログラムでは,扱う値は異なっても,同一

の処理が異なる位置に現れることがある. このような場合,同一の処理を別途記述し,元のプ

ログラムからその処理部分を呼び出すようにできると便利

独立した処理部分:サブプログラム,モジュール         サブルーチン,関数などと呼ばれる

Cプログラムの特徴 関数の集合体

言語としてはシンプルな部類 main関数, printf 関数 , scanf 関数など

返値のデータ型 関数名(仮引数の型と変数宣言の並び){  内部変数の宣言;  実行部分(処理内容);}

関数の定義

仮引数:呼び出し側から与えられるデータを受け取る変数

main関数 プログラムが起動した時に最初に呼ばれる関数 通常,プログラムはオペレーティングシステムから起動され

る. main関数の返値は起動したオペレーティングシステムに渡さ

れる.

int main(int argc,char *argv[]) {

 処理内容;

  return 0; →  プログラムが正常終了した時は }    0 を戻す

OSから渡されるデータ

例)関数         を求める

F(x) = 2x2 + 6x + 4

double F(double x) →  関数 Fの宣言,仮引数 xのデータ型宣言{ →  関数 Fの定義開始 double f; →  倍精度実数型変数 fの宣言 f = 2*x*x+6*x+4; →  関数 Fの計算 return f; →  関数 Fの計算結果を呼び出し側に戻す} →  関数 Fの定義終了

関数(サブプログラム等を含む)の利点: ・関数の外部仕様(事前条件,事後条件)だけを知っておけば良い ・関数の内部仕様(実装方法や不変条件)は知らなくて良い

例えば: sin関数や cos関数などの実装方法を知っている人は?

関数の呼び出し方

関数名(実引数の並び);

実引数   :呼び出し側(例えば,main関数)で関数に       与えたデータのこと.実引数の並び:実引数をカンマ(,)で区切ったもの

例: F(x,4);

関数の返値 呼び出した関数から戻ってくる時に値を返すことが

できる.

return 式 ;値を返さない場合(例えば, void型関数)  「式」は省略可能( return自体も省略可能)

引数と局所変数 関数を呼び出す側→実引数 呼び出される関数→仮引数

実引数,仮引数との間では 引数の個数 並びの順序 データ型   一致しなければならい

実引数→式であっても良い 仮引数→変数 仮引数と実引数の変数名は一致する必要はない

(データ型は一致する必要がある)

引数と局所変数(2) 変数にはその名前が有効な範囲 (scope)

が存在する 変数の局所性はプログラムの可読性を

高めるために利用する

名前の有効範囲 (scope)#include <stdio.h>int F( /* 関数 Fの宣言,これ以降 Fは有効 */ int x, int y) /* 仮引数の宣言,関数 F 内で有効 */{

int i, j, f = 0; /* 整数型変数の宣言 */for (i = 0; i<y; ++i) {

int temp = 0; /* 整数型変数の宣言 */for (j = 0; j<x; ++j)

temp += j;f += temp;

}return f;

}int main(void){

int i = 10, j = 4;

printf( "F(%d,%d) = %d\n", i, j, F(i,j) );printf( "F(%d,%d) = %d\n", 3, i+j, F(3, i+j ) );

}

局所変数

局所変数と大域変数(C言語) 局所変数

関数内部で定義され,その関数でのみ使用可能 複数の関数が同一名称の局所変数を利用しても衝突しない

大域変数 関数外部で定義され,どの関数からでも

使用できる プログラム中では同一名称の大域変数は

一つしかない

静的変数と自動変数 静的変数

プログラム実行中に常に存在して値を保持できる

自動変数 自動変数が宣言されている関数やブロック内に制御が移った時にのみ存在する

内部リンケージと外部リンケージ

リンケージ (linkage) リンカ (linker) による名前解決の範囲を示す

内部リンケージ 翻訳単位の中でのみ有効 翻訳単位の中では同一名称は同一物をさす

外部リンケージ 翻訳単位を超えてプログラム全体で名前を共有できる

C言語の記憶クラスとリンケージ,静的変数の関係

static auto extern 省略時

局所変数内部静的

内部自動

外部静的

内部自動

大域変数内部静的

外部静的

外部静的

関数 内部 外部 外部

内部リンケージ 外部リンケージ

定義したことにな

宣言のみ定義ではない

関数(サブルーチン)間のデータのやり取り 値渡し (Call by Value)

ほとんどの言語で利用できる 実引数を評価して,その値を仮引数に代入する

参照渡し (Call by Reference) C++, Pascal など 実引数の参照を渡し,仮引数を参照している

実体に束縛する 名前渡し (Call by Name)

ALGOLなど 実引数の名前が仮引数の名前に置き換えられる

関数間のデータのやり取り(C言語) C言語では値渡し (Call by Value) しか

できない 大域変数を利用する方法もある ポインタ型を利用した方法もある

関数間のデータのやり取り(C言語)(2) 大域変数の利用

プログラム全体で存在し,データをやり取りする必要がある場合に利用

int g1; /* 大域変数の宣言 */int F(int x) { return x+g1; /* 関数内での大域変数の利用 */}int main(void) { g1 = 10; printf( "F(%d) = %d, g1 = %d\n", 20, F(20), g1 ); return 0;}

関数間のデータのやり取り(C言語)(3) 大域変数の利用

大域変数を利用する関数が多くなると,保守が難しくなる.

また,可読性も悪くなる 他の方法で代替できる時には,大域変数は

利用しないほうが良い

関数間のデータのやり取り(C言語)(4)

ポインタ型の利用 実引数の値を書き換えたいとき

値渡しでは実引数の値はコピーされるので変更できない. 変更したい実引数のポインタを渡す

構造体をやり取りする時に計算効率を優先したいとき 構造体を受け渡しするときには,「浅いコピー」が自動的に起きる 自動的なコピーを抑えたいとき

コンピュータ基礎演習 ーファイルー

ファイル (FILE) 抽象データ型 (Abstract Data Type) のひ

とつ

読込ヘッド書込ヘッド

ストリーム

ファイル名(filename)

ファイル (FILE) ADT FILE に可能な操作

ファイルをセットする (Set) ファイルを外す (Unset) 頭出し( Rewind) 読み込み (Read/Get) 書き込み (Write/Put) 現在のヘッド位置を知る (Tell) ヘッド移動 (Seek)

ランダムアクセス可能なファイルのみ

C言語の FILE FILEをデータ型としては持っていない 代わりに ADTの FILE を提供するライブラリがある

( stdio.h) fopen   ファイルをセットする関数 fclose    ファイルを外す関数 rewind 巻き戻し(ファイル先頭へ移動) fread/getc データの読み込み関数 fwrite/putc データの書き込み関数 ftell ヘッド位置を知る関数 fseek ヘッドを移動する関数

ファイル操作(C言語) ファイルは,最初にファイル名を指定し, fo

pen 関数を呼び出すことでファイルをセットしないと使えない.

セットすると, fread/fwrite/fget/fput で読み書きすることができる

ファイルは,使い終わったら fclose関数を呼び出してファイルを外す. ファイルは計算機資源を消費するので使い終わっ

たら速やかに外す

ファイル入出力例#include <stdio.h> /* FILE を利用するために必要 */

int main(void) {FILE *fp; /* FILE * 型の変数を宣言 */int c;

fp = fopen( “DataFile”, “r” ); /* “DataFile”を読み込み用 (“r”) にオープン */if (fp == NULL) { /* オープンできないときは NULL が返る */

printf( "Can't open DataFile!\n" );exit(1);

}while ((c = getc(fp)) != EOF) /* 1文字読み込む. EOFでなければループ */

print( “%c”, c ); /* 画面に1文字出力 */fclose( fp ); /* 使い終わったらクローズする */return 0;

}

top related