ポインタを使った配列要素の交換


整数型配列aおよびbが定義されているとする. aとbの全要素を交換するとき,
   int temp, i;
   
   for ( i = 0; i < num_of_elements; i++ ){
      temp = a[ i ];
      a[ i ] = b[ i ];
      b[ i ] = temp;
   }
などと書くのはあまりに効率が悪い. こういうときはaおよびbの先頭要素へのポインタpaおよびpbを用意しておき, ポインタ同士を交換すればよい. 要素へのアクセスもポインタを用いる.
   int *pa, *pb, *p;
   
   pa = a; pb = b;
   p = pa; pa = pb; pb = p;
以下のコードは要素数が10000の整数型配列aおよびbの要素を10000回交換し, その都度全要素の和を求めるものである. ポインタの交換ではなく,要素を直接交換している.
#include <stdio.h>
#include <windows.h>

#define num_of_elements 10000

int main(){
  
    int a[ num_of_elements ], b[ num_of_elements ], temp;
    int sum_a, sum_b, i, n;
    DWORD started, terminated;

    started = GetCurrentTime(); 

   for ( i = 0; i < num_of_elements; i++ ){
        a[ i ] = i + 1;
        b[ i ] = ( i + 1 ) * 2;
    }
    
    for ( n = 1; n <= 10000; n++ ){
       for ( i = 0; i < num_of_elements; i++ ){
           temp = a[ i ];
           a[ i ] = b[ i ];
           b[ i ] = temp;
       }
       for ( i = 0, sum_a = 0, sum_b = 0; i < num_of_elements; i++ ){
           sum_a += a[ i ];
           sum_b += b[ i ];
       }
    }

    terminated = GetCurrentTime();
    printf( " total %10.3f seconds\n", ( terminated - started ) * 1e-3 );
    return 0;
}
このコードをVisual C/C++ 5.0でコンパイルし, PentiumIII 600MHzのbushで実行してみた. 3回実行して,それぞれに要した時間は5.117秒,5.097秒,5.108秒であった.
次に,ポインタを交換するようにコードを書き直す.
#include <stdio.h>
#include <windows.h>

#define num_of_elements 10000

int main(){
  
    int a[ num_of_elements ], b[ num_of_elements ], temp, *pa, *pb, *p;
    int sum_a, sum_b, i, n;
    DWORD started, terminated;

    started = GetCurrentTime(); 

   for ( i = 0; i < num_of_elements; i++ ){
        a[ i ] = i + 1;
        b[ i ] = ( i + 1 ) * 2;
    }
    
    pa = a; pb = b;
    for ( n = 1; n <= 10000; n++ ){
       p = pa; pa = pb; pb = p;
       for ( i = 0, sum_a = 0, sum_b = 0; i < num_of_elements; i++ ){
           sum_a += pa[ i ];
           sum_b += pb[ i ];
       }
    }

    terminated = GetCurrentTime();
    printf( " total %10.3f seconds\n", ( terminated - started ) * 1e-3 );
    return 0;
}
こちらも3回実行し,それぞれに要した時間は2.174秒,2.183秒,2.193秒であった. ポインタの交換にかかる時間は無視できるから,あとコードの実行時間は 配列aおよびbの初期化と和の計算に要した時間である. この時間ははじめのコードでも同じはずだから, 全要素の直接交換からポインタを使った間接交換に 置き換えたことにより,実行時間を約60%も短くできたことになる.

ここに置いてある文書に載せた非定常熱伝達のコードは 配列要素を直接交換している. ポインタの交換に置き換えた修正版を以下に示しておく.

#include <stdio.h>
#include <math.h>

#define NUM_STEPS 100
#define INIT_TEMP 1000

int main(){

    double temp_a[ NUM_STEPS ], *pa, temp_b[ NUM_STEPS ], *pb, *p;
    double alpha, time, x_step, time_step;
    int n, i;

    alpha = 6.6; 
    x_step = 1e1 / NUM_STEPS;
    time_step = pow( x_step, 2 ) / 2e0 / alpha * 3.6e3;

    pa = temp_a;
    pb = temp_b;
    time = 0;
    for ( i = 0; i < NUM_STEPS; i++ ){
        if ( i == 0 ){
            pa[ i ] = 0;
            pb[ i ] = 0;
        }
        else {
            pa[ i ] = INIT_TEMP;
            pb[ i ] = INIT_TEMP;
        }
    }

    n = 1;
    while ( pa[ 10 ] >= INIT_TEMP / 2 ){
        time = time_step * n;
        for ( i = 0; i < NUM_STEPS; i++ ){
            switch( i ){
            case 0:
                pa[ i ] = 0;
                break;
            case NUM_STEPS - 1:
                pa[ i ] = INIT_TEMP;
                break;
            default:
                pa[ i ] = ( pb[ i - 1 ] + pb[ i + 1 ] ) / 2e0;
            }
        }
        printf( "%d  %10.3f  %10.3f\n", n, time, pa[ 10 ] );
        p = pb; pb = pa; pa = p;
        n++;
    }

    return 0;

}


お問い合わせはメールにて: akasaka@klc.ac.jp

戻る
SEO [PR] 爆速!無料ブログ 無料ホームページ開設 無料ライブ放送