std::vector 2次元配列の列方向初期長

このQ&Aのポイント
  • std::vectorを使用して2次元配列を宣言する際、列方向の初期長を指定する方法はありますか?
  • 通常、列方向の初期長を指定しない場合、a.resize(N)を実行した後にfor (auto &n : a) n.reserve(10);を行いますが、これは時間がかかります。
  • aの列方向の初期長を10と指定する方法で、a.resize(N)を実行した際に自動的にfor (auto &n : a) n.reserve(10);を行う方法を教えてください。
回答を見る
  • ベストアンサー

std::vector 2次元配列の列方向初期長

std::vectorを使った2次元配列を std::vector< std::vector<int> > a; の様な方法で宣言できるところまでは分かったのですが、aの列の初期長を予め指定する方法はないでしょうか? 例えば、必要な列方向初期長が10であるとします。 行方向のデータ数Nが実行中に与えられる場合 a.resize(N); for (auto &n : a) n.reserve(10); で目的は達せられるのですが、Nが数千万のオーダーだど非常に時間がかかります。 仮にNが2000万個とすると、私のPCでa.resize(N)は約90ミリ秒で完了しますが、for (auto &n : a) n.reserve(10);には約10秒を必要とします。 そこで、aの列の初期長は10(reserve(10)の意味)であると言う何らかの指定を行って a.resize(N)を行った際に、自動的にfor (auto &n : a) n.reserve(10);を行ったのと同じ状態になっているという aの宣言方法があれば教えてください。 aの列方向の初期長(本例の場合は10)は与えますが、.push_back() により10個以上のデータを列方向に詰める場合も想定する為、完全固定長の std::array<> は使用できません。

  • mpach
  • お礼率100% (3/3)

質問者が選んだベストアンサー

  • ベストアンサー
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

あ, 長さはそうなっちゃいますね. すみません. ただ, 速度についてはどうにもならないような気がします. 動的メモリ確保は結構重たい処理なので, 大量に実行するとどうしても時間がかかっちゃいます. #1 で 「速いか」といわれるとわからない と書いたのも, 「ど~書いても時間は同じくらいかかるんじゃないかなぁ」と思ったことが根底にあります. 「高速化したい」ということであれば, 作った「2次元配列」をどう使うかによるんだけど.... その「約10秒」が全体の実行時間に影響するようだと, データ構造から考え直さないといけないかもしれん.

mpach
質問者

お礼

>動的メモリ確保は結構重たい処理 相当に重い処理だったのですね。  future & async() や Concurrency::parallel_for_each() などでマルチスレッド化してもOSの動的メモリ確保受付窓口が1つしか無いためか、オーバーヘッドが発生して倍の20秒程度かかってしまいました。 vectorを使った、この方法での速度アップはあきらめることにします。 おつき合いありがとうございました。

その他の回答 (2)

回答No.2

template<typename T, size_t R> struct reserve_vector : public vector<T> { reserve_vector() { reserve(R); } }; vector<reserve_vector<int,10>> a; ...なんてのはダメですか?

mpach
質問者

お礼

教えて頂いた方法を試してみましたが 今度は a.resize(N)で10秒消費してしまい 速度的には変わりませんでした。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

resize で初期値を与えることはできるけど, 「速いか」といわれるとわからない.

mpach
質問者

お礼

a.resize(N); for (auto &n : a) n.resize(10); と指定しても、for (auto &n : a) n.resize(10); に10秒消費してしまいます。 またresize()で実体を割り当てしまうとpush_back()した際 11個目から追加動作してしまうので、内部にカウンターを定義して i=0, n[i++]=b; の様に管理しなければならなくなりますね。

関連するQ&A

  • std::vectorのマージ

    std::vectorで値が重複しないマージを行う一般的な方法はありますか? A = { 1, 2, 3, 4, 5 } B = { 4, 5, 6, 7, 8 } A + B = { 1, 2, 3, 4, 5, 6, 7, 8 } こういう感じにしたいのです。 今はforで回しているのですが、もっといい方法があるのではないかと思って。 よろしくお願いします。

  • 2次元のvectorにオブジェクトのポインタを格納

    VC++6.0です。 まず、ポインタでなく、int型の格納なら分かったんです。 ・・・ #include <vector> using namespace std; main(){ vector <vector<int > > a(10); ←←← for(int i=0;i<10;i++){ a[i].resize(10); } ・・・ for(int j=0;j<10;j++){ for(int i=0;i<10;i++){ a[i][j]=i+j; } } ・・・ } という感じで利用できることが。 しかし、やりたいのは、整数型でなく、 オブジェクトのポインタを格納したいんですが、 矢印部分を例えば、vector <vector<class *> > a(10); などどしてもエラーになってしまいます。 どのように実装したらよいのでしょうか?

  • C言語の配列をC++のvectorに高速に変換したい

    質問は表題のとおりです。 単純な方法では以下の通りになると思いますが、 (C言語文字列から string への変換のように) 一括変換の仕組みは vector にないのでしょうか? static const int n=5; int a[n]={0,1,2,3,4}; std::vector<int> v(n); std::vector<int>::iterator vit=v.begin(); for(int i=0; i<n; i++){ *vit++ = a[i]; } 上記の例では n=5 ですが、nがとても大きな場合に適用したいと考えています。 ちなみに、gcc 3.4.3 を使っています。

  • C++ vectorに配列をプッシュしたい

    C++のstd::vectorが格納する要素として配列を指定することはできますか vectorを使って2次元配列を表現したいときは,たとえば std::vecor<std::vector<int>> v; とすれば2次元配列が表現できますよね. 2次元配列の列方向の要素数が2で固定されていて,行方向の要素数が不確定のデータを扱いたいので,2次元配列を格納するvectorで扱えればなと思いました. (2個で1組のデータがたくさんあるということなので,vectorの2次元配列ではありません) std::vector<int[2]> v; int a[2]; a[1] = 1; a[0] = 2; v.push_back(a); という書き方ではコンパイルできなかったのですが,vectorに配列要素を格納させることはできないのでしょうか. あるいは,もし可能ならどのように書けばよいのでしょうか. 結局は1組のデータセットを構造体化してそれをvectorにプッシュするやり方に落ち着いたのですが,疑問に思ったままモヤモヤしているので質問させて頂きます. 「vector 配列」などのキーワードで検索してみましたが,vectorの動的配列としての紹介記事が多くヒットしてしまい,自分ではうまく情報を発見することはできませんでした. よろしくお願いします.

  • STL vectorの初期化

    STL vectorの初期化についてなんですが 以下のようなクラスのprivateなメンバ変数としてvectorを定義し それをメソッド内のループ処理にて初期化しながら使用したいのですが 初期化の仕方が分かりません。コンストラクタを呼べば初期化されるようですが 以下のようにヘッダとソース内で2度同じような宣言をしてしまっても問題ないのでしょうか? //=== test.h === class test { private : vector<int> array; public : int fnc(); }; //=== test.c === int fnc() { for (int i = 0; i < 10; i++) { //★ここで初期化したい vector<int> array;  ←これで問題ないか? for (int j = 0; j < 10; j++) { array.push_back( md ); } } } C#などでは宣言とインスタンス生成を別に分けられたのですがC++も同様の事が出来るのでしょうか? 一応「array = new vector<int>;」といれて見たのですがエラーが出ました。

  • 行ベクトルと列ベクトル

    行ベクトルと列ベクトル 次の積を計算せよ。 ( 1 2) (3) 5 6 4 指針 行列の積ABの計算は、Aの行ベクトルとBの列ベクトルの積が基本となる。例えば ( 1 2) (3) 4 ( 5 6) (3)を計算し、これらの成分としておいたものが積になる。このとき、次のことがポイント。 4 (第●行目の行ベクトル)と(第■行目の列ベクトル)積を(●、■)とおく。 教えてほしいところ行ベクトルとは1×n行列のことをいい、m×1の行列を列ベクトルというんですよね。 よって、第●行目の行ベクトル)と(第■行目の列ベクトル)積を(●、■)とおく。 って、行列の中に行列が入ってみるたいで、おかしくないですか?? 実際、( 1 2) の行列の5 6の部分は行ベクトルであるとはいいませんよね?? 5 6

  • C++ 構造体型のvector配列でエラーがでます

    構造体のvector配列を関数に渡しています。 以下のソースコードで、3点エラーがでます どのように変更すればよいですか? #include<stdio.h> #include<stdlib.h> #include<iostream> #include <vector> using namespace std; std::vector<int> v; typedef struct fukusosu{ int a; int b; }FUKUSOSU; int sort(vector<FUKUSOSU> v[], int N){ FUKUSOSU tmp; int j; for(int i = 0 ; i < N - 1 ; i++){ j = i ; for(int k = i + 1 ; k < N ; k++){ if(v[j].a > v[k].a){j = k;}//ここのaに対して、エラーがでます } tmp = v[j];//ここのイコールに対して、エラーがでます v[j] = v[i]; v[i] = tmp;//ここのイコールに対してエラーがでます } } int main(void){ int N; // 要素数 cin >> N; vector<FUKUSOSU> v(N); for(int i = 0; i < N; ++i){ cin >> v[i].a; cin >> v[i].b; } }

  • 散乱後の光子の方向ベクトル

    ある光子が一定の方向ベクトルnを持っているとして、 nx=X0 ny=Y0 nz=Z0 である時、この光子が一定の角度θ、φで散乱された時、散乱後の方向ベクトルaはどのように書くことができますか?

  • 多次元配列について質問

    以下は、Javaの参考書に掲載されていたある問題です。 その問題文と解答ソースコードを記載しますので、以下の疑問点に答えていただければ幸いです。 また、僭越ながらお願いがあるのですが、このソースコードを一度実行してから私の質問を見たほうが、より私の疑問点が回答者様にわかると思うので、実行してくだされば幸いです。 問題文:次のA~Cの手順に従ってプログラムを作成しなさい。 A:5×4の2次元配列のint型配列pを作成します。つまり、pは5個の要素を持ち、各要素が「4つの要素を持つintの配列」であるような配列です。 B:次にpの全要素にMath.random()で得られる乱数値を代入しなさい。乱数値は0から10の範囲になるように10倍し、さらにintにキャストして配列の要素に代入しなさい。 C:pの全ての要素を例示のように表示しなさい。(※ここでいう「例示」とは、私がこの質問板にupした画像のこと)ただし、pの各要素を5×4の表と見た時、各列の(縦方向の並び)の合計を、その5×4の表と見た時、各列(縦方向の並び)の合計も例示のように表示しなさい。 ---解答ソースコード(クラス宣言は除きます)--- public static void main(String[]arg){ //A int[][]p=new int[5][4]; //B for(int i=0;i<p.length;i++){ for(int j=0;j<p[i].length;j++){ p[i][j]=(int)(Math.random()*10); } } for(int[]n:p){ for(int m:n){ System.out.print(m+"\t"); } System.out.println();//改行 } //C int[]sum=new int[p[0].length]; for(int[]n:p){ for(int j=0;j<n.length;j++){ sum[j]+=n[j]; } } System.out.println(); for(int m:sum){ System.out.print(m+"\t"); } } 疑問点:Cの手順の解答について疑問なのですが、以下のソースコードで何故各列の合計を求められるかわかりません。何故ですか?凄く頭が引きちぎれるほど考えたのですがわかりませんでした。 int[]sum=new int[p[0].length]; for(int[]n:p){ for(int j=0;j<n.length;j++){ sum[j]+=n[j]; } } だって、例えば拡張for文でpの0番目の要素を取り出して、さらにfor文でその0番目の要素の0番目、1番目、2番目、3番目をsumに累計するといったように、縦方向でなく「横方向」に合計するソースコードに僕は思えるんですよ。何故縦方向に合計できるんですか?たしかに実行すると縦方向に合計されてるので、縦方向に合計するものには間違いなのだけれど、、

    • ベストアンサー
    • Java
  • ベクトル列の収束

    ある定理の証明をしていた時に、 以下のことを使うとわかると途中の補足で出ていた事なのですが、 その補足でつまってしまいました。 どのようにして解けば良いのでしょうか。 宜しくお願い致します。 E:バナッハ空間 {x_n}:Eのベクトル列 {a_n}:実数列 ∥x_n∥≦a_n かつ Σa_nが収束(n=1~∞) ならば Σx_nも収束(n=1~∞)

専門家に質問してみよう