2017-09-10 10 views
0

サイズがwidth * heightのベクトルまたは配列を初期化する関数を作成したいと思いますが、これらの値の周囲にも境界線が作成されます。辺とベクトルの中心を異なる値で塗りつぶす

外側の値も、中央の値とは異なる値に初期化する必要があります。

私が保存しているオブジェクトにはデフォルトのコンストラクタがありません。初期化には依存できません。

これは私がこれまで持っていたコードですが、これを行うためのより簡単で慣れた方法があるように感じられます。

私はC++ 1zまでの任意の機能を使用できます。

#include <iostream> 
#include <vector> 

void fill_values(const unsigned width, const unsigned height, std::vector<int> &values) { 
    for(unsigned y=0; y<height+2; ++y) { 
     for(unsigned x=0; x<width+2; ++x) { 
      if(x==0 || x==width+1 || y==0 || y==height+1) { 
       values.push_back(1); 
      } else { 
       values.push_back(0); 
      } 
     } 
    } 
} 

int main(int argc, char *argv[]) { 
    const unsigned width = 4; 
    const unsigned height = 3; 
    std::vector<int> values; 

    fill_values(width, height, values); 

    for(unsigned y=0; y<height+2; ++y) { 
     for(unsigned x=0; x<width+2; ++x) { 
      std::cout << values[y * (width+2) + x]; 
     } 
     std::cout << '\n'; 
    } 

    return 0; 
} 

出力: -

111111 
100001 
100001 
100001 
111111 
+0

なぜ1つのベクトルを使用して行列を表現していますか? ベクトルのベクトルを使うと簡単になります。 – Federico

+0

@Federicoすべての行は同じサイズで、ベクトルはクラスにラップされます。 'get(unsigned x、unsigned y){戻り値[y *幅+ x]; } 'ベクトルのベクトルを初期化するよりも。私はまた、1次元ベクトルが1つの間接指定だけが起こっているのでアクセスが速いだろうと考えています、それは正しいでしょうか? – Caw

+0

あまり明確ではない実装を正当化するためにコードが速くなるとは思わない。 私はこれを見る: 'values [y * width + x]'; '値'が行列であることを知らなければ、それを実現するのにはしばらく時間がかかりました。 – Federico

答えて

3

正直、あなたのコードは問題ありません。私はそれが何をするかをかなり容易に理解しています。

しかし、別の複雑な実装を提案する精神の中で、私は以下を提案します。マトリックスを埋める別の方法は、1のフル・ローを追加し、次にheightのローを1000...001の行に追加し、次にもう1つのフル・ローの1を追加することです。これをもう少し明確にすることができます。また、

std::vector<int> fill_values(const unsigned width, const unsigned height) { 
    std::vector<int> m; 
    m.reserve((width + 2) * (height + 2)); 

    // add row of 1s 
    m.insert(m.end(), width + 2, 1); 

    // add height middle rows 
    for (int i = 0; i < height; ++i) { 
     m.push_back(1); 
     m.insert(m.end(), width, 0); 
     m.push_back(1); 
    } 

    // and a final row of 1s 
    m.insert(m.end(), width + 2, 1); 

    return m; 
} 
+0

私が探していたものに最も近いように見えますが、精神的に解析するのはもっと難しいです:) – Caw

2

@Fedoricoはコメントで言ったように、ベクトルのベクトルを使用すると、自分の価値観の変数のためのより良い表現です。値を参照としてパラメータとして渡すのではなく、返り値としてcopy elisionに依存する方が良いでしょう。また、高さと幅のセットをデータの行と列の合計数にするだけで、2つを追加する必要がなくなりました。

#include <iostream> 
#include <vector> 

using namespace std; 

// Fills the 2D matrix with 1s on the border and 0s in the middle. 
vector<vector<int>> generate_matrix(int rows, int cols); 
void print_matrix(const vector<vector<int>>& matrix); 

int main() 
{ 
    // Don't sync I/O with C stdio. 
    ios_base::sync_with_stdio(false); 

    // Height and Width of the entire 2D matrix. 
    const int rows = 6; 
    const int cols = 5; 

    vector<vector<int>> matrix = generate_matrix(rows, cols); 
    print_matrix(matrix); 

    return 0; 
} 

vector<vector<int>> generate_matrix(int rows, int cols) 
{ 
    // fill a rows x cols 2D vector with 0s. 
    vector<vector<int>> matrix(rows, vector<int>(cols, 0)); 

    // fill in 1s on top and bottom rows. 
    if (rows > 0) 
    { 
     for (int i = 0; i < cols; ++i) 
     { 
      matrix[0][i] = 1; 
      matrix[rows-1][i] = 1; 
     } 
    } 

    // fill in 1s on the left and right columns. 
    if (cols > 0) 
    { 
     for (int i = 0; i < rows; ++i) 
     { 
      matrix[i][0] = 1; 
      matrix[i][cols-1] = 1; 
     } 
    } 

    return matrix; 
} 

void print_matrix(const vector<vector<int>>& matrix) 
{ 
    // Use a reference for the row iterator to prevent a vector copy. 
    for (auto& row : matrix) 
    { 
     for (auto element : row) 
     { 
      cout << element; 
     } 
     cout << '\n'; 
    } 
} 
+0

ベクトルの 'fill'メソッドを使って最初と最後の行を1に設定することもできます。 しかし、とにかく、私はまだ単一のベクトルの代わりに実際の行列でこの解決法を好む。 – Federico

1

ない大きな違いがありますが、ラムダ関数を(++ 11 Cから始まる)std::generate_n()を使用することができます。

次のコードは、C++ 11以降に依存します。

次は

#include <vector> 
#include <iostream> 
#include <algorithm> 

int main() 
{ 
    constexpr std::size_t width { 4U }; 
    constexpr std::size_t height { 3U }; 
    constexpr std::size_t w2  { width + 2U }; 
    constexpr std::size_t h2  { height + 2U }; 

    std::vector<int> values; 

    values.resize (w2 * h2); 

    std::generate_n(values.begin(), w2 * h2, [=]() -> int 
    { 
     static std::size_t i = -1; 

     ++i; 

     return  (0U == i/w2) || (h2 - 1U == i/w2) 
       || (0U == i % w2) || (w2 - 1U == i % w2); 
    }); 

    for(unsigned y=0; y<height+2; ++y) { 
     for(unsigned x=0; x<width+2; ++x) { 
      std::cout << values[y * (width+2) + x] << ' '; 
     } 
     std::cout << '\n'; 
    } 

    return 0; 
} 

widthと、コンパイル時に知られているheigth場合、あなたはstd::vector初期化することができます(またはstd::array?)を初期化子リストで、少しのテンプレートの仕事を使用して完全な実施例である(与えます私はいくつかの時間と私は例を示します)。

+0

残念ながら、幅と高さはコンパイル時には分かりません。初期化後、行列は最終的に別の幅と高さで再初期化されるまで使用されます。 – Caw

+0

@Caw - 残念なことです。 – max66

関連する問題