• 締切済み

データ構造で悩んでます

以下の構造体があります。 struct Test {   string name;   int no;// 1~100   int age;// 1~100 }; stlのvectorに頻繁に動的に追加、削除されるとします。これをnoやageをキーに効率よく検索する方法を教えてください。 私が思いついたのは、 ・multisetを別に用意する。問題点は追加、削除毎にソートされてしまう。 ・no,age分vectorを用意する。速いけど汎用性が無い。 boostや他のライブラリは無しでお願いします。

noname#115727
noname#115727

みんなの回答

  • qwertfk
  • ベストアンサー率67% (55/81)
回答No.4

struct Test {  string name;  int no;  int age; }; typedef list<Test> TestList; typedef vector<Test*> TestPtrAry; struct TestContainer { public:  TestList Buf; private:  map< int , TestPtrAry > No_Test;  map< int , TestPtrAry > Age_Test; public:  void Add( const Test& t )  {   Buf.push_back(t);   No_Test[ t.no ].push_back( &Buf.back() );   Age_Test[ t.age ].push_back( &Buf.back() );  }  const TestPtrAry* GetItemsByAge( int age )  {   if( Age_Test.find(age) == Age_Test.end() ) return NULL;   return &Age_Test[age];  } }; という感じでどうでしょうか。

noname#115727
質問者

お礼

回答ありがとうございます。 検索用にマップを用意するやり方ですね。。。 検証してみます。

  • hitomura
  • ベストアンサー率48% (325/664)
回答No.3

要件を見る限り、検索キーがnoまたはageのようなので、setやmapは使いづらいのではないでしょうか。 とりあえずこんな感じで検索ができました。 #include <string> #include <vector> #include <algorithm> #include <iostream> using namespace std; struct Test {  string name;  int no;  int age; }; // no によるデータ収集 struct SearcherByNo {  int no_;  vector<Test>* result_;  SearcherByNo(int no, vector<Test>* result)  {   no_ = no;   result_ = result;  }  void operator()(Test& tester)  {   if (tester.no == no_){    result_->push_back(tester);   }  } }; // age によるデータ収集 struct SearcherByAge {  int age_;  vector<Test>* result_;  SearcherByAge(int age, vector<Test>* result)  {   age_ = age;   result_ = result;  }  void operator()(Test& tester)  {   if (tester.age == age_){    result_->push_back(tester);   }  } }; int main(int argc, char** argv) {  vector<Test> test_data;  // テスト用データ追加  Test alpha = {"alpha", 20, 10};  Test beta = {"beta", 20, 50};  Test gamma = {"gamma", 80, 50};  test_data.push_back(alpha);  test_data.push_back(beta);  test_data.push_back(gamma);  cout << "*** no によるデータ検索 ***" << endl;  vector<Test> result_sbn;  for_each(test_data.begin(), test_data.end(), SearcherByNo(20, &result_sbn));  for (vector<Test>::iterator i = result_sbn.begin(); i != result_sbn.end(); i++){   cout << i->name << endl;  }  cout << "*** age によるデータ検索 ***" << endl;  vector<Test> result_sba;  for_each(test_data.begin(), test_data.end(), SearcherByAge(10, &result_sba));  for (vector<Test>::iterator i = result_sba.begin(); i != result_sba.end(); i++){   cout << i->name << endl;  }  return 0; } なお、データのコピーを行っているので、検索後にデータの追加・修正があったときに実際のデータとズレが出てくる恐れがあります。

noname#115727
質問者

お礼

回答ありがとうございます。 このやり方ですとスッキリしてて良いですね。 ただ、検索は先頭から検索して行ってるので時間がかかっちゃいますね、、、 色々考えて見たいと思います。

回答No.2

vectorなのは配列っぽいアクセスが多いということなんですかね? 参照方式がわかんないから何ともいえないけれど 個人的には、std::vectorやめてstd::list にしてfind_ifを使うに一票 vectorのままでもfind_ifは使えますけどvectorは要素数の編集が苦手ですよ。(記憶) まぁ、レンジスキャン、ユニークスキャンの方が 追加削除よりもおおいならmultisetだけでよいとおもわれ 要素指定のアクセスが多いのならvectorのまま find_ifでしょうか。。

noname#115727
質問者

お礼

回答ありがとうございます。 アクセスに関しては先頭から末尾を順にアクセスします。 追加は末尾。削除は任意の場所です。 find_ifというものがあるんですか。知りませんでした。 ただ、検索も頻繁に行われるのでsetやmapで要素の追加時にソートしたほうがいいのかなと思って質問しました。でもソートも時間かかるんですよね。。。

  • hitomura
  • ベストアンサー率48% (325/664)
回答No.1

確認したいのですが、この構造体の列に対する検索とは具体的に何をするのでしょうか。自分が思いついたのは、 (1)とにかく一致するものが1つでも見つかればいい (2)一致するデータが全てほしい (3)ある一定範囲内に値が入るデータが全てほしい の3パターンですが、上記の何番なのか、ぜんぜん違うならばどのような検索をやりたいのか具体的な例を挙げて説明願います。

noname#115727
質問者

お礼

回答ありがとうございます。 検索は(2)一致するデータが全てほしいです。

関連するQ&A

  • C言語 「構造体のソートと結果のファイル出力」 緊急です。助けてください。

    授業で課題が出され内容は以下となってます。 1.歴代アメリカ大統領の情報を構造体とする. 2.ソートを昇順で行うこと 3.結果を出力すること〔参考:http://www-it.sci.waseda.ac.jp/CPR1/class08/kekka.log) 以下が自分で作ってみたものですが、多数のエラーが出てしまいどうしたらいいのか分かりません。。。抜本的な変更でもかまいませんので、分かる方助けてください。 -----作成分------ #include <stdio.h> #include <string.h> struct president { int no, age; char name1[20], name2[20]; /* 氏名 */ }; int main(void) { int i; struct president pre1[44] = { {1,57,"George","Washington"}, {2,61,"John","Adams"}, {3,57,"Thomas","Jefferson"}, //リストが長いので省略// {44,47,"Barack","Obama"}, }; struct president *pres; pres = pre1; //ポインタ// sort(pres, 44, sizeof(struct president), president_cmp);//ソート構文 エラーがでます。。。// printf("---------sortted list by age------- \n # age first last \n");} for (i = 0; i < 44; i++){printf("------------------------------------ \n") printf("%d %d %s %s \n, pres[i]->no, pres[i]->name, pres[i]->name1, pres[i]->name2);} for(i = 0; i < 44; i++) { if (i==0){printf("---------list of presidents---------- \n");//RAW DATAの表示を行ない。ここは問題ないみたいです// printf(" age first last \n");}; printf("%d %d %s %s \n", pres->no, pres->age, pres->name1, pres->name2); ++pres; } return 0; } int president_cmp(const void*p1, const void*p2){ //比較関数// struct president *cmp1 = (struct president*)p1; struct president *cmp2 = (struct president*)p2; return strcmp(cmp1->age, cmp2->age); } ここにファイル出力の分をたしたいのですが、どこにどうすればいいのでしょう。 大変申し訳ありませんが、緊急です!!お願いします。

  • c++ 参考書の問題

    参考書の練習問題が解けません。教えてください。 以下問題文です。 5つの名前をvector<string> nameに読み込み、名前が指定された人の年齢をユーザに入力させ、年齢をvector<double> ageに格納せよ。次に、name[i]とage[i]のペアを5つ出力せよ。名前をソートし(sort(name.begin(), name.end()))、name[i]とage[i]のペアを出力せよ。ここで注意しなければならないのは、age vectorの順序をソートされたname vectorと正しく一致させることである。ヒント:ageをソートする前にコピーを作成し、それを使ってageをソートした後の正しい順序でageのコピーを作成する。つぎに同じことを繰り返すが、今後は任意の数の名前を使用できるようにする。 以上です。よろしくお願いいたします。

  • 構造体についてです。

    身体測定表を作っていて最初に作ったデータを変更して表示したいのですがNo1の168cm→162cm No2の74kg→74.5kg  No3の20歳→19歳 No4の田中三郎→小林三郎 (No3と4は構造体ポインタを使ってデータを変更) 全データを表示させてその後No1と3の名前~体重を丸ごと入れ替えて全データを表示させたいのですがエラーがでてしまいます。 分かる人がいましたらどこを直したらいいか教えて下さい。 #include <stdio.h> #include <string.h> struct data{ int no; char name[21]; int age; int height; float weight; }; struct data *sp; void main(){ int i; struct data a[4]={ {1,"鈴木太郎",23,168,60}, {2,"山本次郎",17,180,74}, {3,"山田花子",20,156,53}, {4,"田中三郎",35,172,68}, }; struct data b; for(i=0;i<4;i++){ printf("番号 :%d\n",a[i].no); printf("名前 :%s\n",a[i].name); printf("年齢 :%d歳\n",a[i].age); printf("身長 :%dcm\n",a[i].height); printf("体重 :%4.1fkg\n\n",a[i]. weight); } a[0].height=162; a[1].weight=74.5; *sp[2].age=19; strcpy(*sp[3].name,"小林三郎"); for(i=0;i<=4;i++){ b=a[0]; a[0]=a[2]; a[2]=b; a[0].no=1; a[2].no=3; } for(i=0;i<=4;i++){ printf("番号 :%d\n",a[i].no); printf("名前 :%s\n",a[i].name); printf("年齢 :%d歳\n",a[i].age); printf("身長 :%dcm\n",a[i].height); printf("体重 :%4.1fkg\n\n",a[i].weight); } }

  • 構造体型二次元ベクタのソート

    構造体型の二次元のベクタをソートしたいのですがやりかたがよくわかりません。 struct coordinate{ int x; int y; }; vector< vector<coordinate> > dbVec; 上記のコードで、 dbVec[val][0].x  のxを昇順にval列をソートしたいです。 よろしくお願いします。

  • リスト構造のソートで悩んでます。。。

    リスト構造のソートで悩んでます。プログラムの内容はファイルからデータをリスト構造の構造体に読み込み、名前順にソートし結果を表示する。というものです。データの追加や削除はできるのですがソートとなると頭が混乱してしまいお手上げ状態になってしまいました。。。。。 読み込み用のデータとプログラムソースを以下に記載するのでどなたか良きアドバイスをお願いしますm(_ _)m ○データ Sakuragi 16 Rukawa 16 Miyagi 17 Akagi 18 Mitsui 18 ○ソース #include <stdio.h> #include <stdlib.h> #include <string.h> #define MENBER 5 typedef struct data{ char name[BUFSIZ]; int age; struct data *next; }LIST; LIST *newLIST(void); LIST *sort(LIST *); int main(int argc,char *argv[]){ FILE *fp; LIST *p; LIST *np; LIST *npb; LIST *head; char namae[BUFSIZ]; int toshi,i; if((fp=fopen(argv[1],"r"))==NULL){ printf("no file\n"); exit(1); } head = newLIST(); npb =head; for(i=0;i<MENBER;i++){ np = newLIST(); fscanf(fp,"%s %d",namae,&toshi); strcpy(np->name,namae); np->age = toshi; npb->next =np; npb = np; } sort(head); for(p=head->next;p != NULL;p=p->next){ printf("%s\t%d\n",p->name,p->age); } for(p=head->next;p != NULL;p=np){ np = p->next; free(p); } fclose(fp); return(0); } LIST *newLIST(){ LIST *p; p = (LIST *)malloc(sizeof(LIST)); p->next = NULL; return(p); } LIST *sort(LIST *head){ }

  • 参照の参照、struct record **start, の使い方は?

    Linked List を作ってるのですが、 addRecord のプロトタイプが以下のようになってます。 int addRecord(struct record **start, char name[], char address[], int age); こうなると start->age = age; start.age = age; *start->age = age; ともコンパイルエラーになるのですが、対処法ありますでしょうか? ちなみに、これはポインタのアドレスを示すものですよね? これを参照の参照と呼ぶのかは確かではありませんが。。。

  • boostスマートポインタ(shared_ptr)を使用した、簡単なフ

    boostスマートポインタ(shared_ptr)を使用した、簡単なファイルの読み込みとループ処理で困っています。 以下に示すような、テキストファイルから情報を読み取って構造体のvectorをつくる処理をshared_ptrを使って行おうとしています。 input.txt-- >Taro /boy /8 years old >Hanako /girl /6 years old /likes candy ----- このファイルの'>'で始まる行は'名前'として、それ以外の '/ 'で始まる行はvectorに入れて、このふたつを個人ごとにまとめて構造体として管理するという形をとりたいと考えています。 つまり構造体の要素は <名前の行> <それ以外の行が入ったベクター> となります。 ファイル読み込みの過程で '>' を認識したらこれらのメモリ領域を確保し、shared_ptrで管理したいと考えています。 出来た構造体をベクターに入れ、ファイル読み込みのあとに出力する、という形でプログラムを以下のように書きました。  #include <string> #include <fstream> #include <iostream> #include <boost/shared_ptr.hpp> using namespace std; //構造体定義  struct my_struct{ std::string name;    std::vector<std::string> vector_of_string;  } ; int main(void){ std::ifstream ifs("input.txt"); //構造体を入れるベクター std::vector<my_struct> vector_of_my_struct; std::string buf; boost::shared_ptr<my_struct> SMARTptr_my_struct(new my_struct); boost::shared_ptr<vector<string>> SMARTptr_vector_of_string(new vector<string>); while(ifs && std::getline(ifs, buf)) { if(buf[0] == '>'){   //構造体の領域を作成 boost::shared_ptr<my_struct> SMARTptr_my_struct(new my_struct); //'/'で始まる行を格納しておくベクター領域の作成 boost::shared_ptr<vector<string>> SMARTptr_vector_of_string(new vector<string>); //構造体に作成されたベクターを入れる (*SMARTptr_my_struct).vector_of_string = *SMARTptr_vector_of_string; //構造体にこの行ををnameとして入れる (*SMARTptr_my_struct).name = buf; //ここで新たに作られた構造体をベクターに入れる vector_of_my_struct.push_back(*SMARTptr_my_struct); } if(buf[0] == '/'){ //この行をstring格納用のベクター(if(buf[0]=='>') ですでに作られている)に入れる (*SMARTptr_vector_of_string).push_back(buf); } この後、構造体のベクターのループから情報を出力しますが字数制限のため省略させていただきます。 input.txtと同じ内容が出力されることを期待したのですが、実際は'>'で始まる名前の行しか出力されません。 どうやらベクターへのpush_backができていないか、そもそもshared_ptrの扱いに根本的な間違いがあるのでは?と思っているのですが、原因がわかりません。環境はVC++2008 express edition, boost 1.38です。 解決方法、原因、アドバイスなど分かりましたらよろしくお願いします。

  • compareToについて

    質問なのですが、 package projecjava4t; import java.util.Arrays; /** * Program の概要の説明です */ public class Program { public static void main(String[] args) { Girl[] a=new Girl[4]; a[0] = new Girl("candy", 100); a[1] = new Girl("Lisa", 1010); a[2] = new Girl("Ann",1020); a[3] = new Girl("Eliza",1030); Arrays.sort(a); int i; for(i=0;i<a.length;i++)   a[i].disp(); } } class Girl implements Comparable { String name; int age; public Girl(String s, int a){ name = s; age = a; } public void disp(){ System.out.println("名前"+name+"年齢"+age); } public int compareTo(Object g){ return -(age - ((Girl)g).age); } } のArrays.sort(a)のcompareTo(Object g)では、どのようなことが起きてるのかわかりません。 あと、-(age - ((Girl)g).age)の意味がよくわからないのですが、 わかる方いらしたらご教授よろしくお願いします。

    • ベストアンサー
    • Java
  • C++でのSORT

    受験番号(int型)と成績(int型)からなる表(可変長)を成績順に並び替えるsortを例えばSTLを使って実現したいと思います。 そこで、構造体をvectorコンテナにのせることを考えました。ですが、push_backの扱い方が間違っているようです。STLのSORTを使う知識以前に、複数要素を持つコンテナが作れません。 受験番号  成績 1     65 2     92 3     95 を 受験番号  成績 3     95 2     92 1     65 に並び替える。 #include <vector> #include <algorithm> struct goukakusya { int number; int score; }; main() { vector<goukakusya> table1; table1.number.push_back(1); table1.core.push_back(65); table1.number.push_back(2); table1.core.push_back(92); table1.number.push_back(3); table1.core.push_back(95); } よろしく、御願いします。

  • ファイル読込時に構造体の文字列ポインタに割当てたいと

    ファイル読込時に構造体の文字列ポインタに割当てたいと思っています。 (new 演算子を使用します。) 文字列の長さが不定です。 どうすれば、文字列の長さを知ることができますか? 以下のようなところまでは作れましたが、 困っています。 void loaddata()のfscanf関数の部分です。 ほかにも関数の void outputdata() void deletedata() がありますが、長いので省略しました。 ********************************************************** #include<stdio.h> #include<string.h> class data { public: struct basic { char *name; int age; struct basic *next; }; private: struct basic *base; struct basic *base_top; int cnt; public: data::data() { cnt=0; } void inputdata(char *name,int age) { if(cnt==0) { base=new basic; base_top=base; base->age=age; int len=strlen(name); base->name=new char[len+1]; strcpy(base->name,name); cnt++; } else { base->next=new basic; base=base->next; base->age=age; int len=strlen(name); base->name=new char[len+1]; strcpy(base->name,name); cnt++; } } void savedata() { base=base_top; FILE *fp; fp=fopen("dat.txt","w"); for(int i=0;i<cnt;i++) { fprintf(fp,"%s\t%d\n",base->name,base->age); base=base->next; } fclose(fp); } void loaddata() { if(cnt!=0){deletedata();} cnt=0; FILE *fp; fp=fopen("dat.txt","r"); while(1) { fscanf(fp,"%s\t%d\n",base->name,base->age); } } };

専門家に質問してみよう