• ベストアンサー

ハッシュ法

ハッシュ法で作ったデータ構造をファイルに書き込む、またファイルからの読み込みを行うにはどうしたら良いのでしょうか?? 連結リストの場合、ファイルを開いてから下のようにすれば書き込める事が分かったので、下の操作をハッシュテーブルの大きさ分だけ繰り返せば良いのかな、と思ったのですができません(> <) for(pos = g_syain_head; pos != NULL; pos = pos->next) {  offset = sizeof(Syain) * i; fseek(fp, offset, 0); fwrite(pos, sizeof(Syain), 1, fp); i++; } 誰か分かる方お願いします!!

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

  • ベストアンサー
noname#30727
noname#30727
回答No.3

#1さんの回答に似ていますが、少し補足してみます。 #define TABLE_SIZE 101 Shain *hash_table[TABLE_SIZE]; ハッシュテーブルはこんな感じで、テーブルの未使用な部分にはNULLが入っているとします。 【書き込み】 ※sizeofで取得する値はcharを1とした時の大きさを意味しますが、ここではcharが1バイトである事を前提としています。 最初に項目数を数えます。 FILE *fp; int i, c; for (c = 0, i = 0; i < TABLE_SIZE; i++) { if (hash_table[i]) c++; } 項目数を保存します。 fp = fopen(...); fwrite(&c, sizeof(int), 1, fp); 各項目を保存しファイルを閉じます。 for (i = 0; i < TABLE_SIZE; i++) { if (hash_table[i]) { fwrite(hash_table[i], sizeof(Shain), 1, fp); } } fclose(fp); 【読み込み】 項目はmallocで確保し、ハッシュテーブルに追加する時は関数を呼び出している事を前提にします。 追加する関数は void add(const Shain *p);、テーブルの初期化をvoid clear(); としています。 最初にテーブルを初期化します。 clear(); 項目数を読み込みます。 fp = fopen(...); fread(&c, sizeof(int), 1, fp); 全項目をテーブルに追加します。 for (i = 0; i < c; i++) { Shain *p = (Shain *)malloc(sizeof(Shain)); fread(p, sizeof(Shain), 1, fp); add(p); } fclose(fp); 連結リストでも同じような考え方で保存できます。 #2さんが言われていますが、ポインタをファイルに保存しても、読み込んだ時には有効なポインタとはなりませんので、その事だけには注意して下さい。

candlefire
質問者

お礼

大変詳しく説明していただき、どうもありがとうございました。おかげで、解決いたしました!!

その他の回答 (2)

  • goma_2000
  • ベストアンサー率48% (62/129)
回答No.2

連鎖ハッシュの構造が正しく出来ているとして。 (nextポインタで連結が正しく取れるとして) Syainというのは構造体だと思いますが、構造体の変数にポインタが使われている場合にはそのアドレスしか保存されません。(内容は書き込まれないということです)。 そもそも上手くいかないのは書き込みですか?読み込みですか?書き込みだとしたら、上手くいかないことをどうやって確認されました? 読み込む時は、nextポインタの値をそのまま使用しても上手くいきません。連鎖構造(nextポインタ)は再度構築する必要があります。 下記の方が書き込まれている配列サイズはこの場合はnextポインタを番兵として使用しているので必要ありません。その代わりこの値のチェックが必要になりますが。 その他、考えられることは、ファイルを開く時のモードが、保存時と読み込み時で違う場合は、問題が発生します。

candlefire
質問者

お礼

ご回答ありがとうございました。もう一度、データ構造を構築しなければだめだったのですね。分かりました!!

  • nitscape
  • ベストアンサー率30% (275/909)
回答No.1

現時点でどのようにメモリに格納されていて、ファイルから読み出すときはどのようにメモリに格納しなおせばいいかを考えながら保存するといいと思います。 例えば int nSize = 100; int* pData; pData = new int[nSize]; という形式の配列データでしたら、単純に for(i = 0; i < nSize; i++) fwrite(&pdata[i],sizeof(int)); という感じで保存できますよね(一気にint[nSize]分保存したほうが効率がいいですがここでは説明のためバラしています)(fwriteの使い方が違いますが本質的ではないので無視してください)。 それで保存されたファイルから読み込む処理を考えると、 for(i = 0; i < nSize; i++) fread(&pdata[i],sizeof(int)); とすればいいのですが...nSizeの大きさはどうなっている???という問題に直面します。つまり上の方法での保存方法はダメだったわけです。 fwrite(&nSize,sizeof(int));  <-配列サイズを保存 for(i = 0; i < nSize; i++) fwrite(&pdata[i],sizeof(int)); という風に保存しなければダメだったわけです。 読み込むときは fread(&nSize,sizeof(int)); pData = new int[nSize]; for(i = 0; i < nSize; i++) fread(&pdata[i],sizeof(int)); という風にすればきちんと読み込めるわけです(実際にはエラー処理やそれに関連して全保存データの長さや、場合によってはCRC的な情報を入れることもあります)。 質問文のソースは配列サイズに相当する情報がないですよね(リストだから要らないという考え方もありますが、ない場合は複数のリストを保存できませんから)。そのようなことを考えながらもう一度保存方法を整理してみてはどうでしょうか?

candlefire
質問者

お礼

ご回答ありがとうございます。大変丁寧に説明していただきどうもありがとうございました。とっても参考になりました。どうもありがとうございました。