2016-10-03 4 views
0

は、次のコードを考えてみましょう:再帰メモリを効率的かつ高速に実行する際にグローバル変数を宣言しますか?

int main() { 
    int ar[100]={0}; 
    int n = 100; 
    recurFun(ar, n); 
    return 0; 
} 

void recurFun(const int ar[], int n) { 
    if(some condition) { 
    //some code here to manipulate ar[]... 
    return ; 
    } 
    int i; 
    //some code to manipulate i 
    recurFun(ar, i) 
} 

私は再帰関数は独自の変数、それは自分自身を呼び出すたびに行うことを聞いて、ので、私はarが何度も作成され、メモリ使用量の多くを要するかもしれない期待します、右?

私は以下のように、グローバルな配列としてarを宣言した場合:これは、より多くのメモリ効率的なのでしょう

int ar[100]={0}; 

int main() { 
    int n = 100; 
    recurFun(n); 
    return 0; 
} 

void recurFun(int n) { 
    if(some condition) { 
    //some code here to manipulate ar[]... 
    return ; 
    } 
    int i; 
    //some code to manipulate i 
    recurFun(i) 
} 

私は、再帰関数がグローバル変数を複製する理由はないと思います。しかし、は、多くの再帰関数が同じ配列を訪問しているため、これは遅くなります。したがって、オーバーヘッドが発生します。

+0

生の配列は値渡しできません。仮引数の宣言 'const int ar []'は 'int const * ar'の記述と同じです。ポインタだけが渡されます。 –

+0

少しでもOT:あなたの関数は[tail-recursive](https://en.wikipedia.org/wiki/Tail_call)なので、良いコンパイラの最適化があれば、本当の再帰が起こることはないでしょう。コピー(ポインタまたはiの場合でも)。 – Holt

答えて

3

const int ar[]は配列をコピーしません。配列を最初の要素へのポインタに崩壊させます。

あなたのグローバルアレイソリューションは、このポインタをスタック変数に渡さないのでメモリ効率が少し向上しますが、問題はありません。スタック領域は、オーバーフローするまでフリーであり、呼び出しごとに1つの余分なポインタを使用するかどうかは、スタックのオーバーフローの違いであってはなりません。

+0

2つのアプローチの効率を測定しましたか? – juanchopanza

0

私は、再帰関数がそれ自身を呼び出すたびに独自の変数を作成すると聞いていました。したがって、arは何度も作成され、多くのメモリ使用量がかかるでしょうか?

これは間違っています。再帰関数を呼び出すたびに、その関数の新しい変数localが使用されます。これは、グローバルデータとは関係ありません。したがって、再帰関数が呼び出されるたびにarは作成されません。

0

したがって、arは何度も作成され、多くのメモリ使用量がかかると思われます。

いいえ、それは当てはまりません。

recurFunを呼び出すと、配列の最初の要素へのポインタのみが関数に渡されます。あなたはあなたのように配列をrecurFunに渡すことでパフォーマンスの違いは見られません。

0

罰金はありません。

全体の配列自体は(ポインタ)にコピーされていない、とスタックがあるため、他の私は、私が説明するために、この質問には、もう少しを加えるかもしれないと思っなどのパラメータ

0

とどのようで、とにかくサイズを変更する必要がありますメモリが割り当てられます。

int main() { int ar[100]={0}; recurFun(ar, 100); } 
void recurFun(const int ar[], int n) 

これは、実行時に、あなたの配列を割り当てスタックします、とrecurFunにすべての再帰呼び出しのために、それは最悪の場合には(ポインタとint型をスタックに割り当てます!一般的な場合は、おそらくその末尾再帰が可能ですスタックを再利用することができます)。

int ar[100]={0}; 
int main() { recurFun(ar, 100); } 
void recurFun(int n) 

これは、データ・セグメントに、起動時にあなたの配列を割り当てます、そしてrecurFunにすべての再帰呼び出しのためには、スタックに割り当てますint型(最悪の場合に!上記と同じ)。リンカの設定に応じて、これへのアクセスは間接的なテーブルを経由するため、使用するたびに2つのポインタアクセスが必要です。

int main() { int ar[100]= new int[100]; recurFun(ar, 100); } 
void recurFun(const int ar[], int n) 

これは、動的に動的に割り当てられたメモリ・セグメントで実行時に、あなたの配列を割り当てます、そしてrecurFunにすべての再帰呼び出しのために、それは最悪の場合には(ポインタとint型をスタックに割り当てます!同上)。

アレイが非常に大きい(> 100kb)場合を除き、最初の方法が好ましい。

関連する問題