C言語の課題:ハッシュ(オープンアドレス法)の実装方法とプログラム作成の手順

このQ&Aのポイント
  • C言語の課題であるハッシュ(オープンアドレス法)の実装方法とプログラム作成の手順を解説します。
  • 問題の内容は、名前と年齢を入力し、名前をキーとしてハッシュ(オープンアドレス法)に登録することです。
  • さらに、名前が入力されるとハッシュ法を使って検索し、あればその人のデータをハッシュから削除するプログラムも作成します。
回答を見る
  • ベストアンサー

ハッシュ(オープンアドレス法) C言語の課題

努力はしてみたのですが、C言語の課題ができません。教えていただけないでしょうか。 問:名前と年齢を入力し、名前をキーとしてハッシュ(オープンアドレス法)に登録する。'-'が入力されると登録を終了し、次に入力された名前をハッシュ法で検索し、あればその人のデータをハッシュから削除する、その後、ハッシュ表の内容を出力するプログラムを作成せよ。ただしハッシュ表の大きさは5とする。 例 koizumi  入力 1     入力 fukuda  入力 2  入力 aso 入力 3     入力 -     入力 koizumi  入力 fukuda(2) 出力 aso(3) 出力 ハッシュ関数は int hash(char *name) { int ret=0; while (*name)ret += *name++; return ret%5; } 再ハッシュ関数は int rehash(int h) { return (h+1)%5; } を使おうと考えています。 内容を理解できないと困るので簡単なプログラムをお願いします。 よろしくお願いします。

  • effe
  • お礼率43% (14/32)

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

  • ベストアンサー
noname#50176
noname#50176
回答No.1

ちょっと難しくなったかもしれませんが 質問者さんなら解かると思います。 ずらし処理を抜いてシンプルにしています。 補足なのですが、氏名をキーにすると氏名そのものを 直接、照合すればいいのでキーの意味を持ちません。 本来はハッシュキー値をキーにして照合させ、候補される 複数の氏前をユーザ選択させる方式の方が妥当かと思いますが 以下リストは、あえて氏名文字列を利用した冗長処理にしています。 <リスト> #include <stdio.h> #include <stdlib.h> #include <string.h> int hash(char *name) { int ret=0; while (*name)ret += *name++; return ret%5; } int rehash(int h) { return (h+1)%5; } void err_disp() { printf("\n別キーが使用済みです。\n"); } int main() { int key[5],age[5],i,k,c=0,err; char name[5][15],temp[15]; for (i=0;i<5;i++) key[i]=-1,age[i]=0,name[i][0]=0; i=0; while (1) { printf("氏名?"); scanf("%s15",temp); if (*temp=='-' && !*(temp+1)) break; k=i=hash(temp),err=0; if (*name[i] && key[i]!=k) {err_disp();break;} while (*name[i] && key[i]==k) { if (k==(i=rehash(i)) || *name[i] && key[i]!=k) err=1; } if (err) {err_disp();break;} strcpy(name[i],temp); key[i]=k; printf("年齢?"); scanf("%3d",&age[i]); if (++c>=5) break; } printf("\n検索氏名?"); scanf("%s15",temp); printf("\n"); for (k=i=hash(temp);k==key[i];i=++i%5) { if (!strcmp(temp,name[i])) *name[i]=0; } for (i=0;i<5;i++) { if (*name[i]) printf("%s %d歳\n",name[i],age[i]); } return 0; }

effe
質問者

お礼

少々自分には厳しいですが、頑張って読んでみたいとおもいます。 ありがとうございました。

関連するQ&A

  • ハッシュ法(オープンアドレス)線形探査法と再ハッシュ法

    1から10000までの数字がランダム(重複なし)にはいっているファイルから任意に10個の数字を選びハッシュ法(オープンアドレス)の線形探査法と再ハッシュ法を使って探すプログラムを作りたいのですがまったく手がでません。さらに探査回数と実行時間も出力しなければなりませんが、こちらはなんとかできます。ハッシュ法というのが初めてで困っています。どなたか教えてください。お願いします。 ちなみにファイル名は次のようにmain関数中に絶対パスで記述します。 char infile[20] = "/integer.dat"; int in[10]={20,168739,701,52774,44476,185,994737,124623,645300,999901};

  • C言語の課題をやっております。

    C言語の課題をやっております。 ずいぶん考えたのですが、行き詰まってしまいました。 課題は、 1.構造体を作り、名簿風の決められたデータを入れる(初期化?) 2.名前の順に並べ替える 3.画面に表示する という3段階です。 これらを1つのmain関数内で作ることはできたのですが、 それぞれinput sort output関数で作り、main関数で呼び出して完成させる必要があります。 sort outputはかろうじてできたのですが、inputが動かせません。 今の考えとしては、mainでinputを呼び出し、 input関数内で構造体を初期化して、戻り値で構造体のアドレス?をmainに返して、 そのアドレスをそれぞれsort outputに渡し、処理してもらいたいと考えています。 エラーのでる箇所は、main関数の構造体アドレスのやりとりと、 input関数の戻り値のあたりで 問題のあるポインタ、とか移植性のないポインタ、などと 出てしまいます。 書いたプログラムをmain,input,sortまで載せます。 整理できておらずわかりにくいプログラムですが、考え方、間違っているところ、修正点など ご意見を頂きたく思っています。 よろしくお願いします。 # include <stdio.h> struct day { int yy; int mm; int dd; }; typedef struct hito { int NO; char NAME[10]; struct day ENTRANCE; struct day BIRTH; }HITO; void main(void){ int input(void); int output(struct hito *pt); int sort(struct hito *pt); int i,j; int x; struct hito *pt; pt=input(); sort(pt); output(pt); return; } int input(void){ int i,x; struct hito *ptt; HITO list[9]= { {1456, "okayama", 2004,4,1, 1980,2,4}, {2452, "wada", 2005,4,1, 1984,10,2}, {2552, "ikeyama", 2005,4,1, 1987,5,10}, {3456, "meguro", 2006,4,1, 1982,5,2}, {4242, "sagami", 2007,10,1, 1972,3,3}, {5123, "ohsawa", 2008,10,1, 1965,2,2}, {5222, "akagi", 2009,1,4, 1988,3,4}, {6212, "hasebe", 2009,4,1, 1990,8,3}, }; return list; } int sort(struct hito *pt){ int i,j,x; for (i=0; i<8; i++){ for(j=i+1; j<9; j++){ if((pt+i)->NAME[0] > (pt+j)->NAME[0]){ *(pt+9)=*(pt+i); *(pt+i)=*(pt+j); *(pt+j)=*(pt+9); } } } return 0; }

  • C言語の課題について

    C言語の会員名簿処理問題の課題をしています。 次の条件でC言語で会員番号を入力するとその会員番号を持つ会員名を表示する プログラミングを組んでいますが、コンパイルに失敗してしまいます。 何度も見直して修正を施してみたのですが、うまくいきません。 是非お力添えをお願いします。 <条件> (1)会員番号と会員名は構造型でグローバル変数として宣言する。 (2)データ件数は10件とする。 (3)サブ関数で線形探索するプログラムを組み(my_search関数とする)、メイン関数で呼び出す。 (4)my_search関数の型はchar*とする。 (5)探索に成功したらmy_search関数の戻り値は該当会員の氏名とする。 (6)探索に失敗したらmy_search関数の戻り値はNULLとする。 (7)main関数では,関数my_searchの戻り値がNULLなら該当データがないことを 伝えるメッセージを出力して終了させる. そうでなければ,該当の氏名を出力して終了させる. 下に組んだプログラムとコンパイル結果を貼り付けます。 /* z:\情報システム論_2013>cl js010703_a106906.c Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 15.00.21022.08 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. js010703_a106906.c js010703_a106906.c(48) : warning C4047: '==' : 間接参照のレベルが 'int' と 'void *' で異なっています。 js010703_a106906.c(58) : error C2040: 'my_search' : 'char *(int)' は 'int ()' と 間接操作のレベルが異なります。 z:\情報システム論_2013> */ #include <stdio.h> #define N 10 #define MAX 20 struct Mystruct{ int number; char name[MAX]; }; struct Mystruct meibo[N] = { {10, "asaoka"}, {20, "ito"}, {23, "kawano"}, {25, "shimizu"}, {31, "setoguchi"}, {34, "tomiyama"}, {37, "murakami"}, {38, "yasuda"}, {46, "yoshino"}, {49, "yoshikawa"} }; int main() { int x; char p; printf("会員番号を入力してください。\n"); printf("会員番号:"); scanf("%d", &x); printf("入力された会員番号の会員は"); p = my_search(x); if(p==NULL){ printf("存在しません。"); }else{ printf("%s", p); } return 0; } char * my_search(int a) { int j = 0; while(j<N){ if(a==meibo[j].number){ return meibo[j].name; break; }else{ ++j; } return NULL; } } どうしても、この2つのエラーが消えません。 修正点を詳しく教えていただけないでしょうか。 よろしくお願いします。

  • c言語 ハッシュ表

    下のハッシュ表のプログラムについて質問です.関数enterを二回呼び出して,valueの値を変更して表示させても値が更新されません.値が更新せれるにはどうすればよいのでしょうか? #include <stdio.h> #include <stdlib.h> #include <string.h> #define HASH_SIZE 997 /* ハッシュ表の内部配列のサイズ */ #define HASH_RADIX 97 /* ハッシュ関数用の基数 */ /* ハッシュ表内の連結リストに含まれるノードの構造体 */ struct hash_node { /* ハッシュ表内の連結リストのノード */ char *key; /* キー */ int value; /* キーに対応する値 */ int id; /* キーに付与された通し番号 */ struct hash_node *next; /* 次のノードへのポインタ */ }; typedef struct hash_node HashNode; typedef HashNode *HashNodePtr; /* ハッシュ表の構造体 */ struct hashtable { HashNodePtr *heads; /* 内部配列 */ int serial_id; /* 通し番号管理用の変数 */ int size; /* 内部配列のサイズ */ }; typedef struct hashtable HashTable; typedef HashTable *HashTablePtr; /* 文字列 s のハッシュ値を計算する */ unsigned int hash(char *s) { unsigned int v; v = 0; while (*s != '\0') { v = v * HASH_RADIX + *s; s++; } return v; } /* ハッシュ表を一つ生成し,そのポインタを返す */ HashTablePtr create_hashtable() { HashTablePtr t = NULL; int i; t = malloc(sizeof(HashTable)); t->serial_id = 0; t->size = HASH_SIZE; t->heads = malloc(sizeof(HashNodePtr) * t->size); /* 各連結リストの先頭要素へのポインタは必ず NULL に初期化する */ for (i = 0; i < t->size; i++) { t->heads[i] = NULL; } return t; } /* 指定したポインタ変数に NULL を代入して終わるためのマクロ */ #define delete_hashtable(t) \ (delete_hashtable0(t),t=NULL) /* 実質的な削除作業を行う関数(free 後の NULL 代入は省略)*/ void delete_hashtable0(HashTablePtr t) { HashNodePtr n = NULL, m = NULL; int i; /* 各連結リストの領域を解放 */ for (i = 0; i < t->size; i++) { n = t->heads[i]; while (n != NULL) { m = n; n = n->next; free(m); } } /* 最後に連結リストの先頭ポインタの領域を解放 */ free(t->heads); free(t); } /* ハッシュ表 t に登録されているキーと値のペアの数を返す */ int get_cardinality(HashTablePtr t) { return t->serial_id; } /* ハッシュ表 t にてキー key に対応する値を調べる */ int lookup(HashTablePtr t, char *key) { HashNodePtr n = NULL; int index; /* ハッシュ表の内部配列の添え字を計算 */ index = hash(key) % t->size; /* index 番目の連結リストを先頭から順に走査 */ n = t->heads[index]; while (n != NULL) { /* 引数で指定された key とハッシュ表内のキーが一致したら 直ちに対応する値を返す */ if (strcmp(key, n->key) == 0) return n->value; /* 走査を次に進める */ n = n->next; } /* ここではキーに対応する値は非負であると仮定し, 見つからなかったら -1 を返す */ return -1; } /* キー key と値 value のペアをハッシュ表 t に登録し,その通し番号を返す */ int enter(HashTablePtr t, char *key, int value) { HashNodePtr n = NULL, m = NULL; int index; index = hash(key) % t->size; /* 内部配列の添え字を計算 */ /* キーが既に存在しているかどうかチェック(lookup() と同じ処理)*/ n = t->heads[index]; while (n != NULL) { if (strcmp(key, n->key) == 0) return n->id; /* 通し番号を返す */ n = n->next; } /* 新しいノードを生成 */ m = malloc(sizeof(HashNode)); m->key = _strdup(key); m->id = t->serial_id; m->value = value; /* 連結リストの add_first() と同様にして連結リストに追加 */ m->next = t->heads[index]; t->heads[index] = m; t->serial_id++; /* 次の通し番号に更新 */ return m->id; /* 登録したキーと値のペアに付与された通し番号を返す */ } /* * ハッシュ表 t に登録されるキーの配列を返す *(この配列のサイズは get_cardinality() で取得可能) */ char **get_keys(HashTablePtr t) { char **keys = NULL; HashNodePtr n = NULL; int i; keys = malloc(sizeof(char *) * t->serial_id); /* 各連結リストを走査し,配列に詰め込む */ for (i = 0; i < t->size; i++) { n = t->heads[i]; while (n != NULL) { keys[n->id] = n->key; /* 通し番号を配列添え字に */ n = n->next; } } return keys; /* 後で free() する必要あり */ } void print_hashtable(HashTablePtr t) { printf("Taro => %d\n", lookup(t, "Taro")); } /* ハッシュ表の使用例 */ int main(void) { HashTablePtr t = NULL; t = create_hashtable(); enter(t, "Taro", 25); print_hashtable(t); enter(t, "Taro", 35); print_hashtable(t); delete_hashtable(t); }

  • C言語

    3人分の、名前、年齢、性別、を入力して表示するプログラムを作りなさい。というプログラムなんですが、なぜかこのままだとコンパイルはとおるんですが文字入力を3回とfor文で定めているはずなのに、4回になってしまいます。なぜなんでしょうか・・・?prints関数内のfor文はちゃんと動作していて3つ出力されているんですが。コンパイルエラーは無しです。分かるかた教えて頂けないでしょうか? #include <stdio.h> struct tag{ char name[20]; int age; char sex[20]; }; void put (struct tag *ai); void prints(struct tag *sei); int main(void) { struct tag kansuu[3]; put(kansuu); prints(kansuu); return 0; } void put (struct tag *ai) { int i; for(i=0;i <3;i++){ scanf("%s %d %s\n",(ai+i)->name,& (ai+i)->age,(ai+i)->sex); } return;} void prints(struct tag *sei) { int i; for(i=0;i <3;i++) printf("%s %d %s\n",(sei+i)->name,(sei+i)->age,(sei+i)->sex); return;}

  • C言語の課題で

    C言語の課題で 「成績集計プログラム 入力件数nをキーボードより入力し、n人分のテストデータを入力する。その際、合計点、最高点、最低点を求め、最後に平均点を計算しそれぞれを出力するプログラムを作成せよ。ただし、平均点は実数型とし小数点第2位まで出力する。平均点以外の変数は整数型とする。」というのが出ました。 #include <stdio.h> int main(void) { int n,a,b,c; int res,i; printf("入力件数を入力して下さい。\n"); scanf("%d",&n); for(i = 1; i <= n; i++) { printf("点数を入力して下さい。\n"); scanf("%d",&a); printf("%d人目=>%d\n",i,a); if(i == res) break; } return 0; } ここまでは、出来たのですが、後が分かりません。どなたか教えていただけませんか?お願いします。

  • ハッシュ法でのデータ管理について教えてください

    ハッシュ法でのデータ管理をするプログラムを作りたいんですが長いことPASCALに触ってなかったせいか全く分かりません。 どなたか教えていただけないでしょうか??問題の概要は以下のようなものです。 表に登録するデータについては、キーは英数字からなる長さ8までの文字列でデータ本体は整数(型名はintegerでよい)です。 ハッシュ表のサイズは11とします。 ハッシュ関数は文字列xの各文字のASCIIコードの総和を11で割った余りとします。 さらにメニュー表示として入力した文字により行う操作を決定します。 どの文字がどのような操作を行うのかは以下のとおりです。 's' の場合: ハッシュ表に登録されている全レコードを,ハッシュ関数値毎に(キーの値とデータの両方を)すべて表示します. 'r' の場合: さらに「キーの値」と「データ」を入力し,すでに同じキーをもつデータがあれば「二重登録」として検出し,そうでなければ,そのレコードをハッシュ表に登録します. 'e' の場合: さらに「キーの値」を入力し,そのキーをもつデータがハッシュ表に登録されているならば, そのデータを表示します.さらに削除するかどうかを入力させて,削除する選択をした場合にはそのレ コードを削除します.そのキーをもつデータがハッシュ表にない場合には「そのキーをもつレコードが ないこと」を出力しますが,ハッシュ表には操作を加えません. 'i' の場合: ハッシュ表に登録されている全レコードを,キーの値が小さい順に表示します.ここで「キー の値の順」とは,文字列の辞書順のことを意味します.Pascal では,文字列a,b に対して,a がb より 辞書的順序が先(小さい) ときには「a<b」で表現できます. 'd' の場合: 「'i' の場合」の逆で,キーの値が大きい順に表示します. 'q' の場合: プログラムを終了します.具体的には,実行文部の最後の「end.」の直前までジャンプし ます. 長くなってすいません。ちょっとしたヒントでもいいので教えていただければ幸いです。

  • C言語の関数の質問です

    C言語の質問です 最近C言語を始めました。以下の問題がわかりません。 int型の数値を入力して結果をdouble型の戻り値を返すことはできないのか。 関数の値のやり取りでも暗黙の型変換や明示的な型変換はできるのか。 #include <stdio.h> double square(int x); int main(void) { int num;   double ret;   scanf("%d",num); ret = square(num);    printf("%ld",ret); return(0); } double square(int x){ return(x*x); }

  • アルゴリズムでわからない問題があります。(C言語)

    問題1:探索アルゴリズムであるハッシュ法について正しいものを選べ。 (1)ハッシュ関数の出力によりデータを格納した配列の先頭から順番に調べる. (2) 入力データを,ハッシュ関数の出力により求めた格納場所に基づいて,あらかじめ木構造に格納しておく. (4) 入力データを格納した配列を繰り返し2つに分割し,それぞれを順番に調べていく. (3) 入力データから格納場所の位置に変換する関数(ハッシュ関数)の出力により,データの探索場所を決定する。 (5) 入力データを,ハッシュ関数の出力により求めた格納場所に基づいて,あらかじめヒープに格納しておく 問題2:探索アルゴリズムであるハッシュ法について正しくないものを選べ。 (1)入力データはハッシュ値で決められる場所に格納される. (2) ハッシュ関数には,異なる入力の値に対し異なる値を出力することが求められる. (3) ハッシュ関数の時間計算量は,入力データのサイズに比例する. (4) データの格納場所が大きい方が効率がよい. (5) 一般に2分探索法より高速に動作する. どなたかアルゴリズムに詳しい方回答お願いします

  • C言語の課題なのですが、助けてください

    C言語のプログラミングの課題で、「以下のプログラムをキーワードを引数として入力できるように変更する(argvを利用する)」という問題なのですが、プログラミングが苦手な私にはさっぱりわからず、大変困っています。設問のプログラミングがわかる方がいらっしゃいましたら、教えていただけると大変助かります。よろしくお願いします。 #include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX_LEN 256 int main(int argc, char *argv[]) { FILE *rfp; FILE *wfp; int i, score; double evalue; char id[MAX_LEN], name[MAX_LEN], fname[MAX_LEN]; char keyword[] = "glu"; for(i = 0; i < 100; i++){ sprintf(fname,"files/%d.txt",i); if((rfp = fopen(fname, "r")) == NULL) { printf("入力ファイルが存在しません。\n"); return (EXIT_FAILURE); } while (fscanf(rfp,"%s\t%s\t%d\t%f", id, name, &score, &evalue) != EOF){ if (strstr(name,keyword) != NULL){ printf("%s\n",id); } } fclose(rfp); } return (EXIT_SUCCESS); }