アルゴリズムと データ構造 第3回 基本的なデータ構造(2): 配列 1 前回の復習 アルゴリズムの計算量 最悪(最大)計算量 計算量の漸近的評価 (オーダ) 多項式時間アルゴリズム(polynomial time algorithm) 指数時間アルゴリズム(exponential time algorithm) 配列 ポインタの復習 2 演習問題の答え 第1問 次のような計算量T(n)について、そのオーダを求めなさい O(n3) T(n) = 1.5n2+0.6n3 + 8.3n (b) T(n) = 4logn + 8n O(n) (c) T(n) = 3n2 + 7nlog3n = 3n2 + 7n2log3 = (3+7log3) n2 (a) (d)T(n) = 2n + 3n5 O(2n) O(n2) 注意:2nのような「2」は定数倍ではない。nの 関数に『掛け算』されている『数』が無視の対 象 手順: (1)定数倍を無視 (2)最も大きくなるnの項だけを残す 3 演習問題の答え 第2問 計算量T(n)= 2n+1のとき、そのオーダは2nといえるか。また、 T(n)=22nのときはどうか示しなさい。 解答: ∵T(n) = 2n+1 = 2・2n ∴T(n) のオーダは2nと言える T(n)=22nのとき、定義を用いて証明する ①.この定義に従い、T(n)=22nがO(2n)であると仮定する。 ②.2つの正の定数n0とcが存在して、n≧n0なるすべてのnに対して、22n≦c2nが 成り立つ。 ③.この不等式の両辺を2nで割ると、2n≦cとなる。 ④.ここで、nが大きくなったとき、この式の左辺は無限大になるが、右辺は定数 である。 ⑤.これは、この不等式が成り立つことに矛盾している。 4 したがって、T(n)= 22nのときのオーダは2nとはいえない。 演習問題の答え 第2問 計算量T(n)= 2n+1のとき、そのオーダは2nといえるか。また、 T(n)=22nのときはどうか示しなさい。 解答:(解法2) 極限理論を用いて証明する T(n) lim = 𝑛→∞ G(n) 定数 T n のオーダはG n のオーダと等しい ∞ T n のオーダはG n のオーダより大きい 20n+1 T n のオーダはG n のオーダより小さい ∵ lim n =2 𝑛→∞ 2 ∴ T 𝑛 2=2n2n+1のオーダはO(2n) ∵ lim n =∞ といえる 𝑛→∞ 2 5 動的メモリ管理 今までのメモリを割り当てる方法 int a; →1個しか割り当てられない int a[10]; →あらかじめ割り当てる個数(たとえば10個)が決まってい ないとダメ 要らなくなったとき解放できない 動的なメモリ割り当て/解放 malloc(), calloc(,)関数 free()関数を使う 6 動的メモリ管理 動的メモリ管理とは プログラム実行中に、記憶域を必要な分確保 不要になった記憶域は開放 動的メモリ管理でできること プログラム開始後に配列領域の大きさを決定 関数内で新規作成したデータの返却 7 動的メモリ管理 記憶域の確保 • 必要な時に、必要な分だけメモリを割り当てる. • 割り当ての結果,空っぽの配列が生成される. • 書式:void *malloc(unsigned int size) 引数:割り当てるバイト数 返り値:割り当てた領域の先頭ポインタ(失敗すればNULL) • 例)ポインタpを先頭に100byte割り当てるときには? 任意の型 *p; //先頭ポインタp定義 p=malloc(100); //100byte割り当て 8 mallocの使い方の例(1) 念のためchar * 型にキャストする char *x; x=(char *) malloc(1000*sizeof(char)); 処理をする free(x); // 解放する 1000 byte分のメモリを確保する char は1バイトを取る ①②③④ … 1000 byte分のメモリを確保する →x[1000]が確保された! 9 補足: キャストとsizeof演算子 キャスト演算子 データ型を変換する操作 float x; 書式: (型)式 int y; 「式」で示すデータが「型」に変換される 型が違うものを代入するときなどに使用 y=(int) x; sizeof演算子 引数の型のサイズをbyte数で返す sizeof(int) = 4 sizeof(char) = 1 10 mallocの使い方の例(2) int * 型にキャストする int *y; y=(int *) malloc(1000*sizeof(int)); 処理をする 4000 byte分のメモリを確保する free(y); // 解放する int は4バイトを取る ① ② ③ … 4*1000=4000 byte分のメモリを確保する →y[1000]が確保された! 11 動的メモリ管理 記憶域の確保 calloc関数 void *calloc(size_t nmemb, size_t size) sizeで指定したバイト数を単位として、要素nmemb個の記憶域を 確保して返す 確保された記憶域は0初期化される 確保に失敗するとNULLが返される 12 動的メモリ管理 記憶域の開放 free関数 不要になったときメモリを解放し,他のプログラムで使 えるようにする. 書式: void free(void *ptr) 引数: 解放するメモリのポインタ 返り値: なし(void) 例)ポインタpから始まる,malloc/callocで割り当てした 領域を解放するには? free(p); //pから始まる領域解放 13 動的メモリ管理 動的配列の確保 char *str; str = calloc(100, sizeof(char)); scanf(“%s”, str); printf(“%s\”, str); free(str); ・ char型100個分の領域を確保 ・ 不要になったらfreeで開放するのを忘れずに 14 動的メモリ管理 動的配列の確保 int *make_array(int n) { return (calloc(n, sizeof(int))); } ・ n個の要素を持つint型配列を返す関数 ・ 確保に失敗した場合はNULLが返される ・ この関数を呼んだ方で、使用後freeを実行する必要あり 15 整数の動的生成 実行結果 *x = 57 16 配列の動的生成 実行例 入力 要素数:4 4個の整数を入力してください。 a[0]: 10 a[1]: 73 a[2]: 2 a[3]: -5 出力 各要素の値は以下のとおりです。 a[0] = 10 a[1] = 73 a[2] = 2 a[3] = -5 17 配列要素の最大値 要素3の配列の最大値 int a[3]; int max; max = a[0]; If (a[1] > max) max = a[1]; If (a[2] > max) max = a[2]; 18 配列要素の最大値 要素nの配列の最大値 int a[n]; int max; /* 便宜上の宣言例 */ max = a[0]; If (a[1] > max) max = a[1]; If (a[2] > max) max = a[2]; ・・・ If (a[n - 1] > max) max = a[n - 1]; 19 配列要素の最大値 要素nの配列の最大値 int a[n]; int max, i; /* 便宜上の宣言例 */ max = a[0]; for (i = 1; i < n; i++) If (a[i] > max) max = a[i]; 20 フローチャート 開始 a[0] → max 走査 i : 1, 1, n-1 Yes a[i] > max a[i] → max No 走査 終了 21 配列要素の最大値を求める関数 22 配列要素の最大値を求めるメイン処理 実行例 人数:5 5人の身長を入力してください。 height[0]: 172 入力 height[1]: 153 height[2]: 192 height[3]: 140 height[4]: 165 出力 最大値は192です。 23 配列要素の並びの反転 22 5 11 32 120 68 70 120 68 22 120 5 22 11 5 22 交換 70 5 11 32 n / 2回 交換 70 68 11 32 交換 70 68 120 32 24 配列要素の並びの反転 アルゴリズムの流れ 1. 2. 3. 先頭と最後尾を交換 それぞれ1つずつ内側を交換 以下中央に来るまで繰り返し for (i = 0; i < n / 2; i++) a[i] と a[n - i - 1] を交換 25 配列要素の並びの反転 2値の交換 作業用に同じ型の変数を介して交換 xとyを交換するとき、作業用変数tを用意した場合: 1. xの値をtに代入 2. yの値をxに代入 3. tの値をyに代入 26 配列要素の並びの反転 反転プログラム int i; for (i = 0; i < n / 2; i++) { int t = a[i]; a[i] = a[n - i - 1]; a[n - i - 1] = t; } 27 配列要素の並びの反転関数 28 配列要素の並びの反転メイン処理 実行例 入力 要素数:5 5個の整数を入力してください。 x[0]: 10 x[1]: 73 x[2]: 2 x[3]: -5 x[4]: 42 出力 配列の要素の並びを反転しま した。 x[0] = 42 x[1] = -5 x[2] = 2 x[3] = 73 29 x[4] = 10 基数変換 10進整数からn進整数へ 変換する数をnで割った剰余を求める 剰余を求めたら商に対して順次繰り返し 商が0になったら終了 上位桁 下位桁 2 10 6 9 1 1962 10 196 2 10 19 6 10 1 9 0 1 1962(10) 8 1962 16 1962 8 245 2 16 122 10 8 30 5 16 7 10 8 3 6 0 7 0 3 3652(8) 7AA(16) 30 基数変換関数 31 基数変換メイン処理 実行例 入力 10進数を基数変換します。 変換する非負の整数: 59 何進数に変換しますか (2-36): 2 出力 2進数では111011です。 入力 32 もう一度しますか(1---はい/0---いいえ): 0 まとめ 動的メモリ管理 配列の応用 整数の動的生成 配列要素の最大値を求める関数 配列要素の並びの反転 基数変換 予習: 次回は、多次元配列、構造体、配列によるリスト 33
© Copyright 2024 ExpyDoc