データ構造に構造体を使ったテクニックについての質問(初心者向け)

このQ&Aのポイント
  • 大学の研究で困っている人が質問です。C/C++で数値計算をする際、データ構造に構造体を使うテクニックについて教えてください。
  • 質問者は、枝とノードのリストを持つデータ構造で、その中のノードから新しい枝を作ることができます。新しい枝がない場合は、float型の情報を持ちます。
  • 質問者は、約1億個のノードを持つ予定で、メモリを効率的に使うプログラミング方法を模索しています。現在は、structとunionを使用してデータ構造を表現しています。他の方法があれば教えてください。
回答を見る
  • ベストアンサー

データ構造について構造体を使ったテクニックについての質問(ほぼ初心者)

大学の研究で困っています。 数値計算をC(C++)でやろうとしています。 枝が一本あって、その枝はノードのリストで作られています。その一つ一つのノードからまた新しい枝が作られています。新しい枝がない場合、float(精度を考えるとdoubleにしたい)型の情報を一つ持ちます。 全部で1億個くらいのノードをもつ予定です。(発展系はその二乗三乗と増えていきます。)そこでメモリを効率的に使うプログラミングを考えているのです。 struct leaf{ int init; struct node top; } struct node{ struct node *next; union pnt { float *value; struct leaf *sub; } p; } この文法で動くのかまた他の方法があるかを聞きたくて書き込みしました。よろしくお願いします。(VC++、Win、2GHz)

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

  • ベストアンサー
  • liar_adan
  • ベストアンサー率48% (730/1515)
回答No.1

想定されているデータ型は(ご存じとは思いますが)「木(tree)」と呼ばれるもので、 アルゴリズム関係の本にはだいたい出てきます。 木を使う場合、 「二つのノードへのポインタを持つ」 「ノードに数値を記憶する」のが一般的な方法です。 質問のやり方では、共用体を使って数値とポインタをまとめようとしていますが、 この方法の問題は、 「入っているデータが、数値なのか、ポインタなのかわからない」 ところです。 正しい処理をするためには「これが数値かポインタか」を表す フラグ変数を持たねばならず、そうするとメモリ節約の意味が無くなってしまいます。 普通に木を構成した方がいいかもしれません。 なお、 union pnt { float *value; struct leaf *sub; } のところでは、float *value;ではなくてfloat value;が正しいと思います。 一億個となると…どうかなあ。 一億って言ったら100メガですよね。 1ノードに16バイトかかるとしても1.6GB。 普通のPCの限界の2Gまでメモリを積んで、できるかできないかというところですね。 きついなあ…。 普通、こういうデータ構造では、ひとつひとつのノードごとに malloc()を使ってメモリ確保をするのですが、 それだとmalloc()の管理用領域の分だけ無駄になるかもしれません。 配列を使って、ノード領域をまとめて確保し、 ポインタのかわりにlong型の「ノード番号」で管理する。 ポインタ参照のかわりに「ノード番号」→「実際のポインタへの変換」→「参照」の仕組を作っておく。 …という方法が考えられます。 こうしても、多少の節約になるくらいですが。 なお、「発展形はその二乗三乗」というのは、 現実に計算するのはたぶん不可能だと思います。 メモリ的にも無理だし、 仮に、1クロックで1ノードの処理が終わるとして(実際は10クロックぐらいはかかると思います)、 1億個の処理が完了するまでに0.05秒。 1億個×1億個だと、60日ぶっ通しで計算してできることになります。 ネガティブなこと書きましたが、できるところまでがんばってください。

関連するQ&A

  • 構造体について

    構造体について分からない点があり,教えて頂きたく投稿いたします. 現在,以下のような構造体を作成しています. typedef struct{ int data; struct node *NEXT; }node; また,それを管理するためのリストを以下の構造体にて宣言しました. typedef struct{ node *crnt; node *last; }node_list; また,使用する関数内での宣言は以下の通りです. node_list *non_dscvr_node_list; //未探査ノードを格納する node *crt_dscvr_node; //現在探査中のノードを示す node *start; そして, start->data = 10; start->NEXT = NULL; non_dscvr_node_list->crnt = start; non_dscvr_node_list->last = start; : : crt_dscvr_node = non_dscvr_node_list->crnt; non_dscvr_node_list->crnt = crt_dscvr_node->NEXT; //ここでエラーがでる. エラーの詳細は以下の通りです. warning: assignment from incompatible pointer type 私としては,リストに格納されている先頭ノードをポップして,次のノードを先頭にしたつもりだったのですが,ポインタタイプに互換性がないと怒られてしまいました. 少し調べては見ましたが,nodeの構造体を管理するために別に構造体を定義しているページがあまり見あたりません. 従って,そのようなページがあれば教えて頂きたいと思います. このような方法はあまりよくないのでしょうか. 併せて教えていただけますようお願いいたします.

  • 構造体

    プログラミングの授業で構造体を習ったのですが、課題がよく分からないので質問させていただきます。その課題ですが、 複素数を表す構造体を、 struct complex{float r;(実部)float i;(虚部)}; の形で定義したとして、2つの複素数を入力し、その2つの絶対値の2乗、和、差、積、商を求めるプログラムを作るというものです。 ただし、条件として、 複素数を入力する関数void inputComp(struct complex*c)、複素数をa+biのような形に表示する関数void printComp(struct complex*c)、複素数の絶対値の2乗を関数値として返す関数float asqrComp(struct complex*c)を作成せよというのがあって困っています。 条件がなければprintfを多用してできないこともないでしょうが、条件を満たすプログラムを教えてください。

  • List構造

    Listの尻にノードを追加する関数で困っています。 以下に、ソースの一部を掲載させていただきます。 typedef struct __node{ int data; struct __node *next; }Node; ... /*リストの尻にノードを追加する関数 * 引数: head. リストの先頭ノードのポインタ data. リストの尻に追加したいint型の変数*/ void Insert_Tail(Node *head, int data) { Node *ptr = head; if(ptr == NULL){ /*<ノードが存在しない時には追加されない>*/ /*領域の確保*/      head = (Node*)calloc(1,sizeof(Node)); /*データをセット*/ head->data = data; head->next = NULL; return ; }else{ /*<ノードが存在するときには正常に動作>*/ while(ptr->next != NULL){ ptr = ptr->next; } /*領域の確保*/ ptr->next = (Node*)calloc(1,sizeof(Node));      /*データのセット*/ ptr->next->data = data; ptr->next->next = NULL; } } コメントアウトにも書かせていただきましたが、ノードがすでに存在するときには、正常にノードの最後に追加してくれるのですが、ノードが存在しない時にはリストに追加してくれません。 どうかご指導、ご指摘の程お願いします。

  • データ構造のプログラム

    #include <stdio.h> struct node{ char no; struct node *next; }; struct node head; int main(void) { struct node *new, *cur; char n; while(1){ scanf("%s", &n); if(n=='-'){ break; } new=(struct node*)malloc(sizeof(struct node)); if(new==NULL){ printf("error\n"); return(0); } new->no=n; new->next=head,next; head.next=new; } cur=head.next; while(cur!=NULL); printf("%s",cur); putchar('\n'); cur=cur->next; } free(new); new=free; return(0); } 上のプログラムを書き換えて (1),’-’が入力されたとき文字の入力を終了しそれまでに格納された文字を出力せよ。 ただし、リストに格納する際リストの最後に格納するようにせよ。 例 a(入力) b(入力) c(入力) -(入力) a(出力) b(出力) c(出力) (2),’-’が入力された後,次に入力された文字を持つ要素をリストから削除し、 最後にリスト中の全て文字を出力するようにせよ 例 a(入力) b(入力) c(入力) -(入力) b(入力) c(出力) a(出力) このような問題なのですが、分かりません。 どなたか教えてください。

  • C言語 リスト

    (1) /* list.c */ #include <stdio.h> #include <stdlib.h> struct node { int num; struct node *next; }; main() { struct node *head, *p; int x; head = NULL; while(scanf("%d",&x) != EOF) { p = (struct node *)malloc(sizeof(struct node)); p->num = x; p->next = head; head = p; } // リストの要素のnumの値を先頭から順に表示する p=head; while(p!=NULL) { printf("%d\n" ,p->num); p = p->next; } } (2) struct node *q; q = head; while(q->next != NULL) q = q->next; (1)を(2)を使い新しいノードをリストの最後に追加するようにしたいのですが どう書いたら良いのか教えていただきたいです

  • 線形リストのコードでどーしても理解できない個所があります。

    線形リストのコードでどーしても理解できない個所があります。 (以下、コード部分) typedef struct __node { char name[20]; char tel[16]; struct __node *next; } Node; typedef struct { Node *head; Node *tail; } List; Node *AllocNode(void) { return ((Node *)calloc(1, sizeof(Node))); } /*--- 新たに生成したノードを先頭へ挿入 ---*/ void InsertNode(List *list, const char *name, const char *tel) { Node *ptr = list->head; list->head = AllocNode(); strcpy(list->head->name, name); strcpy(list->haed->tel, tel); list->head->next = ptr; } /*--- pが指すノードの直前にノードを挿入 ---*/ void PutNodeP(List *list, Node *p, const char *name, const char *tel) { if (p == list->head) InsertNode(list, name, tel); else { Node *temp = AllocNode(); if (p == list->tail) list->tail = temp; else *temp = *p; strcpy(p->name, name); strcpy(p->tel, tel); temp->next = p; } } 上の29行目以降の≪pが指すノードの直前にノードを挿入≫についてです。 if文部分については理解できますが、else文部分について、何をやっているのかわからないです。Cの基本的な部分(ポインタも含めて)については充分に理解しているつもりです。 どなたか御教授頂けないでしょうか。 長々と書いてしまいましたがよろしくお願いします。

  • リスト構造をファイルに出力

    struct node{ NODE *next[5]; NODE *pre; }NODE; というような構造体を定義して int main(){ int i; NODE *first; NODE *nd[1000]; first=(NODE*)malloc(sizeof(NODE)); for(i=0;i<1000;i++){ nd[i]=(NODE*)malloc(sizeof(NODE)); } //各NODEを樹構造に定義 first->next[0]=nd[0]; : : } のようなプログラムを組んで NODE[5]→NODE[0]→NODE[1]→NODE[3]       ↓     ←NODE[4]→   のようなリンクリストを構成したのですが そのリストをそのままファイルに出力できませんか? テキストに落として再読み込みすることは考えたのですがメモリの状態をそのままファイルに落とす方法があればそちらのほうが簡便ですので 詳しいいらっしゃいますか? 開発環境はVisualSturio.NETでC++を使っています。

  • C言語 自己参照型 複数木構造

    C言語の自己参照型を使用しプログラムを作ろうとしていますが、 2分探索木についての解説、サンプルをのせているサイトは たくさんあり勉強になったのですが、 木が2以上の複数の場合になった場合、どういったプログラムをくめば いいのかわからず、学習したいと思っています。 参考となる、サイト、サンプルを教えていただけないでしょうか? //2分木の場合 struct node{ int nodeID; struct node *nextA; struct node *nextB; } //複数木の場合? struct node{ int nodeID; struct node **next; } のように複数木の場合は、次の木が複数に対応できるように ポインタのポインタを使用するのかと思いますが、 構造体のメンバでポインタのポインタの使用の仕方が いまいち理解できませんでした。 よろしくお願い致します。

  • C言語 二分木探索

    今、int型の二分木にデータを追加する関数(引数は二分木へのポインタと追加する値、追加されたノードへのポインタを返す)をつくろうとしてます。 以前リストにデータを追加する関数をつくったのでそれを変更してつくろうとしているのですが途中までいってつまってしまいました。 つくりかたを教えてください。 よろしくお願いします! struct BinaryTreeNode{ int data; struct BinaryTreeNode *l_next; struct BinaryTreeNode *r_next; }; struct BinaryTree{ int node_num; struct BinaryTreeNode *root; }; BinaryTreeNode *BinaryTreeNodeAlloc(void) { BinaryTreeNode *node; node = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode)); if (node == NULL) { return (NULL); } node->l_next = NULL; node->r_next = NULL; return (node); } BinaryTreeNode *BinaryTreeDataAdd(BinaryTree *list, int x) { BinaryTreeNode *ptr; BinaryTreeNode *prev; BinaryTreeNode *new_node; ptr = list->root; prev = NULL; while (ptr) {       ←?? if (ptr->data < x) { prev = ptr; ptr = ptr->next; } else if (ptr->data == x) { return (NULL); } else { new_node = BinaryTreeNodeAlloc(); if (new_node == NULL) { exit (0);                ←?? } new_node->data = x; new_node->next = ptr; if (prev != NULL) { prev->next = new_node; } else { list->head = new_node; } list->node_num++; return (new_node); } } new_node = BinaryTreeNodeAlloc(); if (new_node == NULL) { exit (0); } new_node->data = x; new_node->r_next = NULL; new_node->l_next = NULL; if (prev != NULL) { prev->next = new_node; } else { list->head = new_node; } list->node_num++; return (new_node); }

  • 構造体へのポインタ

    すみません、構造体へのポインタの配列の扱いに困っています。 下記ソースの struct list *hashtable[HASHSIZE]; の箇所をmain部に入れた場合の 他の関数内での使用の仕方が全くわかりません。 どのように修正すれば良いのでしょうか。 申し訳ありませんが教えてください。 --------------------- #include <stdio.h> #include <stdlib.h> #include <string.h> #define HASHSIZE 40 #define MAX_KW_LEN 256 #define NUM_KW 23 #define TRUE 1 #define FALSE 0 struct list {  char keyword[MAX_KW_LEN];  struct list *next;   /* 次の list へのポインタ */ }; struct list *hashtable[HASHSIZE]; /* ハッシュテーブル */ /* キーワード ( Cの予約語 ) */ static char kw[NUM_KW][MAX_KW_LEN] = {   "auto", "break", "double",   "enum", "char", "continue", "extern", "float", "for", "int",   "long", "register", "short", "signed", "static",   "struct", "typedef", "union", "unsigned", "return",   "void", "volatile", "while" }; int Hash(char *key); void InitHTable(void); int FindKeyWord(char *key); void ListKeyWord(void); void FreeKeyWord(void); int main(void); int Hash(char *key) {  int hashval = 0;  while (*key != '\0')   hashval += *key++;  return (hashval % HASHSIZE); } void InitHTable(void) {  int i;  struct list *p, *q;  int hashval;  for (i = 0; i < NUM_KW; i++) {   printf("%d\n",i);   if ((FindKeyWord(kw[i])) == FALSE) { /* 登録されていなかったら */             /* メモリを割り付ける */    if ((p = (struct list *)malloc(sizeof(struct list))) == NULL) {     fprintf(stderr, "メモリ不足です。\n");     exit(2);    }    strcpy((*p).keyword, kw[i]);    hashval = Hash(kw[i]);    /* ハッシュ値を求めて */        if (hashtable[hashval] == NULL) { /* 未登録なら */     hashtable[hashval] = p;  /* p の指すアドレスを登録 */     p->next = NULL;    /* リストの末尾に NULL を追加 */    }    else {        /* 既に登録していたら */     q = hashtable[hashval];     while (q->next != NULL) {  /* データがなくなるまで */      q = q->next;    /* リストをたどる */     }     q->next = p;     /* リストの末尾に p の指すアドレスを登録 */     p->next = NULL;    /* その末尾に NULL を追加 */    }   }  } } int FindKeyWord(char *key) {  struct list *p;  for (p = hashtable[Hash(key)]; p != NULL; p = p->next)   if (!strcmp(key, (*p).keyword))  /* 登録済みなら */    return (TRUE);     /* TRUE を返す */   return (FALSE);      /* 未登録ならFALSE を返す */ } void ListKeyWord(void) {  int i;  struct list *p;  for (i = 0; i < HASHSIZE; i++)   for (p = hashtable[i]; p != NULL; p = p->next) /* p が NULL でなければ */               /* ハッシュ値とキーワードを表示 */    printf("予約語:%s ハッシュ値:%d:\n", (*p).keyword, Hash((*p).keyword)); } /* malloc( ) で割り付けたメモリを解放 */ void FreeKeyWord(void) {  int i;  struct list *p, *q;  for (i = 0; i < HASHSIZE; i++)   for (p = hashtable[i]; p != NULL; ) { /* p が NULL でなければ */    q = p->next;      /* p->next を保存 */    free(p);       /* メモリを解放 */    p = q;        /* p->next を p に代入 */   } } int main(void) {  char word[MAX_KW_LEN];  int i;  InitHTable( );  ListKeyWord( );  for (i = 0; i < 4; i++) {   printf("Cの予約語を入力して下さい ");   fgets(word, 128, stdin);   if ((FindKeyWord(word)) == TRUE)    printf("%s は登録済みです。\n", word);   else    printf("%s は未登録です。\n", word);  }  FreeKeyWord( ); }

専門家に質問してみよう