2013-08-11 32 views
6

配列の1秒おき(一般的にはN個)の要素を取得し、次に単純なforループを得るより効率的な方法がありますか?たとえば、汎用アルゴリズムを使用してですか?C++の配列のn個の要素

#include<iostream> 
using namespace std; 

int main() 
{ 
    const int a_size = 6, b_size = 3; 
    int a[a_size] = {1, 3, 6, 3, 2, 7}; 
    int b[b_size]; 
    int bx = 0; 
    for (int ax = 0; ax < a_size; ++ax) 
    { 
     if (ax % 2 == 0) 
      b[bx++] = a[ax]; 
    } 
} 
+6

: 'のために(int型AX = 0; AX + = 2; AX vdenotaris

+0

あなたの例では、bの奇数要素は初期化されていない値であることに注意してください。 – kfsone

+0

これらはありません(コピーは 'bx 'によって追跡されます)。しかし、 'b_size'がステップ(この例では2)に対して誤った値を与えられると、出力配列に初期化されていない値があります。 –

答えて

12
for (int ax = 0; ax < a_size; ax += 2) 

a_sizeINT_MAXに近い場合にだけ注意してください。

+1

'a_size <= INT_MAX - 2'を確認してください。しかし、もしあなたが 'INT_MAX'の近くでサイズの配列を持っているなら、あなたは何か間違っています。 –

+0

@Cole "Cole9" Johnson - はい、2つの要素をスキップします。しかし、問題はより一般的には「N」要素に関するものでした。 –

2

ループは十分なはずです。 Pete氏が指摘したように、モジュロテストは避けることができます。

for (int ax = 0; ax < a_size; ax += 2) 
    ... 

C++はvalarrayヘッダを介してスライスするためのサポートを提供しています(例えば、std::slice_arrayを見てみましょう)。

私はそれがあなたが探しているものかどうかわかりません。重量のある数値計算を目的としています。あなたが不明な場合、私は単純なループが正しい答えだと思います。

+0

高画質、スライスは私にとって非常に便利です – cpp

0

例:

#include<iostream> 
using namespace std; 

int main() { 
    const int a_size = 6; 
    const int b_size = a_size/2; 

    int a[a_size] = {1, 3, 6, 3, 2, 7}; 
    int b[b_size]; 

    for (int ax = 0, bx = 0; ax < a_size; ax += 2) { 
     b[bx++] = a[ax]; 
    } 
} 
1

あなたは簡単にevery_n述語を作成し、あなたが得ることができるように、一般的なようだなどcopy_if、のために必要に応じてそれをフィルタリングするために使用することができます。

おおよそ(注:まだのような未検査)「毎にn個の要素」述語の例:

/** 
@brief Un predicado que retorna @c true cada @a n invocaciones. 
**/ 
template <typename Integer> 
struct every_n { 
    static_assert (std::numeric_limits<Integer>::is_integer, "Must behave like an integer"); 
    public: 
    explicit every_n (Integer const& e) 
    : n(e), x(1) {} 

    every_n (every_n const& E) 
    : n(E.n), x(E.x) {} 

    bool operator() (...) { 
     if (x<n) { ++x; return false; } 
     else { x=Integer(1); return true; } 
    } 

    private: 
    Integer x; 
    const Integer n; 
}; 

// "make_" idiom 
template <typename Integer> 
every_n<Integer> every (Integer const& c) { return every_n<Integer>(c); } 


// sample usage 
# include required headers, etc 
using namespace std; 
const int a_size = 6, b_size = 3; 
int a[a_size] = {1, 3, 6, 3, 2, 7}; 
int b[b_size]; 
copy_if (begin(a), end(a), begin(b), every(3)); 

すべてのコードが必要でevery()が整数のように動作タイプと呼ばれることがあります。

(このコードでは、C++ 11であるstatic_assert、begin()、end()、copy_if()を使用していますが、適切な関数をバックポートすればC++ 03でも同様に機能します)

+0

私はこれを理解していません(それは私にとっては複雑です)。copy_ifの単項述語は、この要素の位置ではなく、配列要素を引数としてとります。述語に要素の位置を渡すことは可能ですか? – cpp

+1

可能ですが、持っているわけではありません。 'every()'呼び出しは、n回呼び出されるたびに「tick」する述語を作成します。 'copy_if'は各ステップでテストする要素を渡しますが、' bool operator()(...) 'はそれを破棄します。なぜなら、要素は内部的に追跡するステップの数だけであるからです。 'every_n'が" tick "すると、要素は値にかかわらず呼び出し元アルゴリズムの正の一致としてマークされます。 –

+0

大きな説明のためのThanx – cpp

2

効率的であれば、メモリフットプリントを小さくする方が高速であれば、配列アクセスの代わりにポインタを使用することにします。たとえば、あなたが望むものは、ポインタを使って次のように実装できます。

int main() { 
    const int a_size = 6, b_size = 3; 
    int a[a_size] = {1, 3, 6, 3, 2, 7}; 
    int b[b_size]; 
    int* a_ptr = a; 
    int* a_end_ptr = a_ptr + a_size; 
    int* b_ptr = b; 
    while(a_ptr < a_end_ptr) { 
     *b_ptr = *a_ptr; 
     b_ptr++; 
     a_ptr += 2; 
    } 
} 

この例は、配列アクセスの例よりも少し速いはずです。この例は、配列アクセスの例よりも少し速いはずです。しかし、これらの最適化を行う際には、プログラムの大規模なスキーム(重要でない時間を費やさないかどうか)を検討することが常に意識されるべきです。

+1

このコードは、起こるのを待っているバグです。 'a_size'が_oddの数値ならば、配列の終わりを過ぎて' a_ptr'をインクリメントし、クラッシュするまで続けます。 – Blastfurnace

+0

複雑なポインタコードを書くことは一切ありません。最適化を有効にすると、コンパイラは自動的にそれらのポインタを自動的に挿入します。 (int ax = 0; ax

+0

@Blastfurnace、あなたは正しいと私はその問題を解決しました。 – Akash

1

これは早くそれを取得通りである:使用

void copy_n(int & a[], int & b[], int a_sz, int n) { 
    int bx = 0; 
    for (int i=0; i<a_sz; i+=n) { 
    b[bx++]=a[i]; 
    } 
} 
関連する問題