690 likes | 919 Views
コンピュータ基礎演習 −アルゴリズムとデータ構造−. アルゴリズムの設計と解析. アルゴリズムとは 問題を解くための 論理または手順 データ構造とは 問題を解くための情報をどのような形で 表現・記憶 するか プログラム データ構造を利用して,アルゴリズムを プログラミング言語で表現したもの. プログラミングとは. 問題分析 何をするプログラムを書くのか決める (プログラム仕様の決定) どんなアルゴリズム,データ構造を使用すればよいかを選択 実際にプログラムを書く プログラムが正しく動くことを保証する (検証). この授業では,
E N D
コンピュータ基礎演習−アルゴリズムとデータ構造−コンピュータ基礎演習−アルゴリズムとデータ構造−
アルゴリズムの設計と解析 • アルゴリズムとは • 問題を解くための論理または手順 • データ構造とは • 問題を解くための情報をどのような形で表現・記憶するか • プログラム • データ構造を利用して,アルゴリズムをプログラミング言語で表現したもの
プログラミングとは • 問題分析 • 何をするプログラムを書くのか決める (プログラム仕様の決定) • どんなアルゴリズム,データ構造を使用すればよいかを選択 • 実際にプログラムを書く • プログラムが正しく動くことを保証する (検証) この授業では, 適切なアルゴリズム,データ構造を 選ぶ能力を身に付ける.
良いアルゴリズムの条件 • 信頼性が高い(精度の良い,正しい結果が得られる) • 処理効率が良い(計算回数が少ない,処理速度が速い,大量のメモリ領域を使わない) • 一般性がある(特定の問題だけでなく,他の問題にも適用できる) • 拡張しやすい(仕様変更に対し簡単に修正が行える) • わかりやすい(誰が見ても理解できる.プログラムの保守がしやすい) • 移植しやすい(他のシステムにも少ない労働で稼働させることができる)
プログラミング • 問題分析 • 与えられた問題の意味を正確に理解 • 目的 • 与えられるデータは何か • 求めるべき結果は何か • 要求される精度は • 処理に与えられた計算量は • その他の要素 • そのプログラムは何度ぐらい利用されるか
処理方法の決定 • 計算方法の選択 • どの方法が与えられた問題の処理に適しているか(アルゴリズム+データ構造) • その方法により所望の精度は得られるか • 計算量の制限は満たしているか • データの入力方法 • データの種類,使用できる入力装置の種類に応じて適当な方法を選ぶ • キーボードからの直接入力 • ディスクからのファイル読み込み • 処理結果の出力方法 • 結果の利用方法,使用できる出力装置の種類
処理手順の記述 • コーディング • 文法的な誤り→言語処理プログラムによりこの時点で発見できる • プログラムの検査 • 論理的な誤り→事前条件,事後条件の検査 • アルゴリズム設計段階での条件設定 • 中間処理の例外検出 • プログラムの実行
事前条件と事後条件(1) • 事前条件 (precondition) • プログラムが正しく動作するための前提条件 • 事後条件(postcondition) • プログラムが動作した後に成立する条件 • 不変条件 • プログラムが動作中に成立している条件
事前条件と事後条件(2) プログラムの起動 プログラムの終了 プログラムの実行中 事前条件 不変条件 事後条件 正しいプログラムとは: 事前条件が成立しているときに起動された場合に, 実行中に不変条件が常に成立しており,かつ, 終了後に事後条件が成立するプログラム
プログラムの検査 • プログラム起動時に事前条件が成立しているか? • プログラム実行中は不変条件が成立しているか? • プログラム終了時に事後条件が成立しているか?
演習問題1)漸化式 n個の中からr個を選ぶ組み合わせの数 nCr を求める a,b,c の中から2個選ぶ組み合わせは, ab,ac,bc の3通り 一般には, 計算機でこの式を実行した場合,大きい n の値に対しn! がオーバーフローする危険性がある.
演習問題1)漸化式 例えば, 最終結果はオーバーフローしないが,分子では??? ヒント: int は通常 232(≒約4,000,000,000)まで
問題を分析する • 組み合わせは漸化式で表現できる 自分自身{nCr}を次数の低い自分自身{nCr-1}で 再帰的に定義
問題を分析する(2) 漸化式の表現方法 • 繰り返しの利用 • 関数呼び出しのオーバーヘッドが小さい • 複雑な再帰的定義を展開する場合, • プログラムが複雑になる • 2) 再帰呼び出しの利用 • 定義通りにプログラムを組みやすく保守しやすい • メモリの使用効率が悪い
問題を分析する(3) 漸化式を繰り返しで表現する場合: 方針) を初期値とし,それに係数 を 順次掛け合わせていく. 繰り返しの制御には r を利用する. r を1から始めて,繰り返し毎に +1 を加え, 指定した値になれば停止する.
プログラムが正しく動作するためには があらかじめ成立していなければならない 問題を分析する(4) 事前条件 今までの議論が成立するために暗黙的に仮定していたこと 例えば,こういう組み合わせの値は?
問題を分析する(5) 契約の概念 事前条件を満たした状態でプログラムが呼び出された場合, プログラムは事後条件を満たすことを保証する. この場合の事後条件とは? が正しく計算されること
繰り返しによる実装例 #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) 問題に対する適切な数学モデルが構築できれば アルゴリズムはそのモデルを使って定式化できる 詳細化の過程で,どのようなデータが必要か?(事前条件) そのデータに対してどのような操作を行うか?(事後条件) データに加える操作が明らかになれば,それを効率良く行う アルゴリズムとデータ表現(データ構造)が決定される.
問題解決の過程 問題の表現能力 大 問題の記述量 小 問題の表現能力 小 問題の記述量 大
疑似コーディング • プログラミング言語と自然言語とを利用して,設計の補助として作成するコード 例えば,
データ型とデータ構造 • データ型(type of data) • ある特定言語のデータの型 • 例えば,int, char など • データ構造(data structure) • ある数学モデルを実装するためのデータの集まり • いろいろなデータ型をもつデータの集まり
C言語のデータ型 • 基本型 • 文字型,整数型,実数型 • 構造型 • 配列,構造体,共用体 • ポインタ型
データ構造 • ある数学モデルを実装するための様々なデータ型を持つデータの集まり • リスト(list) • 待ち行列(queue) • スタック(stack) • 木(tree) • ハッシュ表(hash table) • グラフ(graph) 抽象データ型 (Abstract Data Type) =データ構造+手続き これらのデータ構造は,配列型のデータ領域と格納場所を 示す整数型カウンタで実装できる. もちろん,ポインタと構造体を使っても実装できる.
コンピュータ基礎演習 ーC言語の復習:配列ーコンピュータ基礎演習 ーC言語の復習:配列ー
配列と構造体 • 配列(array) • 同じデータ型を持った要素を集めたもの • 配列の要素は,添字(インデックス,index)により参照可能 • 構造体(structure) • 異なるデータ型を意味的にひとまとまりにしたもの
配列(C言語) • データ型 配列名 [ 要素数 ]; • 指定されたデータ型が要素数分だけ連続した格納領域の宣言 例)int data[4]; 0〜3番までの4個のint 領域が確保される.
配列の初期化 • データ型 配列名[要素数] = {定数,定数,…,定数} 例) int data[4] = { 7, 4, 3, 10 };
演習問題2 • 例えば,最大値を求めるには • 最大値の条件: • 他のすべてのデータより大きい(事後条件) • すべてのデータと比較が必要 疑似言語記述: • m←data[0] • 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回トランプをした場合の得点表 int score[3][4]; 整数型2次元配列で表現
2次元配列 列 0 1 2 3 行 0 1 2 列にゲームの回数,行にプレイヤー メモリ(計算機)の中ではどんな形で格納? int score[3][4]; 低位アドレス 高位アドレス
2次元配列の初期値設定 データ型 配列[要素数][要素数] = { {定数,定数,… , 定数}, {定数,定数, … , 定数}, ・・・・・・ {定数,定数,… , 定数} }; int score[3][4] = { { 7, 45, 3, 10 }, { 11, -3, 8, 17 }, { 90, 41, 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)1行分(data[i])を入力 繰り返し回数を覚えている 変数は違うものを利用 1-1) for (i ← 0 .. 3) 1-2) for (j ← 0 .. 3) 1-3) 1つのデータ(data[i][j])を入力する
疑似コーディング(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 ← 0 1-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言語復習:関数ーコンピュータ基礎演習 ーC言語復習:関数ー 岩井 儀雄 iwai@sys.es.osaka-u.ac.jp
サブプログラム • 大きなプログラムでは,扱う値は異なっても,同一の処理が異なる位置に現れることがある. • このような場合,同一の処理を別途記述し,元のプログラムからその処理部分を呼び出すようにできると便利 独立した処理部分:サブプログラム,モジュール サブルーチン,関数などと呼ばれる
Cプログラムの特徴 • 関数の集合体 • 言語としてはシンプルな部類 • main関数,printf関数, scanf関数など 返値のデータ型 関数名(仮引数の型と変数宣言の並び) { 内部変数の宣言; 実行部分(処理内容); } 関数の定義 仮引数:呼び出し側から与えられるデータを受け取る変数
main関数 • プログラムが起動した時に最初に呼ばれる関数 • 通常,プログラムはオペレーティングシステムから起動される. • main関数の返値は起動したオペレーティングシステムに渡される. int main(int argc,char *argv[]) { 処理内容; return 0; → プログラムが正常終了した時は } 0 を戻す OSから渡されるデータ
例)関数 を求める 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自体も省略可能)